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  }