From 13cb37028c25bda40835e66407e76f1479656da0 Mon Sep 17 00:00:00 2001 From: deadprogram Date: Fri, 10 May 2024 17:57:21 +0200 Subject: [PATCH] uc8151: improvements to speed and also add flicker-free mode based on @antirez code example Signed-off-by: deadprogram --- examples/uc8151/main.go | 51 +++-- uc8151/lut.go | 30 +++ uc8151/registers.go | 8 +- uc8151/uc8151.go | 418 +++++++++++----------------------------- 4 files changed, 188 insertions(+), 319 deletions(-) create mode 100644 uc8151/lut.go diff --git a/examples/uc8151/main.go b/examples/uc8151/main.go index c0e7520fd..1ee778b6b 100644 --- a/examples/uc8151/main.go +++ b/examples/uc8151/main.go @@ -3,6 +3,7 @@ package main import ( "image/color" "machine" + "time" "tinygo.org/x/drivers" "tinygo.org/x/drivers/uc8151" @@ -15,30 +16,56 @@ func main() { led = machine.LED led.Configure(machine.PinConfig{Mode: machine.PinOutput}) machine.SPI0.Configure(machine.SPIConfig{ - Frequency: 12000000, + Frequency: 12 * machine.MHz, SCK: machine.EPD_SCK_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.Configure(uc8151.Config{ - Rotation: drivers.Rotation270, - Speed: uc8151.MEDIUM, - Blocking: true, + Rotation: drivers.Rotation270, + Speed: uc8151.TURBO, + FlickerFree: true, + Blocking: false, }) black := color.RGBA{1, 1, 1, 255} - display.ClearBuffer() - display.Display() - for i := int16(0); i < 37; i++ { - for j := int16(0); j < 16; j++ { - if (i+j)%2 == 0 { - showRect(i*8, j*8, 8, 8, black) + display.ClearDisplay() + + mod := int16(1) + for { + // checkerboard + 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) } - } - display.Display() + // 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) + } + } + } } func showRect(x int16, y int16, w int16, h int16, c color.RGBA) { diff --git a/uc8151/lut.go b/uc8151/lut.go new file mode 100644 index 000000000..392488bf0 --- /dev/null +++ b/uc8151/lut.go @@ -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 +} diff --git a/uc8151/registers.go b/uc8151/registers.go index c4170c87d..407d7a44f 100644 --- a/uc8151/registers.go +++ b/uc8151/registers.go @@ -150,7 +150,9 @@ const ( ROTATION_270 = drivers.Rotation270 DEFAULT Speed = 0 - MEDIUM Speed = 1 - FAST Speed = 2 - TURBO Speed = 3 + SLOW Speed = 1 + MEDIUM Speed = 2 + FAST Speed = 3 + FASTER Speed = 4 + TURBO Speed = 5 ) diff --git a/uc8151/uc8151.go b/uc8151/uc8151.go index 1775f1b21..0c658d107 100644 --- a/uc8151/uc8151.go +++ b/uc8151/uc8151.go @@ -1,6 +1,7 @@ // 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 +// Additional inspiration from https://github.com/antirez/uc8151_micropython // Datasheet: https://www.buydisplay.com/download/ic/UC8151C.pdf package uc8151 // import "tinygo.org/x/drivers/uc8151" @@ -19,31 +20,35 @@ var ( ) type Config struct { - Width int16 - Height int16 - Rotation drivers.Rotation // Rotation is clock-wise - Speed Speed // Value from DEFAULT, MEDIUM, FAST, TURBO - Blocking bool + Width int16 + Height int16 + Rotation drivers.Rotation // Rotation is clock-wise + Speed Speed // Value from DEFAULT, SLOW, MEDIUM, FAST, FASTER, TURBO + 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 { - bus drivers.SPI - cs machine.Pin - dc machine.Pin - rst machine.Pin - busy machine.Pin - width int16 - height int16 - buffer []uint8 - bufferLength uint32 - rotation drivers.Rotation - speed Speed - blocking bool + bus drivers.SPI + cs machine.Pin + dc machine.Pin + rst machine.Pin + busy machine.Pin + width int16 + height int16 + buffer []uint8 + bufferLength uint32 + rotation drivers.Rotation + speed Speed + blocking bool + flickerFree bool + updateCount, updateAfter int } 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 { csPin.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.speed = cfg.Speed d.blocking = cfg.Blocking + d.flickerFree = cfg.FlickerFree + d.updateAfter = cfg.UpdateAfter d.bufferLength = (uint32(d.width) * uint32(d.height)) / 8 d.buffer = make([]uint8, d.bufferLength) 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.SetLUT(d.speed) + d.SetLUT(d.speed, d.flickerFree) d.SendCommand(PWR) d.SendData(VDS_INTERNAL | VDG_INTERNAL) - d.SendData(VCOM_VG | VGHL_16V) - d.SendData(0x2B) - d.SendData(0x2B) - d.SendData(0x2B) + d.SendData(VCOM_VD | VGHL_16V) + d.SendData(0b100110) // +10v VDH + d.SendData(0b100110) // -10v VDL + d.SendData(0b000011) // VDHR default (For red pixels, not used here) d.SendCommand(PON) d.WaitUntilIdle() @@ -106,7 +113,7 @@ func (d *Device) Configure(cfg Config) { d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US) d.SendCommand(PFS) - d.SendData(FRAMES_1) + d.SendData(FRAMES_4) d.SendCommand(TSE) d.SendData(TEMP_INTERNAL | OFFSET_0) @@ -115,7 +122,7 @@ func (d *Device) Configure(cfg Config) { d.SendData(0x22) d.SendCommand(CDI) - d.SendData(0x4C) // 4C //5C + d.SendData(0b11_00_1100) d.SendCommand(PLL) d.SendData(HZ_100) @@ -199,6 +206,15 @@ func (d *Device) Display() error { if d.blocking { 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.SendCommand(PTOU) @@ -207,6 +223,9 @@ func (d *Device) Display() error { d.SendCommand(DSP) d.SendCommand(DRF) + + d.SetLUT(d.speed, d.flickerFree) + if d.blocking { d.WaitUntilIdle() d.PowerOff() @@ -282,6 +301,12 @@ func (d *Device) DisplayRect(x int16, y int16, width int16, height int16) error // ClearDisplay erases the device SRAM func (d *Device) ClearDisplay() { + ff := d.flickerFree + d.flickerFree = false + defer func() { + d.flickerFree = ff + }() + d.ClearBuffer() d.Display() } @@ -375,296 +400,81 @@ func (d *Device) Invert(invert bool) { } } -// SetLUT sets the look up tables for full or partial updates -func (d *Device) SetLUT(speed Speed) { - switch speed { - case MEDIUM: - var lut = [44]uint8{ - 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{ - 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_BW) - // do not send last two bytes - for i := 0; i < 42; i++ { - d.SendData(lut[i]) - } +// SetLUT sets the look up tables for full or partial updates based on +// the speed and flicker-free mode. +// Based on code from https://github.com/antirez/uc8151_micropython +func (d *Device) SetLUT(speed Speed, flickerFree bool) error { + var lut LUTSet + + // Num. of frames for single direction change. + period := 64 + p := uint8(period / (2 ^ (int(speed) - 1))) + if p < 1 { + p = 1 + } - 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]) - } + // Num. of frames for back-and-forth change. + hperiod := period % 2 + hp := uint8(hperiod / (2 ^ (int(speed) - 1))) + if hp < 1 { + hp = 1 + } - 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]) - } + if speed < FAST && !flickerFree { + // For low speed everything is charge-neutral, even WB/BW. - 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]) - } + // 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) - 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]) - } + // 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) - 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]) - } + // 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) - 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]) - } + // 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) + } - 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]) - } + 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() + } - 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]) - } + d.SendCommand(LUT_VCOM) + d.SendData(append(lut.VCOM[:], []uint8{0, 0}...)...) - 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]) - } + d.SendCommand(LUT_BW) + d.SendData(lut.BW[:]...) - 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]) - } + d.SendCommand(LUT_WB) + d.SendData(lut.WB[:]...) - 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]) - } + d.SendCommand(LUT_WW) + d.SendData(lut.WW[:]...) - 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]) - } + d.SendCommand(LUT_BB) + d.SendData(lut.BB[:]...) - break - } + return nil }