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

     1  // Package pcd8544 implements a driver for the PCD8544 48x84 pixels matrix LCD, used in Nokia's 5110 and 3310 phones.
     2  //
     3  // Datasheet: http://eia.udg.edu/~forest/PCD8544_1.pdf
     4  package pcd8544 // import "tinygo.org/x/drivers/pcd8544"
     5  
     6  import (
     7  	"errors"
     8  	"image/color"
     9  	"machine"
    10  	"time"
    11  
    12  	"tinygo.org/x/drivers"
    13  )
    14  
    15  // Device wraps an SPI connection.
    16  type Device struct {
    17  	bus        drivers.SPI
    18  	dcPin      machine.Pin
    19  	rstPin     machine.Pin
    20  	scePin     machine.Pin
    21  	buffer     []byte
    22  	width      int16
    23  	height     int16
    24  	bufferSize int16
    25  }
    26  
    27  type Config struct {
    28  	Width  int16
    29  	Height int16
    30  }
    31  
    32  // New creates a new PCD8544 connection. The SPI bus must already be configured.
    33  func New(bus drivers.SPI, dcPin, rstPin, scePin machine.Pin) *Device {
    34  	return &Device{
    35  		bus:    bus,
    36  		dcPin:  dcPin,
    37  		rstPin: rstPin,
    38  		scePin: scePin,
    39  	}
    40  }
    41  
    42  // Configure initializes the display with default configuration
    43  func (d *Device) Configure(cfg Config) {
    44  	if cfg.Width != 0 {
    45  		d.width = cfg.Width
    46  	} else {
    47  		d.width = 84
    48  	}
    49  	if cfg.Height != 0 {
    50  		d.height = cfg.Height
    51  	} else {
    52  		d.height = 48
    53  	}
    54  	d.bufferSize = d.width * d.height / 8
    55  	d.buffer = make([]byte, d.bufferSize)
    56  
    57  	d.rstPin.Low()
    58  	time.Sleep(100 * time.Nanosecond)
    59  	d.rstPin.High()
    60  	d.SendCommand(FUNCTIONSET | EXTENDEDINSTRUCTION) // H = 1
    61  	d.SendCommand(SETVOP | 0x3f)                     // 0x3f : Vop6 = 0, Vop5 to Vop0 = 1
    62  	d.SendCommand(SETTEMP | 0x03)                    // Experimentally determined
    63  	d.SendCommand(SETBIAS | 0x03)                    // Experimentally determined
    64  	d.SendCommand(FUNCTIONSET)                       // H = 0
    65  	d.SendCommand(DISPLAYCONTROL | DISPLAYNORMAL)
    66  }
    67  
    68  // ClearBuffer clears the image buffer
    69  func (d *Device) ClearBuffer() {
    70  	d.buffer = make([]byte, d.bufferSize)
    71  }
    72  
    73  // ClearDisplay clears the image buffer and clear the display
    74  func (d *Device) ClearDisplay() {
    75  	d.ClearBuffer()
    76  	d.Display()
    77  }
    78  
    79  // Display sends the whole buffer to the screen
    80  func (d *Device) Display() error {
    81  	d.SendCommand(FUNCTIONSET) // H = 0
    82  	d.SendCommand(SETXADDR)
    83  	d.SendCommand(SETYADDR)
    84  
    85  	for i := int16(0); i < d.bufferSize; i++ {
    86  		d.SendData(d.buffer[i])
    87  	}
    88  	return nil
    89  }
    90  
    91  // sendDataCommand sends image data or a command to the screen
    92  func (d *Device) sendDataCommand(isCommand bool, data uint8) {
    93  	if isCommand {
    94  		d.dcPin.Low()
    95  	} else {
    96  		d.dcPin.High()
    97  	}
    98  	d.scePin.Low()
    99  	d.bus.Transfer(data)
   100  	d.scePin.High()
   101  }
   102  
   103  // SetPixel enables or disables a pixel in the buffer
   104  // color.RGBA{0, 0, 0, 255} is consider transparent, anything else
   105  // with enable a pixel on the screen
   106  func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
   107  	if x < 0 || x >= d.width || y < 0 || y >= d.height {
   108  		return
   109  	}
   110  	byteIndex := x + (y/8)*d.width
   111  	if c.R != 0 || c.G != 0 || c.B != 0 {
   112  		d.buffer[byteIndex] |= 1 << uint8(y%8)
   113  	} else {
   114  		d.buffer[byteIndex] &^= 1 << uint8(y%8)
   115  	}
   116  }
   117  
   118  // GetPixel returns if the specified pixel is on (true) or off (false)
   119  func (d *Device) GetPixel(x int16, y int16) bool {
   120  	if x < 0 || x >= d.width || y < 0 || y >= d.height {
   121  		return false
   122  	}
   123  	byteIndex := x + (y/8)*d.width
   124  	return (d.buffer[byteIndex] >> uint8(y%8) & 0x1) == 1
   125  }
   126  
   127  // SetBuffer changes the whole buffer at once
   128  func (d *Device) SetBuffer(buffer []byte) error {
   129  	if int16(len(buffer)) != d.bufferSize {
   130  		//return ErrBuffer
   131  		return errors.New("wrong size buffer")
   132  	}
   133  	for i := int16(0); i < d.bufferSize; i++ {
   134  		d.buffer[i] = buffer[i]
   135  	}
   136  	return nil
   137  }
   138  
   139  // SendCommand sends a command to the display
   140  func (d *Device) SendCommand(command uint8) {
   141  	d.sendDataCommand(true, command)
   142  }
   143  
   144  // SendData sends a data byte to the display
   145  func (d *Device) SendData(data uint8) {
   146  	d.sendDataCommand(false, data)
   147  }
   148  
   149  // Size returns the current size of the display.
   150  func (d *Device) Size() (w, h int16) {
   151  	return d.width, d.height
   152  }