tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/uc8151/uc8151.go (about) 1 // Package uc8151 implements a driver for e-ink displays controlled by UC8151 2 // 3 // Inspired by https://github.com/pimoroni/pimoroni-pico/blob/main/drivers/uc8151/uc8151.cpp 4 // Datasheet: https://www.buydisplay.com/download/ic/UC8151C.pdf 5 package uc8151 // import "tinygo.org/x/drivers/uc8151" 6 7 import ( 8 "errors" 9 "image/color" 10 "machine" 11 "time" 12 13 "tinygo.org/x/drivers" 14 "tinygo.org/x/drivers/pixel" 15 ) 16 17 var ( 18 errOutOfRange = errors.New("out of screen range") 19 ) 20 21 type Config struct { 22 Width int16 23 Height int16 24 Rotation drivers.Rotation // Rotation is clock-wise 25 Speed Speed // Value from DEFAULT, MEDIUM, FAST, TURBO 26 Blocking bool 27 } 28 29 type Device struct { 30 bus drivers.SPI 31 cs machine.Pin 32 dc machine.Pin 33 rst machine.Pin 34 busy machine.Pin 35 width int16 36 height int16 37 buffer []uint8 38 bufferLength uint32 39 rotation drivers.Rotation 40 speed Speed 41 blocking bool 42 } 43 44 type Speed uint8 45 46 // New returns a new epd2in13x driver. Pass in a fully configured SPI bus. 47 func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device { 48 csPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) 49 dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) 50 rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) 51 busyPin.Configure(machine.PinConfig{Mode: machine.PinInput}) 52 return Device{ 53 bus: bus, 54 cs: csPin, 55 dc: dcPin, 56 rst: rstPin, 57 busy: busyPin, 58 } 59 } 60 61 // Configure sets up the device. 62 func (d *Device) Configure(cfg Config) { 63 if cfg.Width != 0 { 64 d.width = cfg.Width 65 } else { 66 d.width = EPD_WIDTH 67 } 68 if cfg.Height != 0 { 69 d.height = cfg.Height 70 } else { 71 d.height = EPD_HEIGHT 72 } 73 d.rotation = cfg.Rotation 74 d.speed = cfg.Speed 75 d.blocking = cfg.Blocking 76 d.bufferLength = (uint32(d.width) * uint32(d.height)) / 8 77 d.buffer = make([]uint8, d.bufferLength) 78 for i := uint32(0); i < d.bufferLength; i++ { 79 d.buffer[i] = 0xFF 80 } 81 82 d.Reset() 83 84 d.SendCommand(PSR) 85 if d.speed == 0 { 86 d.SendData(RES_128x296 | LUT_OTP | FORMAT_BW | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE | SCAN_UP) 87 } else { 88 d.SendData(RES_128x296 | LUT_REG | FORMAT_BW | SHIFT_RIGHT | BOOSTER_ON | RESET_NONE | SCAN_UP) 89 } 90 91 d.SetLUT(d.speed) 92 93 d.SendCommand(PWR) 94 d.SendData(VDS_INTERNAL | VDG_INTERNAL) 95 d.SendData(VCOM_VG | VGHL_16V) 96 d.SendData(0x2B) 97 d.SendData(0x2B) 98 d.SendData(0x2B) 99 100 d.SendCommand(PON) 101 d.WaitUntilIdle() 102 103 d.SendCommand(BTST) 104 d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US) 105 d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US) 106 d.SendData(START_10MS | STRENGTH_3 | OFF_6_58US) 107 108 d.SendCommand(PFS) 109 d.SendData(FRAMES_1) 110 111 d.SendCommand(TSE) 112 d.SendData(TEMP_INTERNAL | OFFSET_0) 113 114 d.SendCommand(TCON) 115 d.SendData(0x22) 116 117 d.SendCommand(CDI) 118 d.SendData(0x4C) // 4C //5C 119 120 d.SendCommand(PLL) 121 d.SendData(HZ_100) 122 123 d.SendCommand(POF) 124 d.WaitUntilIdle() 125 } 126 127 // Reset resets the device 128 func (d *Device) Reset() { 129 d.rst.Low() 130 time.Sleep(10 * time.Millisecond) 131 d.rst.High() 132 time.Sleep(10 * time.Millisecond) 133 d.WaitUntilIdle() 134 } 135 136 // PowerOff power off the device 137 func (d *Device) PowerOff() { 138 d.SendCommand(POF) 139 } 140 141 // PowerOn power on the device 142 func (d *Device) PowerOn() { 143 d.SendCommand(PON) 144 } 145 146 // SendCommand sends a command to the display 147 func (d *Device) SendCommand(command uint8) { 148 d.dc.Low() 149 d.cs.Low() 150 d.bus.Transfer(command) 151 d.cs.High() 152 } 153 154 // SendData sends a data byte to the display 155 func (d *Device) SendData(data ...uint8) { 156 d.dc.High() 157 d.cs.Low() 158 d.bus.Tx(data, nil) 159 d.cs.High() 160 } 161 162 // SetPixel modifies the internal buffer in a single pixel. 163 // The display have 2 colors: black and white 164 // We use RGBA(0, 0, 0) as white (transparent) 165 // Anything else as black 166 func (d *Device) SetPixel(x int16, y int16, c color.RGBA) { 167 x, y = d.xy(x, y) 168 169 if x < 0 || x >= d.width || y < 0 || y >= d.height { 170 return 171 } 172 byteIndex := x/8 + y*(d.width/8) 173 if c.R != 0 || c.G != 0 || c.B != 0 { 174 d.buffer[byteIndex] |= 0x80 >> uint8(x%8) 175 } else { 176 d.buffer[byteIndex] &^= 0x80 >> uint8(x%8) 177 } 178 } 179 180 // DrawBitmap copies the bitmap to the screen at the given coordinates. 181 func (d *Device) DrawBitmap(x, y int16, bitmap pixel.Image[pixel.Monochrome]) error { 182 dw, dh := d.Size() 183 bw, bh := bitmap.Size() 184 if x < 0 || x+int16(bw) > dw || y < 0 || y+int16(bh) > dh { 185 return errOutOfRange 186 } 187 188 for i := 0; i < bw; i++ { 189 for j := 0; j < bh; j++ { 190 d.SetPixel(x+int16(i), y+int16(j), bitmap.Get(i, j).RGBA()) 191 } 192 } 193 194 return nil 195 } 196 197 // Display sends the buffer to the screen. 198 func (d *Device) Display() error { 199 if d.blocking { 200 d.WaitUntilIdle() 201 } 202 d.PowerOn() 203 204 d.SendCommand(PTOU) 205 d.SendCommand(DTM2) 206 d.SendData(d.buffer...) 207 208 d.SendCommand(DSP) 209 d.SendCommand(DRF) 210 if d.blocking { 211 d.WaitUntilIdle() 212 d.PowerOff() 213 } 214 215 return nil 216 } 217 218 // DisplayRect sends only an area of the buffer to the screen. 219 // The rectangle points need to be a multiple of 8 in the screen. 220 // They might not work as expected if the screen is rotated. 221 func (d *Device) DisplayRect(x int16, y int16, width int16, height int16) error { 222 if d.blocking { 223 d.WaitUntilIdle() 224 } 225 226 x, y = d.xy(x, y) 227 if x < 0 || y < 0 || x >= d.width || y >= d.height || width < 0 || height < 0 { 228 return errors.New("wrong rectangle") 229 } 230 switch d.rotation { 231 case drivers.Rotation0: 232 width, height = height, width 233 x -= width 234 case drivers.Rotation90: 235 x -= width - 1 236 y -= height - 1 237 case drivers.Rotation180: 238 width, height = height, width 239 y -= height 240 } 241 x &= 0xF8 242 width &= 0xF8 243 width = x + width // reuse variables 244 if width >= d.width { 245 width = d.width 246 } 247 height = y + height 248 if height > d.height { 249 height = d.height 250 } 251 252 d.SendCommand(PON) 253 d.SendCommand(PTIN) 254 d.SendCommand(PTL) 255 256 d.SendData(uint8(x)) 257 d.SendData(uint8(x+width-1) | 0x07) 258 d.SendData(uint8(y >> 8)) 259 d.SendData(uint8(y)) 260 d.SendData(uint8((y + height - 1) >> 8)) 261 d.SendData(uint8(y + height - 1)) 262 d.SendData(0x01) 263 264 d.SendCommand(DTM2) 265 x = x / 8 266 width = width / 8 267 for ; y < height; y++ { 268 for i := x; i < width; i++ { 269 d.SendData(d.buffer[i+y*(d.width/8)]) 270 } 271 } 272 273 d.SendCommand(DSP) 274 d.SendCommand(DRF) 275 276 if d.blocking { 277 d.WaitUntilIdle() 278 d.PowerOff() 279 } 280 return nil 281 } 282 283 // ClearDisplay erases the device SRAM 284 func (d *Device) ClearDisplay() { 285 d.ClearBuffer() 286 d.Display() 287 } 288 289 // WaitUntilIdle waits until the display is ready 290 func (d *Device) WaitUntilIdle() { 291 for !d.busy.Get() { 292 time.Sleep(10 * time.Millisecond) 293 } 294 } 295 296 // IsBusy returns the busy status of the display 297 func (d *Device) IsBusy() bool { 298 return d.busy.Get() 299 } 300 301 // ClearBuffer sets the buffer to 0xFF (white) 302 func (d *Device) ClearBuffer() { 303 for i := uint32(0); i < d.bufferLength; i++ { 304 d.buffer[i] = 0x00 305 } 306 } 307 308 // Size returns the current size of the display. 309 func (d *Device) Size() (w, h int16) { 310 if d.rotation == drivers.Rotation90 || d.rotation == drivers.Rotation270 { 311 return d.height, d.width 312 } 313 return d.width, d.height 314 } 315 316 // Rotation returns the currently configured rotation. 317 func (d *Device) Rotation() drivers.Rotation { 318 return d.rotation 319 } 320 321 // SetRotation changes the rotation (clock-wise) of the device 322 func (d *Device) SetRotation(rotation drivers.Rotation) error { 323 d.rotation = rotation 324 return nil 325 } 326 327 // Set the sleep mode for this display. 328 func (d *Device) Sleep(sleepEnabled bool) error { 329 if sleepEnabled { 330 d.PowerOff() 331 return nil 332 } 333 334 d.PowerOn() 335 return nil 336 } 337 338 // SetBlocking changes the blocking flag of the device 339 func (d *Device) SetBlocking(blocking bool) { 340 d.blocking = blocking 341 } 342 343 // xy changes the coordinates according to the rotation 344 func (d *Device) xy(x, y int16) (int16, int16) { 345 switch d.rotation { 346 case drivers.Rotation0: 347 return x, y 348 case drivers.Rotation90: 349 return d.width - y - 1, x 350 case drivers.Rotation180: 351 return d.width - x - 1, d.height - y - 1 352 case drivers.Rotation270: 353 return y, d.height - x - 1 354 } 355 return x, y 356 } 357 358 // SetSpeed changes the refresh speed of the device (the display needs to re-configure) 359 func (d *Device) SetSpeed(speed Speed) { 360 d.Configure(Config{ 361 Width: d.width, 362 Height: d.height, 363 Rotation: d.rotation, 364 Speed: speed, 365 Blocking: d.blocking, 366 }) 367 } 368 369 // Invert sets the display' invert mode 370 func (d *Device) Invert(invert bool) { 371 if invert { 372 d.SendData(0x5C) 373 } else { 374 d.SendData(0x4C) 375 } 376 } 377 378 // SetLUT sets the look up tables for full or partial updates 379 func (d *Device) SetLUT(speed Speed) { 380 switch speed { 381 case MEDIUM: 382 var lut = [44]uint8{ 383 0x00, 0x16, 0x16, 0x0d, 0x00, 0x01, 384 0x00, 0x23, 0x23, 0x00, 0x00, 0x02, 385 0x00, 0x16, 0x16, 0x0d, 0x00, 0x01, 386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 390 0x00, 0x00, 391 } 392 d.SendCommand(LUT_VCOM) 393 for i := 0; i < 44; i++ { 394 d.SendData(lut[i]) 395 } 396 lut = [44]uint8{ 397 0x54, 0x16, 0x16, 0x0d, 0x00, 0x01, 398 0x60, 0x23, 0x23, 0x00, 0x00, 0x02, 399 0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01, 400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 401 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 404 d.SendCommand(LUT_WW) 405 // do not send last two bytes 406 for i := 0; i < 42; i++ { 407 d.SendData(lut[i]) 408 } 409 410 lut = [44]uint8{ 411 0x54, 0x16, 0x16, 0x0d, 0x00, 0x01, 412 0x60, 0x23, 0x23, 0x00, 0x00, 0x02, 413 0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01, 414 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 416 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 418 d.SendCommand(LUT_BW) 419 // do not send last two bytes 420 for i := 0; i < 42; i++ { 421 d.SendData(lut[i]) 422 } 423 424 lut = [44]uint8{ 425 0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01, 426 0x60, 0x23, 0x23, 0x00, 0x00, 0x02, 427 0x54, 0x16, 0x16, 0x0d, 0x00, 0x01, 428 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 431 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 432 d.SendCommand(LUT_WB) 433 // do not send last two bytes 434 for i := 0; i < 42; i++ { 435 d.SendData(lut[i]) 436 } 437 438 lut = [44]uint8{ 439 0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01, 440 0x60, 0x23, 0x23, 0x00, 0x00, 0x02, 441 0x54, 0x16, 0x16, 0x0d, 0x00, 0x01, 442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 446 d.SendCommand(LUT_BB) 447 // do not send last two bytes 448 for i := 0; i < 42; i++ { 449 d.SendData(lut[i]) 450 } 451 452 break 453 case FAST: 454 var lut = [44]uint8{ 455 0x00, 0x04, 0x04, 0x07, 0x00, 0x01, 456 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x02, 457 0x00, 0x04, 0x04, 0x07, 0x00, 0x02, 458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 462 0x00, 0x00, 463 } 464 d.SendCommand(LUT_VCOM) 465 for i := 0; i < 44; i++ { 466 d.SendData(lut[i]) 467 } 468 lut = [44]uint8{ 469 0x54, 0x04, 0x04, 0x07, 0x00, 0x01, 470 0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02, 471 0xa8, 0x04, 0x04, 0x07, 0x00, 0x02, 472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 473 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 476 d.SendCommand(LUT_WW) 477 // do not send last two bytes 478 for i := 0; i < 42; i++ { 479 d.SendData(lut[i]) 480 } 481 482 lut = [44]uint8{ 483 0x54, 0x04, 0x04, 0x07, 0x00, 0x01, 484 0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02, 485 0xa8, 0x04, 0x04, 0x07, 0x00, 0x02, 486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 490 d.SendCommand(LUT_BW) 491 // do not send last two bytes 492 for i := 0; i < 42; i++ { 493 d.SendData(lut[i]) 494 } 495 496 lut = [44]uint8{ 497 0xa8, 0x04, 0x04, 0x07, 0x00, 0x01, 498 0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02, 499 0x54, 0x04, 0x04, 0x07, 0x00, 0x02, 500 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 504 d.SendCommand(LUT_WB) 505 // do not send last two bytes 506 for i := 0; i < 42; i++ { 507 d.SendData(lut[i]) 508 } 509 510 lut = [44]uint8{ 511 0xa8, 0x04, 0x04, 0x07, 0x00, 0x01, 512 0x60, 0x0c, 0x0c, 0x00, 0x00, 0x02, 513 0x54, 0x04, 0x04, 0x07, 0x00, 0x02, 514 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 518 d.SendCommand(LUT_BB) 519 // do not send last two bytes 520 for i := 0; i < 42; i++ { 521 d.SendData(lut[i]) 522 } 523 524 break 525 case TURBO: 526 var lut = [44]uint8{ 527 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 528 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 529 0x00, 0x02, 0x02, 0x03, 0x00, 0x02, 530 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 531 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 532 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 534 0x00, 0x00, 535 } 536 d.SendCommand(LUT_VCOM) 537 for i := 0; i < 44; i++ { 538 d.SendData(lut[i]) 539 } 540 lut = [44]uint8{ 541 0x54, 0x01, 0x01, 0x02, 0x00, 0x01, 542 0x60, 0x02, 0x02, 0x00, 0x00, 0x02, 543 0xa8, 0x02, 0x02, 0x03, 0x00, 0x02, 544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 548 d.SendCommand(LUT_WW) 549 // do not send last two bytes 550 for i := 0; i < 42; i++ { 551 d.SendData(lut[i]) 552 } 553 554 lut = [44]uint8{ 555 0x54, 0x01, 0x01, 0x02, 0x00, 0x01, 556 0x60, 0x02, 0x02, 0x00, 0x00, 0x02, 557 0xa8, 0x02, 0x02, 0x03, 0x00, 0x02, 558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 562 d.SendCommand(LUT_BW) 563 // do not send last two bytes 564 for i := 0; i < 42; i++ { 565 d.SendData(lut[i]) 566 } 567 568 lut = [44]uint8{ 569 0xa8, 0x01, 0x01, 0x02, 0x00, 0x01, 570 0x60, 0x02, 0x02, 0x00, 0x00, 0x02, 571 0x54, 0x02, 0x02, 0x03, 0x00, 0x02, 572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 576 d.SendCommand(LUT_WB) 577 // do not send last two bytes 578 for i := 0; i < 42; i++ { 579 d.SendData(lut[i]) 580 } 581 582 lut = [44]uint8{ 583 0xa8, 0x01, 0x01, 0x02, 0x00, 0x01, 584 0x60, 0x02, 0x02, 0x00, 0x00, 0x02, 585 0x54, 0x02, 0x02, 0x03, 0x00, 0x02, 586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 590 d.SendCommand(LUT_BB) 591 // do not send last two bytes 592 for i := 0; i < 42; i++ { 593 d.SendData(lut[i]) 594 } 595 596 break 597 default: 598 var lut = [44]uint8{ 599 0x00, 0x64, 0x64, 0x37, 0x00, 0x01, 600 0x00, 0x8c, 0x8c, 0x00, 0x00, 0x04, 601 0x00, 0x64, 0x64, 0x37, 0x00, 0x01, 602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 606 0x00, 0x00, 607 } 608 d.SendCommand(LUT_VCOM) 609 for i := 0; i < 44; i++ { 610 d.SendData(lut[i]) 611 } 612 lut = [44]uint8{ 613 0x54, 0x64, 0x64, 0x37, 0x00, 0x01, 614 0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04, 615 0xa8, 0x64, 0x64, 0x37, 0x00, 0x01, 616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 620 d.SendCommand(LUT_WW) 621 // do not send last two bytes 622 for i := 0; i < 42; i++ { 623 d.SendData(lut[i]) 624 } 625 626 lut = [44]uint8{ 627 0x54, 0x64, 0x64, 0x37, 0x00, 0x01, 628 0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04, 629 0xa8, 0x64, 0x64, 0x37, 0x00, 0x01, 630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 634 d.SendCommand(LUT_BW) 635 // do not send last two bytes 636 for i := 0; i < 42; i++ { 637 d.SendData(lut[i]) 638 } 639 640 lut = [44]uint8{ 641 0xa8, 0x64, 0x64, 0x37, 0x00, 0x01, 642 0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04, 643 0x54, 0x64, 0x64, 0x37, 0x00, 0x01, 644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 648 d.SendCommand(LUT_WB) 649 // do not send last two bytes 650 for i := 0; i < 42; i++ { 651 d.SendData(lut[i]) 652 } 653 654 lut = [44]uint8{ 655 0xa8, 0x64, 0x64, 0x37, 0x00, 0x01, 656 0x60, 0x8c, 0x8c, 0x00, 0x00, 0x04, 657 0x54, 0x64, 0x64, 0x37, 0x00, 0x01, 658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 662 d.SendCommand(LUT_BB) 663 // do not send last two bytes 664 for i := 0; i < 42; i++ { 665 d.SendData(lut[i]) 666 } 667 668 break 669 } 670 }