tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/waveshare-epd/epd2in13x/epd2in13x.go (about)

     1  // Package epd2in13x implements a driver for Waveshare 2.13in (B & C versions) tri-color e-paper device.
     2  //
     3  // Datasheet: https://www.waveshare.com/w/upload/d/d3/2.13inch-e-paper-b-Specification.pdf
     4  package epd2in13x // import "tinygo.org/x/drivers/waveshare-epd/epd2in13x"
     5  
     6  import (
     7  	"errors"
     8  	"image/color"
     9  	"machine"
    10  	"time"
    11  
    12  	"tinygo.org/x/drivers"
    13  )
    14  
    15  type Config struct {
    16  	Width     int16
    17  	Height    int16
    18  	NumColors uint8
    19  }
    20  
    21  type Device struct {
    22  	bus          drivers.SPI
    23  	cs           machine.Pin
    24  	dc           machine.Pin
    25  	rst          machine.Pin
    26  	busy         machine.Pin
    27  	width        int16
    28  	height       int16
    29  	buffer       [][]uint8
    30  	bufferLength uint32
    31  }
    32  
    33  type Color uint8
    34  
    35  // New returns a new epd2in13x driver. Pass in a fully configured SPI bus.
    36  func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
    37  	csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
    38  	dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
    39  	rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
    40  	busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
    41  	return Device{
    42  		bus:  bus,
    43  		cs:   csPin,
    44  		dc:   dcPin,
    45  		rst:  rstPin,
    46  		busy: busyPin,
    47  	}
    48  }
    49  
    50  // Configure sets up the device.
    51  func (d *Device) Configure(cfg Config) {
    52  	if cfg.Width != 0 {
    53  		d.width = cfg.Width
    54  	} else {
    55  		d.width = 104
    56  	}
    57  	if cfg.Height != 0 {
    58  		d.height = cfg.Height
    59  	} else {
    60  		d.height = 212
    61  	}
    62  	if cfg.NumColors == 0 {
    63  		cfg.NumColors = 3
    64  	} else if cfg.NumColors == 1 {
    65  		cfg.NumColors = 2
    66  	}
    67  	d.bufferLength = (uint32(d.width) * uint32(d.height)) / 8
    68  	d.buffer = make([][]uint8, cfg.NumColors-1)
    69  	for i := range d.buffer {
    70  		d.buffer[i] = make([]uint8, d.bufferLength)
    71  	}
    72  	for i := range d.buffer {
    73  		for j := uint32(0); j < d.bufferLength; j++ {
    74  			d.buffer[i][j] = 0xFF
    75  		}
    76  	}
    77  
    78  	d.cs.Low()
    79  	d.dc.Low()
    80  	d.rst.Low()
    81  
    82  	d.Reset()
    83  
    84  	d.SendCommand(BOOSTER_SOFT_START)
    85  	d.SendData(0x17)
    86  	d.SendData(0x17)
    87  	d.SendData(0x17)
    88  	d.SendCommand(POWER_ON)
    89  	d.WaitUntilIdle()
    90  	d.SendCommand(PANEL_SETTING)
    91  	d.SendData(0x8F)
    92  	d.SendCommand(VCOM_AND_DATA_INTERVAL_SETTING)
    93  	d.SendData(0x37)
    94  	d.SendCommand(RESOLUTION_SETTING)
    95  	d.SendData(uint8(d.width))
    96  	d.SendData(0x00)
    97  	d.SendData(uint8(d.height))
    98  }
    99  
   100  // Reset resets the device
   101  func (d *Device) Reset() {
   102  	d.rst.Low()
   103  	time.Sleep(200 * time.Millisecond)
   104  	d.rst.High()
   105  	time.Sleep(200 * time.Millisecond)
   106  }
   107  
   108  // DeepSleep puts the display into deepsleep
   109  func (d *Device) DeepSleep() {
   110  	d.SendCommand(POWER_OFF)
   111  	d.WaitUntilIdle()
   112  	d.SendCommand(DEEP_SLEEP)
   113  	d.SendData(0xA5)
   114  }
   115  
   116  // SendCommand sends a command to the display
   117  func (d *Device) SendCommand(command uint8) {
   118  	d.sendDataCommand(true, command)
   119  }
   120  
   121  // SendData sends a data byte to the display
   122  func (d *Device) SendData(data uint8) {
   123  	d.sendDataCommand(false, data)
   124  }
   125  
   126  // sendDataCommand sends image data or a command to the screen
   127  func (d *Device) sendDataCommand(isCommand bool, data uint8) {
   128  	if isCommand {
   129  		d.dc.Low()
   130  	} else {
   131  		d.dc.High()
   132  	}
   133  	d.cs.Low()
   134  	d.bus.Transfer(data)
   135  	d.cs.High()
   136  }
   137  
   138  // SetPixel modifies the internal buffer in a single pixel.
   139  // The display have 3 colors: black, white and a third color that could be red or yellow
   140  // We use RGBA(0,0,0, 255) as white (transparent)
   141  // RGBA(1-255,0,0,255) as colored (red or yellow)
   142  // Anything else as black
   143  func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
   144  	if x < 0 || x >= d.width || y < 0 || y >= d.height {
   145  		return
   146  	}
   147  	if c.R != 0 && c.G == 0 && c.B == 0 { // COLORED
   148  		d.SetEPDPixel(x, y, COLORED)
   149  	} else if c.G != 0 || c.B != 0 { // BLACK
   150  		d.SetEPDPixel(x, y, BLACK)
   151  	} else { // WHITE / EMPTY
   152  		d.SetEPDPixel(x, y, WHITE)
   153  	}
   154  }
   155  
   156  // SetEPDPixel modifies the internal buffer in a single pixel.
   157  func (d *Device) SetEPDPixel(x int16, y int16, c Color) {
   158  	if x < 0 || x >= d.width || y < 0 || y >= d.height {
   159  		return
   160  	}
   161  	byteIndex := (x + y*d.width) / 8
   162  	if c == WHITE {
   163  		d.buffer[BLACK-1][byteIndex] |= 0x80 >> uint8(x%8)
   164  		d.buffer[COLORED-1][byteIndex] |= 0x80 >> uint8(x%8)
   165  	} else if c == COLORED {
   166  		d.buffer[BLACK-1][byteIndex] |= 0x80 >> uint8(x%8)
   167  		d.buffer[COLORED-1][byteIndex] &^= 0x80 >> uint8(x%8)
   168  	} else { // BLACK
   169  		d.buffer[COLORED-1][byteIndex] |= 0x80 >> uint8(x%8)
   170  		d.buffer[BLACK-1][byteIndex] &^= 0x80 >> uint8(x%8)
   171  	}
   172  }
   173  
   174  // Display sends the buffer (if any) to the screen.
   175  func (d *Device) Display() error {
   176  	d.SendCommand(DATA_START_TRANSMISSION_1) // black
   177  	time.Sleep(2 * time.Millisecond)
   178  	for i := uint32(0); i < d.bufferLength; i++ {
   179  		d.SendData(d.buffer[BLACK-1][i])
   180  	}
   181  	time.Sleep(2 * time.Millisecond)
   182  	d.SendCommand(DATA_START_TRANSMISSION_2) // red
   183  	time.Sleep(2 * time.Millisecond)
   184  	for i := uint32(0); i < d.bufferLength; i++ {
   185  		d.SendData(d.buffer[COLORED-1][i])
   186  	}
   187  	time.Sleep(2 * time.Millisecond)
   188  	d.SendCommand(DISPLAY_REFRESH)
   189  	return nil
   190  }
   191  
   192  // SetDisplayRect sends a rectangle of data at specific coordinates to the device SRAM directly
   193  func (d *Device) SetDisplayRect(buffer [][]uint8, x int16, y int16, w int16, h int16) error {
   194  	if w%8 != 0 {
   195  		return errors.New("rectangle width needs to be a multiple of 8")
   196  	}
   197  	for i := range buffer {
   198  		if int16(len(buffer[i])) < (w/8)*h {
   199  			return errors.New("buffer has the wrong size")
   200  		}
   201  	}
   202  	d.SendCommand(PARTIAL_IN)
   203  	d.SendCommand(PARTIAL_WINDOW)
   204  	d.SendData(uint8(x) & 0xF8)
   205  	d.SendData(((uint8(x) & 0xF8) + uint8(w) - 1) | 0x07)
   206  	d.SendData(uint8(y) >> 8)
   207  	d.SendData(uint8(y) & 0xFF)
   208  	d.SendData(uint8(y+h-1) >> 8)
   209  	d.SendData(uint8(y+h-1) & 0xFF)
   210  	d.SendData(0x01)
   211  	time.Sleep(2 * time.Millisecond)
   212  	d.SendCommand(DATA_START_TRANSMISSION_1)
   213  	for i := int16(0); i < (w/8)*h; i++ {
   214  		d.SendData(buffer[BLACK-1][i])
   215  	}
   216  	time.Sleep(2 * time.Millisecond)
   217  	if len(buffer) > 1 {
   218  		d.SendCommand(DATA_START_TRANSMISSION_2)
   219  		for i := int16(0); i < (w/8)*h; i++ {
   220  			d.SendData(buffer[COLORED-1][i])
   221  		}
   222  		time.Sleep(2 * time.Millisecond)
   223  	}
   224  	d.SendCommand(PARTIAL_OUT)
   225  	return nil
   226  }
   227  
   228  // SetDisplayRectColor sends a rectangle of data at specific coordinates to the device SRAM directly
   229  func (d *Device) SetDisplayRectColor(buffer []uint8, x int16, y int16, w int16, h int16, c Color) error {
   230  	if w%8 != 0 {
   231  		return errors.New("rectangle width needs to be a multiple of 8")
   232  	}
   233  	if int16(len(buffer)) < (w/8)*h {
   234  		return errors.New("buffer has the wrong size")
   235  	}
   236  	if c == WHITE {
   237  		return errors.New("wrong color")
   238  	}
   239  	d.SendCommand(PARTIAL_IN)
   240  	d.SendCommand(PARTIAL_WINDOW)
   241  	d.SendData(uint8(x) & 0xF8)
   242  	d.SendData(((uint8(x) & 0xF8) + uint8(w) - 1) | 0x07)
   243  	d.SendData(uint8(y) >> 8)
   244  	d.SendData(uint8(y) & 0xFF)
   245  	d.SendData(uint8(y+h-1) >> 8)
   246  	d.SendData(uint8(y+h-1) & 0xFF)
   247  	d.SendData(0x01)
   248  	time.Sleep(2 * time.Millisecond)
   249  	if c == COLORED {
   250  		d.SendCommand(DATA_START_TRANSMISSION_2)
   251  	} else {
   252  		d.SendCommand(DATA_START_TRANSMISSION_1)
   253  	}
   254  	for i := int16(0); i < (w/8)*h; i++ {
   255  		d.SendData(buffer[i])
   256  	}
   257  	time.Sleep(2 * time.Millisecond)
   258  	d.SendCommand(PARTIAL_OUT)
   259  	return nil
   260  }
   261  
   262  // ClearDisplay erases the device SRAM
   263  func (d *Device) ClearDisplay() {
   264  	d.SendCommand(DATA_START_TRANSMISSION_1) // black
   265  	time.Sleep(2 * time.Millisecond)
   266  	for i := uint32(0); i < d.bufferLength; i++ {
   267  		d.SendData(0xFF)
   268  	}
   269  	time.Sleep(2 * time.Millisecond)
   270  	d.SendCommand(DATA_START_TRANSMISSION_2) // red
   271  	time.Sleep(2 * time.Millisecond)
   272  	for i := uint32(0); i < d.bufferLength; i++ {
   273  		d.SendData(0xFF)
   274  	}
   275  	time.Sleep(2 * time.Millisecond)
   276  }
   277  
   278  // WaitUntilIdle waits until the display is ready
   279  func (d *Device) WaitUntilIdle() {
   280  	for !d.busy.Get() {
   281  		time.Sleep(100 * time.Millisecond)
   282  	}
   283  }
   284  
   285  // IsBusy returns the busy status of the display
   286  func (d *Device) IsBusy() bool {
   287  	return d.busy.Get()
   288  }
   289  
   290  // ClearBuffer sets the buffer to 0xFF (white)
   291  func (d *Device) ClearBuffer() {
   292  	for i := uint8(0); i < uint8(len(d.buffer)); i++ {
   293  		for j := uint32(0); j < d.bufferLength; j++ {
   294  			d.buffer[i][j] = 0xFF
   295  		}
   296  	}
   297  }
   298  
   299  // Size returns the current size of the display.
   300  func (d *Device) Size() (w, h int16) {
   301  	return d.width, d.height
   302  }