mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
uc8151: improvements to speed and also add flicker-free mode based on @antirez code example
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
committed by
Daniel Esteban
parent
2a621dc3b1
commit
9063f46313
+39
-12
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"machine"
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/drivers"
|
"tinygo.org/x/drivers"
|
||||||
"tinygo.org/x/drivers/uc8151"
|
"tinygo.org/x/drivers/uc8151"
|
||||||
@@ -15,30 +16,56 @@ func main() {
|
|||||||
led = machine.LED
|
led = machine.LED
|
||||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
machine.SPI0.Configure(machine.SPIConfig{
|
machine.SPI0.Configure(machine.SPIConfig{
|
||||||
Frequency: 12000000,
|
Frequency: 12 * machine.MHz,
|
||||||
SCK: machine.EPD_SCK_PIN,
|
SCK: machine.EPD_SCK_PIN,
|
||||||
SDO: machine.EPD_SDO_PIN,
|
SDO: machine.EPD_SDO_PIN,
|
||||||
})
|
})
|
||||||
|
|
||||||
display = uc8151.New(machine.SPI0, machine.EPD_CS_PIN, machine.EPD_DC_PIN, machine.EPD_RESET_PIN, machine.EPD_BUSY_PIN)
|
display = uc8151.New(machine.SPI0, machine.EPD_CS_PIN, machine.EPD_DC_PIN, machine.EPD_RESET_PIN, machine.EPD_BUSY_PIN)
|
||||||
display.Configure(uc8151.Config{
|
display.Configure(uc8151.Config{
|
||||||
Rotation: drivers.Rotation270,
|
Rotation: drivers.Rotation270,
|
||||||
Speed: uc8151.MEDIUM,
|
Speed: uc8151.TURBO,
|
||||||
Blocking: true,
|
FlickerFree: true,
|
||||||
|
Blocking: false,
|
||||||
})
|
})
|
||||||
black := color.RGBA{1, 1, 1, 255}
|
black := color.RGBA{1, 1, 1, 255}
|
||||||
|
|
||||||
display.ClearBuffer()
|
display.ClearDisplay()
|
||||||
display.Display()
|
|
||||||
for i := int16(0); i < 37; i++ {
|
mod := int16(1)
|
||||||
for j := int16(0); j < 16; j++ {
|
for {
|
||||||
if (i+j)%2 == 0 {
|
// checkerboard
|
||||||
showRect(i*8, j*8, 8, 8, black)
|
for i := int16(0); i < 11; i++ {
|
||||||
|
if mod == 1 {
|
||||||
|
mod = 0
|
||||||
|
} else {
|
||||||
|
mod = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
display.ClearBuffer()
|
||||||
|
for i := int16(0); i < 37; i++ {
|
||||||
|
for j := int16(0); j < 16; j++ {
|
||||||
|
if (i+j)%2 == mod {
|
||||||
|
showRect(i*8, j*8, 8, 8, black)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.Display()
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
// moving line
|
||||||
|
for i := int16(16); i < 21; i++ {
|
||||||
|
display.ClearBuffer()
|
||||||
|
for j := int16(0); j < 16; j++ {
|
||||||
|
if (i+j)%2 == 0 {
|
||||||
|
showRect(i*8, j*8, 8, 8, black)
|
||||||
|
}
|
||||||
|
display.Display()
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display.Display()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func showRect(x int16, y int16, w int16, h int16, c color.RGBA) {
|
func showRect(x int16, y int16, w int16, h int16, c color.RGBA) {
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package uc8151
|
||||||
|
|
||||||
|
// LUTType is the look-up table for the display
|
||||||
|
type LUTType [42]uint8
|
||||||
|
|
||||||
|
type LUTSet struct {
|
||||||
|
VCOM LUTType
|
||||||
|
WW LUTType
|
||||||
|
BW LUTType
|
||||||
|
WB LUTType
|
||||||
|
BB LUTType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lut *LUTType) Clear() {
|
||||||
|
for i := range lut {
|
||||||
|
lut[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lut *LUTType) SetRow(row int, pat uint8, dur [4]uint8, rep uint8) error {
|
||||||
|
index := row * 6
|
||||||
|
lut[index] = pat
|
||||||
|
lut[index+1] = dur[0]
|
||||||
|
lut[index+2] = dur[1]
|
||||||
|
lut[index+3] = dur[2]
|
||||||
|
lut[index+4] = dur[3]
|
||||||
|
lut[index+5] = rep
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+5
-3
@@ -150,7 +150,9 @@ const (
|
|||||||
ROTATION_270 = drivers.Rotation270
|
ROTATION_270 = drivers.Rotation270
|
||||||
|
|
||||||
DEFAULT Speed = 0
|
DEFAULT Speed = 0
|
||||||
MEDIUM Speed = 1
|
SLOW Speed = 1
|
||||||
FAST Speed = 2
|
MEDIUM Speed = 2
|
||||||
TURBO Speed = 3
|
FAST Speed = 3
|
||||||
|
FASTER Speed = 4
|
||||||
|
TURBO Speed = 5
|
||||||
)
|
)
|
||||||
|
|||||||
+125
-315
@@ -1,6 +1,7 @@
|
|||||||
// Package uc8151 implements a driver for e-ink displays controlled by UC8151
|
// Package uc8151 implements a driver for e-ink displays controlled by UC8151
|
||||||
//
|
//
|
||||||
// Inspired by https://github.com/pimoroni/pimoroni-pico/blob/main/drivers/uc8151/uc8151.cpp
|
// Inspired by https://github.com/pimoroni/pimoroni-pico/blob/main/drivers/uc8151/uc8151.cpp
|
||||||
|
// Additional inspiration from https://github.com/antirez/uc8151_micropython
|
||||||
// Datasheet: https://www.buydisplay.com/download/ic/UC8151C.pdf
|
// Datasheet: https://www.buydisplay.com/download/ic/UC8151C.pdf
|
||||||
package uc8151 // import "tinygo.org/x/drivers/uc8151"
|
package uc8151 // import "tinygo.org/x/drivers/uc8151"
|
||||||
|
|
||||||
@@ -19,31 +20,35 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Width int16
|
Width int16
|
||||||
Height int16
|
Height int16
|
||||||
Rotation drivers.Rotation // Rotation is clock-wise
|
Rotation drivers.Rotation // Rotation is clock-wise
|
||||||
Speed Speed // Value from DEFAULT, MEDIUM, FAST, TURBO
|
Speed Speed // Value from DEFAULT, SLOW, MEDIUM, FAST, FASTER, TURBO
|
||||||
Blocking bool
|
Blocking bool // block on calls to display or return immediately
|
||||||
|
FlickerFree bool // if we should avoid flickering
|
||||||
|
UpdateAfter int // if we are using flicker-free mode, how often we should update the screen
|
||||||
}
|
}
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
bus drivers.SPI
|
bus drivers.SPI
|
||||||
cs machine.Pin
|
cs machine.Pin
|
||||||
dc machine.Pin
|
dc machine.Pin
|
||||||
rst machine.Pin
|
rst machine.Pin
|
||||||
busy machine.Pin
|
busy machine.Pin
|
||||||
width int16
|
width int16
|
||||||
height int16
|
height int16
|
||||||
buffer []uint8
|
buffer []uint8
|
||||||
bufferLength uint32
|
bufferLength uint32
|
||||||
rotation drivers.Rotation
|
rotation drivers.Rotation
|
||||||
speed Speed
|
speed Speed
|
||||||
blocking bool
|
blocking bool
|
||||||
|
flickerFree bool
|
||||||
|
updateCount, updateAfter int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Speed uint8
|
type Speed uint8
|
||||||
|
|
||||||
// New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
|
// New returns a new uc8151 driver. Pass in a fully configured SPI bus.
|
||||||
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
|
||||||
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
@@ -73,6 +78,8 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
d.rotation = cfg.Rotation
|
d.rotation = cfg.Rotation
|
||||||
d.speed = cfg.Speed
|
d.speed = cfg.Speed
|
||||||
d.blocking = cfg.Blocking
|
d.blocking = cfg.Blocking
|
||||||
|
d.flickerFree = cfg.FlickerFree
|
||||||
|
d.updateAfter = cfg.UpdateAfter
|
||||||
d.bufferLength = (uint32(d.width) * uint32(d.height)) / 8
|
d.bufferLength = (uint32(d.width) * uint32(d.height)) / 8
|
||||||
d.buffer = make([]uint8, d.bufferLength)
|
d.buffer = make([]uint8, d.bufferLength)
|
||||||
for i := uint32(0); i < d.bufferLength; i++ {
|
for i := uint32(0); i < d.bufferLength; i++ {
|
||||||
@@ -88,14 +95,14 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
d.SendData(RES_128x296 | LUT_REG | FORMAT_BW | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE | SCAN_UP)
|
d.SendData(RES_128x296 | LUT_REG | FORMAT_BW | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE | SCAN_UP)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.SetLUT(d.speed)
|
d.SetLUT(d.speed, d.flickerFree)
|
||||||
|
|
||||||
d.SendCommand(PWR)
|
d.SendCommand(PWR)
|
||||||
d.SendData(VDS_INTERNAL | VDG_INTERNAL)
|
d.SendData(VDS_INTERNAL | VDG_INTERNAL)
|
||||||
d.SendData(VCOM_VG | VGHL_16V)
|
d.SendData(VCOM_VD | VGHL_16V)
|
||||||
d.SendData(0x2B)
|
d.SendData(0b100110) // +10v VDH
|
||||||
d.SendData(0x2B)
|
d.SendData(0b100110) // -10v VDL
|
||||||
d.SendData(0x2B)
|
d.SendData(0b000011) // VDHR default (For red pixels, not used here)
|
||||||
|
|
||||||
d.SendCommand(PON)
|
d.SendCommand(PON)
|
||||||
d.WaitUntilIdle()
|
d.WaitUntilIdle()
|
||||||
@@ -106,7 +113,7 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US)
|
d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US)
|
||||||
|
|
||||||
d.SendCommand(PFS)
|
d.SendCommand(PFS)
|
||||||
d.SendData(FRAMES_1)
|
d.SendData(FRAMES_4)
|
||||||
|
|
||||||
d.SendCommand(TSE)
|
d.SendCommand(TSE)
|
||||||
d.SendData(TEMP_INTERNAL | OFFSET_0)
|
d.SendData(TEMP_INTERNAL | OFFSET_0)
|
||||||
@@ -115,7 +122,7 @@ func (d *Device) Configure(cfg Config) {
|
|||||||
d.SendData(0x22)
|
d.SendData(0x22)
|
||||||
|
|
||||||
d.SendCommand(CDI)
|
d.SendCommand(CDI)
|
||||||
d.SendData(0x4C) // 4C //5C
|
d.SendData(0b11_00_1100)
|
||||||
|
|
||||||
d.SendCommand(PLL)
|
d.SendCommand(PLL)
|
||||||
d.SendData(HZ_100)
|
d.SendData(HZ_100)
|
||||||
@@ -199,6 +206,15 @@ func (d *Device) Display() error {
|
|||||||
if d.blocking {
|
if d.blocking {
|
||||||
d.WaitUntilIdle()
|
d.WaitUntilIdle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.flickerFree && d.updateAfter != 0 && d.updateCount%d.updateAfter == 0 {
|
||||||
|
// we need full refresh here
|
||||||
|
d.SetLUT(MEDIUM, false)
|
||||||
|
} else {
|
||||||
|
d.SetLUT(d.speed, d.flickerFree)
|
||||||
|
}
|
||||||
|
d.updateCount++
|
||||||
|
|
||||||
d.PowerOn()
|
d.PowerOn()
|
||||||
|
|
||||||
d.SendCommand(PTOU)
|
d.SendCommand(PTOU)
|
||||||
@@ -207,6 +223,9 @@ func (d *Device) Display() error {
|
|||||||
|
|
||||||
d.SendCommand(DSP)
|
d.SendCommand(DSP)
|
||||||
d.SendCommand(DRF)
|
d.SendCommand(DRF)
|
||||||
|
|
||||||
|
d.SetLUT(d.speed, d.flickerFree)
|
||||||
|
|
||||||
if d.blocking {
|
if d.blocking {
|
||||||
d.WaitUntilIdle()
|
d.WaitUntilIdle()
|
||||||
d.PowerOff()
|
d.PowerOff()
|
||||||
@@ -282,6 +301,12 @@ func (d *Device) DisplayRect(x int16, y int16, width int16, height int16) error
|
|||||||
|
|
||||||
// ClearDisplay erases the device SRAM
|
// ClearDisplay erases the device SRAM
|
||||||
func (d *Device) ClearDisplay() {
|
func (d *Device) ClearDisplay() {
|
||||||
|
ff := d.flickerFree
|
||||||
|
d.flickerFree = false
|
||||||
|
defer func() {
|
||||||
|
d.flickerFree = ff
|
||||||
|
}()
|
||||||
|
|
||||||
d.ClearBuffer()
|
d.ClearBuffer()
|
||||||
d.Display()
|
d.Display()
|
||||||
}
|
}
|
||||||
@@ -375,296 +400,81 @@ func (d *Device) Invert(invert bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLUT sets the look up tables for full or partial updates
|
// SetLUT sets the look up tables for full or partial updates based on
|
||||||
func (d *Device) SetLUT(speed Speed) {
|
// the speed and flicker-free mode.
|
||||||
switch speed {
|
// Based on code from https://github.com/antirez/uc8151_micropython
|
||||||
case MEDIUM:
|
func (d *Device) SetLUT(speed Speed, flickerFree bool) error {
|
||||||
var lut = [44]uint8{
|
var lut LUTSet
|
||||||
0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x00, 0x23, 0x23, 0x00, 0x00, 0x02,
|
|
||||||
0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00,
|
|
||||||
}
|
|
||||||
d.SendCommand(LUT_VCOM)
|
|
||||||
for i := 0; i < 44; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
|
|
||||||
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
// Num. of frames for single direction change.
|
||||||
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
period := 64
|
||||||
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
|
p := uint8(period / (2 ^ (int(speed) - 1)))
|
||||||
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
if p < 1 {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
p = 1
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
|
|
||||||
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
|
|
||||||
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case FAST:
|
|
||||||
var lut = [44]uint8{
|
|
||||||
0x00, 0x04, 0x04, 0x07, 0x00, 0x01,
|
|
||||||
0x00, 0x0c, 0x0c, 0x00, 0x00, 0x02,
|
|
||||||
0x00, 0x04, 0x04, 0x07, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00,
|
|
||||||
}
|
|
||||||
d.SendCommand(LUT_VCOM)
|
|
||||||
for i := 0; i < 44; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x04, 0x04, 0x07, 0x00, 0x01,
|
|
||||||
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
|
|
||||||
0xa8, 0x04, 0x04, 0x07, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x04, 0x04, 0x07, 0x00, 0x01,
|
|
||||||
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
|
|
||||||
0xa8, 0x04, 0x04, 0x07, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x04, 0x04, 0x07, 0x00, 0x01,
|
|
||||||
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
|
|
||||||
0x54, 0x04, 0x04, 0x07, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x04, 0x04, 0x07, 0x00, 0x01,
|
|
||||||
0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02,
|
|
||||||
0x54, 0x04, 0x04, 0x07, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
case TURBO:
|
|
||||||
var lut = [44]uint8{
|
|
||||||
0x00, 0x01, 0x01, 0x02, 0x00, 0x01,
|
|
||||||
0x00, 0x02, 0x02, 0x00, 0x00, 0x02,
|
|
||||||
0x00, 0x02, 0x02, 0x03, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00,
|
|
||||||
}
|
|
||||||
d.SendCommand(LUT_VCOM)
|
|
||||||
for i := 0; i < 44; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x01, 0x01, 0x02, 0x00, 0x01,
|
|
||||||
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
|
|
||||||
0xa8, 0x02, 0x02, 0x03, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x01, 0x01, 0x02, 0x00, 0x01,
|
|
||||||
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
|
|
||||||
0xa8, 0x02, 0x02, 0x03, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x01, 0x01, 0x02, 0x00, 0x01,
|
|
||||||
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
|
|
||||||
0x54, 0x02, 0x02, 0x03, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x01, 0x01, 0x02, 0x00, 0x01,
|
|
||||||
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
|
|
||||||
0x54, 0x02, 0x02, 0x03, 0x00, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
var lut = [44]uint8{
|
|
||||||
0x00, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x00, 0x8c, 0x8c, 0x00, 0x00, 0x04,
|
|
||||||
0x00, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00,
|
|
||||||
}
|
|
||||||
d.SendCommand(LUT_VCOM)
|
|
||||||
for i := 0; i < 44; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
|
|
||||||
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
|
|
||||||
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BW)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
|
|
||||||
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_WB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
lut = [44]uint8{
|
|
||||||
0xa8, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04,
|
|
||||||
0x54, 0x64, 0x64, 0x37, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
|
||||||
d.SendCommand(LUT_BB)
|
|
||||||
// do not send last two bytes
|
|
||||||
for i := 0; i < 42; i++ {
|
|
||||||
d.SendData(lut[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Num. of frames for back-and-forth change.
|
||||||
|
hperiod := period % 2
|
||||||
|
hp := uint8(hperiod / (2 ^ (int(speed) - 1)))
|
||||||
|
if hp < 1 {
|
||||||
|
hp = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if speed < FAST && !flickerFree {
|
||||||
|
// For low speed everything is charge-neutral, even WB/BW.
|
||||||
|
|
||||||
|
// Phase 1: long go-inverted-color.
|
||||||
|
lut.VCOM.SetRow(0, 0x00, [4]uint8{p, 0x00, 0x00, 0x00}, 0x02)
|
||||||
|
lut.BW.SetRow(0, 0b01_000000, [4]uint8{p, 0x00, 0x00, 0x00}, 0x02)
|
||||||
|
lut.WB.SetRow(0, 0b10_000000, [4]uint8{p, 0x00, 0x00, 0x00}, 0x02)
|
||||||
|
|
||||||
|
// Phase 2: short ping/pong.
|
||||||
|
lut.VCOM.SetRow(1, 0x00, [4]uint8{hp, hp, 0x00, 0x00}, 0x02)
|
||||||
|
lut.BW.SetRow(1, 0b10_01_0000, [4]uint8{hp, hp, 0x00, 0x00}, 0x01)
|
||||||
|
lut.WB.SetRow(1, 0b01_10_0000, [4]uint8{hp, hp, 0x00, 0x00}, 0x01)
|
||||||
|
|
||||||
|
// Phase 3: long go-target-color.
|
||||||
|
lut.VCOM.SetRow(2, 0x00, [4]uint8{p, 0x00, 0x00, 0x00}, 0x02)
|
||||||
|
lut.BW.SetRow(2, 0b10_000000, [4]uint8{p, 0x00, 0x00, 0x00}, 0x02)
|
||||||
|
lut.WB.SetRow(2, 0b01_000000, [4]uint8{p, 0x00, 0x00, 0x00}, 0x02)
|
||||||
|
|
||||||
|
// For this speed, we use the same LUTs for WW/BB as well.
|
||||||
|
copy(lut.WW[:], lut.BW[:])
|
||||||
|
copy(lut.BB[:], lut.WB[:])
|
||||||
|
} else {
|
||||||
|
// Speed >= FAST
|
||||||
|
// For greater than 3 we use non charge-neutral LUTs for WB/BW
|
||||||
|
// since the inpulse is short and it gets reversed when the
|
||||||
|
// pixel changes color, so that's not a problem for the display,
|
||||||
|
// however we still need to use charge-neutral LUTs for WW/BB.
|
||||||
|
lut.VCOM.SetRow(0, 0x00, [4]uint8{p, p, p, p}, 0x01)
|
||||||
|
lut.BW.SetRow(0, 0b10_00_00_00, [4]uint8{p * 4, 0x00, 0x00, 0x00}, 0x01)
|
||||||
|
lut.WB.SetRow(0, 0b01_00_00_00, [4]uint8{p * 4, 0x00, 0x00, 0x00}, 0x01)
|
||||||
|
lut.WW.SetRow(0, 0b01_10_00_00, [4]uint8{p * 2, p * 2, 0x00, 0x00}, 0x01)
|
||||||
|
lut.BB.SetRow(0, 0b10_01_00_00, [4]uint8{p * 2, p * 2, 0x00, 0x00}, 0x01)
|
||||||
|
}
|
||||||
|
|
||||||
|
if flickerFree {
|
||||||
|
// If no flickering mode is enabled, we use an empty
|
||||||
|
// waveform BB and WW. The screen will need to be periodically fully refreshed.
|
||||||
|
lut.WW.Clear()
|
||||||
|
lut.BB.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SendCommand(LUT_VCOM)
|
||||||
|
d.SendData(append(lut.VCOM[:], []uint8{0, 0}...)...)
|
||||||
|
|
||||||
|
d.SendCommand(LUT_BW)
|
||||||
|
d.SendData(lut.BW[:]...)
|
||||||
|
|
||||||
|
d.SendCommand(LUT_WB)
|
||||||
|
d.SendData(lut.WB[:]...)
|
||||||
|
|
||||||
|
d.SendCommand(LUT_WW)
|
||||||
|
d.SendData(lut.WW[:]...)
|
||||||
|
|
||||||
|
d.SendCommand(LUT_BB)
|
||||||
|
d.SendData(lut.BB[:]...)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user