diff --git a/.circleci/config.yml b/.circleci/config.yml index f2412db..d6a72e1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,6 +28,8 @@ jobs: - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mag3110/main.go - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mma8653/main.go - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mpu6050/main.go + - run: tinygo build -size short -o test.elf -target=microbit ./examples/pcd8544/setbuffer/main.go + - run: tinygo build -size short -o test.elf -target=microbit ./examples/pcd8544/setpixel/main.go - run: tinygo build -size short -o test.elf -target=circuitplay-express ./examples/thermistor/main.go - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/vl53l1x/main.go - run: tinygo build -size short -o test.elf -target=circuitplay-express ./examples/ws2812/main.go diff --git a/README.md b/README.md index cb10145..9cd8813 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ func main() { | [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C | | [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C | | [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C | +| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI | | [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC | | [VL53L1X time-of-flight distance sensor](https://www.st.com/resource/en/datasheet/vl53l1x.pdf) | I2C | | [WS2812 RGB LED](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) | GPIO | diff --git a/examples/pcd8544/setbuffer/data/data.go b/examples/pcd8544/setbuffer/data/data.go new file mode 100644 index 0000000..1f7381f --- /dev/null +++ b/examples/pcd8544/setbuffer/data/data.go @@ -0,0 +1,57 @@ +package data + +// example images +var Images = [2][]byte{ + {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, 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x60, 0x60, 0x60, 0x60, 0xe0, 0x60, 0x30, 0x18, 0x98, + 0x70, 0x70, 0x60, 0x60, 0x60, 0xe0, 0x10, 0x08, 0x08, 0x04, 0x02, 0x02, 0xf2, 0xf2, 0x72, 0x72, 0x72, 0x04, 0x08, 0x10, + 0x60, 0x80, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x20, + 0x20, 0x20, 0xe0, 0x18, 0x1c, 0x07, 0x07, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x87, 0x18, 0x60, 0x80, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x00, 0x80, 0x40, 0x38, 0x07, 0x03, 0x07, 0x47, 0x47, 0x07, 0x9f, 0x87, 0xfc, 0x78, 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, 0x00, 0x01, 0x02, 0x02, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x3f, 0x20, 0x30, 0x0f, 0x0b, 0x80, 0x40, 0x41, 0x41, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf9, 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, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x00, 0x00, 0xf8, 0x06, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x01, 0x00, 0x06, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x71, + 0x60, 0xc0, 0x80, 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, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x1b, 0x20, 0x60, 0xc0, 0x80, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x05, 0x84, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x1c, 0x10, 0x10, 0x20, 0x40, 0x40, 0x40, 0x47, 0x47, 0x44, 0x44, 0x44, 0x20, 0x20, 0x98, 0x84, 0xc3, 0x60, 0x20, + 0x1c, 0x1c, 0x1b, 0x1b, 0x18, 0x18, 0x1f, 0x07, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x3f, 0x3f, 0x3f, 0x1b, 0x03, 0x03, 0x01, 0x01, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x03, 0x01, + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, 0x7e, 0x63, 0x63, 0xc1, 0x01, 0x81, 0x63, 0x23, 0x26, 0x3c, + 0x20, 0x20, 0x20, 0xa0, 0x60, 0x10, 0x08, 0x08, 0x04, 0x02, 0xe2, 0xe2, 0xe2, 0x62, 0xe4, 0xec, 0x10, 0x20, 0x60, 0x80, + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, + 0x20, 0x20, 0x20, 0xf8, 0x38, 0x06, 0x06, 0x03, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1c, 0x60, 0x80, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x01, 0x01, + 0x00, 0x80, 0x60, 0x1f, 0x03, 0x06, 0x0c, 0x16, 0x16, 0x16, 0x06, 0x06, 0xf8, 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, 0x00, + 0x00, 0x01, 0x03, 0x02, 0xfe, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x3f, 0x21, 0x1f, 0x0a, 0x80, 0x40, 0x41, 0x42, 0x42, 0x22, 0x22, + 0x22, 0x42, 0x42, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0xfd, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x7f, 0x7f, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x1e, 0x61, 0x81, 0x01, 0x01, 0x82, 0x42, 0x24, 0x18, 0x00, 0xf8, 0x06, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x01, 0x02, 0x9c, 0x60, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x30, 0x20, 0x20, + 0xc0, 0x80, 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, 0x00, 0x03, 0x04, 0x08, 0x08, 0x08, 0x08, 0x38, 0x3f, 0xc0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x0c, 0x10, 0x20, 0x20, 0x40, 0x40, 0x43, 0x47, 0x47, 0x24, 0x23, 0x23, 0x18, 0x84, 0x83, 0xc0, 0x60, 0x30, 0x18, 0x18, + 0x18, 0x19, 0x1a, 0x1a, 0x0f, 0x07, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x06, 0x06, 0x1c, 0x1c, 0x7e, 0x7e, 0x7e, 0x36, 0x06, 0x06, 0x02, 0x02, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 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}, +} diff --git a/examples/pcd8544/setbuffer/main.go b/examples/pcd8544/setbuffer/main.go new file mode 100644 index 0000000..338bea0 --- /dev/null +++ b/examples/pcd8544/setbuffer/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "machine" + "time" + + "github.com/tinygo-org/drivers/examples/pcd8544/setbuffer/data" + "github.com/tinygo-org/drivers/pcd8544" +) + +func main() { + dcPin := machine.GPIO{machine.P3} + dcPin.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT}) + rstPin := machine.GPIO{machine.P4} + rstPin.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT}) + scePin := machine.GPIO{machine.P5} + scePin.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT}) + + machine.SPI0.Configure(machine.SPIConfig{}) + + lcd := pcd8544.New(machine.SPI0, dcPin, rstPin, scePin) + lcd.Configure(pcd8544.Config{}) + + i := 0 + for { + err := lcd.SetBuffer(data.Images[i]) + if err != nil { + println(err.Error()) + } + lcd.Display() + i = (i + 1) % 2 + + time.Sleep(800 * time.Millisecond) + } +} diff --git a/examples/pcd8544/setpixel/main.go b/examples/pcd8544/setpixel/main.go new file mode 100644 index 0000000..09d9736 --- /dev/null +++ b/examples/pcd8544/setpixel/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "image/color" + "machine" + "time" + + "github.com/tinygo-org/drivers/pcd8544" +) + +func main() { + dcPin := machine.GPIO{machine.P3} + dcPin.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT}) + rstPin := machine.GPIO{machine.P4} + rstPin.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT}) + scePin := machine.GPIO{machine.P5} + scePin.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT}) + + machine.SPI0.Configure(machine.SPIConfig{}) + + lcd := pcd8544.New(machine.SPI0, dcPin, rstPin, scePin) + lcd.Configure(pcd8544.Config{}) + + var x int16 + var y int16 + deltaX := int16(1) + deltaY := int16(1) + for { + pixel := lcd.GetPixel(x, y) + c := color.RGBA{255, 255, 255, 255} + if pixel { + c = color.RGBA{0, 0, 0, 255} + } + lcd.SetPixel(x, y, c) + lcd.Display() + + x += deltaX + y += deltaY + + if x == 0 || x == 83 { + deltaX = -deltaX + } + + if y == 0 || y == 47 { + deltaY = -deltaY + } + time.Sleep(1 * time.Millisecond) + } +} diff --git a/pcd8544/pcd8544.go b/pcd8544/pcd8544.go new file mode 100644 index 0000000..8b54f08 --- /dev/null +++ b/pcd8544/pcd8544.go @@ -0,0 +1,150 @@ +// Package pcd8544 implements a driver for the PCD8544 48x84 pixels matrix LCD, used in Nokia's 5110 and 3310 phones. +// +// Datasheet: http://eia.udg.edu/~forest/PCD8544_1.pdf +package pcd8544 + +import ( + "errors" + "image/color" + "machine" + "time" +) + +// Device wraps an SPI connection. +type Device struct { + bus machine.SPI + dcPin machine.GPIO + rstPin machine.GPIO + scePin machine.GPIO + buffer []byte + width int16 + height int16 + bufferSize int16 +} + +type Config struct { + Width int16 + Height int16 +} + +// New creates a new PCD8544 connection. The SPI bus must already be configured. +func New(bus machine.SPI, dcPin machine.GPIO, rstPin machine.GPIO, scePin machine.GPIO) *Device { + return &Device{ + bus: bus, + dcPin: dcPin, + rstPin: rstPin, + scePin: scePin, + } +} + +// Configure initializes the display with default configuration +func (d *Device) Configure(cfg Config) { + if cfg.Width != 0 { + d.width = cfg.Width + } else { + d.width = 84 + } + if cfg.Height != 0 { + d.height = cfg.Height + } else { + d.height = 48 + } + d.bufferSize = d.width * d.height / 8 + d.buffer = make([]byte, d.bufferSize) + + d.rstPin.Low() + time.Sleep(100 * time.Nanosecond) + d.rstPin.High() + d.SendCommand(FUNCTIONSET | EXTENDEDINSTRUCTION) // H = 1 + d.SendCommand(SETVOP | 0x3f) // 0x3f : Vop6 = 0, Vop5 to Vop0 = 1 + d.SendCommand(SETTEMP | 0x03) // Experimentally determined + d.SendCommand(SETBIAS | 0x03) // Experimentally determined + d.SendCommand(FUNCTIONSET) // H = 0 + d.SendCommand(DISPLAYCONTROL | DISPLAYNORMAL) +} + +// ClearBuffer clears the image buffer +func (d *Device) ClearBuffer() { + d.buffer = make([]byte, d.bufferSize) +} + +// ClearDisplay clears the image buffer and clear the display +func (d *Device) ClearDisplay() { + d.ClearBuffer() + d.Display() +} + +// Display sends the whole buffer to the screen +func (d *Device) Display() error { + d.SendCommand(FUNCTIONSET) // H = 0 + d.SendCommand(SETXADDR) + d.SendCommand(SETYADDR) + + for i := int16(0); i < d.bufferSize; i++ { + d.SendData(d.buffer[i]) + } + return nil +} + +// sendDataCommand sends image data or a command to the screen +func (d *Device) sendDataCommand(isCommand bool, data uint8) { + if isCommand { + d.dcPin.Low() + } else { + d.dcPin.High() + } + d.scePin.Low() + d.bus.Transfer(data) + d.scePin.High() +} + +// SetPixel enables or disables a pixel in the buffer +// color.RGBA{0, 0, 0, 255} is consider transparent, anything else +// with enable a pixel on the screen +func (d *Device) SetPixel(x int16, y int16, c color.RGBA) { + if x < 0 || x >= d.width || y < 0 || y >= d.height { + return + } + byteIndex := x + (y/8)*d.width + if c.R != 0 || c.G != 0 || c.B != 0 { + d.buffer[byteIndex] |= 1 << uint8(y%8) + } else { + d.buffer[byteIndex] &^= 1 << uint8(y%8) + } +} + +// GetPixel returns if the specified pixel is on (true) or off (false) +func (d *Device) GetPixel(x int16, y int16) bool { + if x < 0 || x >= d.width || y < 0 || y >= d.height { + return false + } + byteIndex := x + (y/8)*d.width + return (d.buffer[byteIndex] >> uint8(y%8) & 0x1) == 1 +} + +// SetBuffer changes the whole buffer at once +func (d *Device) SetBuffer(buffer []byte) error { + if int16(len(buffer)) != d.bufferSize { + //return ErrBuffer + return errors.New("Wrong size buffer") + } + for i := int16(0); i < d.bufferSize; i++ { + d.buffer[i] = buffer[i] + } + return nil +} + +// SendCommand sends a command to the display +func (d *Device) SendCommand(command uint8) { + d.sendDataCommand(true, command) +} + +// SendData sends a data byte to the display +func (d *Device) SendData(data uint8) { + d.sendDataCommand(false, data) +} + +// Size returns the current size of the display. +func (d *Device) Size() (w, h int16) { + return d.width, d.height +} diff --git a/pcd8544/registers.go b/pcd8544/registers.go new file mode 100644 index 0000000..b8ab7e3 --- /dev/null +++ b/pcd8544/registers.go @@ -0,0 +1,21 @@ +package pcd8544 + +// Registers +const ( + POWERDOWN = 0x04 + ENTRYMODE = 0x02 + EXTENDEDINSTRUCTION = 0x01 + FUNCTIONSET = 0x20 + + DISPLAYCONTROL = 0x08 + DISPLAYBLANK = 0x0 + DISPLAYNORMAL = 0x04 + DISPLAYALLON = 0x01 + DISPLAYINVERTED = 0x05 + + SETYADDR = 0x40 + SETXADDR = 0x80 + SETTEMP = 0x04 + SETBIAS = 0x10 + SETVOP = 0x80 +)