mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-16 21:03:23 +00:00
SSD1331 TFT color display (#77)
This commit is contained in:
committed by
Ron Evans
parent
4867abcbba
commit
bf077c8249
@@ -37,6 +37,7 @@ smoke-test:
|
|||||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/sht3x/main.go
|
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/sht3x/main.go
|
||||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/ssd1306/i2c_128x32/main.go
|
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/ssd1306/i2c_128x32/main.go
|
||||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/ssd1306/spi_128x64/main.go
|
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/ssd1306/spi_128x64/main.go
|
||||||
|
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/ssd1331/main.go
|
||||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/st7735/main.go
|
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/st7735/main.go
|
||||||
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/st7789/main.go
|
tinygo build -size short -o ./build/test.elf -target=microbit ./examples/st7789/main.go
|
||||||
tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/thermistor/main.go
|
tinygo build -size short -o ./build/test.elf -target=circuitplay-express ./examples/thermistor/main.go
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ func main() {
|
|||||||
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
|
| [PCD8544 display](http://eia.udg.edu/~forest/PCD8544_1.pdf) | SPI |
|
||||||
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
| [SHT3x Digital Humidity Sensor](https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/0_Datasheets/Humidity/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital.pdf) | I2C |
|
||||||
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
| [SSD1306 OLED display](https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf) | I2C / SPI |
|
||||||
|
| [SSD1331 TFT color display](https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/) | SPI |
|
||||||
| [ST7735 TFT color display](https://www.crystalfontz.com/controllers/Sitronix/ST7735R/319/) | SPI |
|
| [ST7735 TFT color display](https://www.crystalfontz.com/controllers/Sitronix/ST7735R/319/) | SPI |
|
||||||
| [ST7789 TFT color display](https://cdn-shop.adafruit.com/product-files/3787/3787_tft_QT154H2201__________20190228182902.pdf) | SPI |
|
| [ST7789 TFT color display](https://cdn-shop.adafruit.com/product-files/3787/3787_tft_QT154H2201__________20190228182902.pdf) | SPI |
|
||||||
| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC |
|
| [Thermistor](https://www.farnell.com/datasheets/33552.pdf) | ADC |
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package ssd1331
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"image/color"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/ssd1331"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
machine.SPI0.Configure(machine.SPIConfig{
|
||||||
|
Frequency: 8000000,
|
||||||
|
})
|
||||||
|
display := ssd1331.New(machine.SPI0, machine.P6, machine.P7, machine.P8)
|
||||||
|
display.Configure(ssd1331.Config{})
|
||||||
|
display.SetContrast(0x30, 0x20, 0x30)
|
||||||
|
width, height := display.Size()
|
||||||
|
|
||||||
|
white := color.RGBA{255, 255, 255, 255}
|
||||||
|
red := color.RGBA{255, 0, 0, 255}
|
||||||
|
blue := color.RGBA{0, 0, 255, 255}
|
||||||
|
green := color.RGBA{0, 255, 0, 255}
|
||||||
|
black := color.RGBA{0, 0, 0, 255}
|
||||||
|
|
||||||
|
display.FillScreen(black)
|
||||||
|
|
||||||
|
display.FillRectangle(0, 0, width/2, height/2, white)
|
||||||
|
display.FillRectangle(width/2, 0, width/2, height/2, red)
|
||||||
|
display.FillRectangle(0, height/2, width/2, height/2, green)
|
||||||
|
display.FillRectangle(width/2, height/2, width/2, height/2, blue)
|
||||||
|
display.FillRectangle(width/4, height/4, width/2, height/2, black)
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package ssd1331
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
const (
|
||||||
|
DRAWLINE = 0x21
|
||||||
|
DRAWRECT = 0x22
|
||||||
|
FILL = 0x26
|
||||||
|
SETCOLUMN = 0x15
|
||||||
|
SETROW = 0x75
|
||||||
|
CONTRASTA = 0x81
|
||||||
|
CONTRASTB = 0x82
|
||||||
|
CONTRASTC = 0x83
|
||||||
|
MASTERCURRENT = 0x87
|
||||||
|
SETREMAP = 0xA0
|
||||||
|
STARTLINE = 0xA1
|
||||||
|
DISPLAYOFFSET = 0xA2
|
||||||
|
NORMALDISPLAY = 0xA4
|
||||||
|
DISPLAYALLON = 0xA5
|
||||||
|
DISPLAYALLOFF = 0xA6
|
||||||
|
INVERTDISPLAY = 0xA7
|
||||||
|
SETMULTIPLEX = 0xA8
|
||||||
|
SETMASTER = 0xAD
|
||||||
|
DISPLAYOFF = 0xAE
|
||||||
|
DISPLAYON = 0xAF
|
||||||
|
POWERMODE = 0xB0
|
||||||
|
PRECHARGE = 0xB1
|
||||||
|
CLOCKDIV = 0xB3
|
||||||
|
PRECHARGEA = 0x8A
|
||||||
|
PRECHARGEB = 0x8B
|
||||||
|
PRECHARGEC = 0x8C
|
||||||
|
PRECHARGELEVEL = 0xBB
|
||||||
|
VCOMH = 0xBE
|
||||||
|
)
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
// Package ssd1331 implements a driver for the SSD1331 TFT color displays.
|
||||||
|
//
|
||||||
|
// Datasheet: https://www.crystalfontz.com/controllers/SolomonSystech/SSD1331/381/
|
||||||
|
//
|
||||||
|
package ssd1331 // import "tinygo.org/x/drivers/ssd1331"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"machine"
|
||||||
|
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Model uint8
|
||||||
|
type Rotation uint8
|
||||||
|
|
||||||
|
// Device wraps an SPI connection.
|
||||||
|
type Device struct {
|
||||||
|
bus machine.SPI
|
||||||
|
dcPin machine.Pin
|
||||||
|
resetPin machine.Pin
|
||||||
|
csPin machine.Pin
|
||||||
|
width int16
|
||||||
|
height int16
|
||||||
|
batchLength int16
|
||||||
|
isBGR bool
|
||||||
|
batchData []uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the configuration for the display
|
||||||
|
type Config struct {
|
||||||
|
Width int16
|
||||||
|
Height int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new ST7735 connection. The SPI wire must already be configured.
|
||||||
|
func New(bus machine.SPI, resetPin, dcPin, csPin machine.Pin) Device {
|
||||||
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
return Device{
|
||||||
|
bus: bus,
|
||||||
|
dcPin: dcPin,
|
||||||
|
resetPin: resetPin,
|
||||||
|
csPin: csPin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure initializes the display with default configuration
|
||||||
|
func (d *Device) Configure(cfg Config) {
|
||||||
|
if cfg.Width != 0 {
|
||||||
|
d.width = cfg.Width
|
||||||
|
} else {
|
||||||
|
d.width = 96
|
||||||
|
}
|
||||||
|
if cfg.Height != 0 {
|
||||||
|
d.height = cfg.Height
|
||||||
|
} else {
|
||||||
|
d.height = 64
|
||||||
|
}
|
||||||
|
|
||||||
|
d.batchLength = d.width
|
||||||
|
if d.height > d.width {
|
||||||
|
d.batchLength = d.height
|
||||||
|
}
|
||||||
|
d.batchLength += d.batchLength & 1
|
||||||
|
d.batchData = make([]uint8, d.batchLength*2)
|
||||||
|
|
||||||
|
// reset the device
|
||||||
|
d.resetPin.High()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
d.resetPin.Low()
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
d.resetPin.High()
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
d.Command(DISPLAYOFF)
|
||||||
|
d.Command(SETREMAP)
|
||||||
|
d.Command(0x72) // RGB
|
||||||
|
//d.Command(0x76) // BGR
|
||||||
|
d.Command(STARTLINE)
|
||||||
|
d.Command(0x0)
|
||||||
|
d.Command(DISPLAYOFFSET)
|
||||||
|
d.Command(0x0)
|
||||||
|
d.Command(NORMALDISPLAY)
|
||||||
|
d.Command(SETMULTIPLEX)
|
||||||
|
d.Command(0x3F)
|
||||||
|
d.Command(SETMASTER)
|
||||||
|
d.Command(0x8E)
|
||||||
|
d.Command(POWERMODE)
|
||||||
|
d.Command(0x0B)
|
||||||
|
d.Command(PRECHARGE)
|
||||||
|
d.Command(0x31)
|
||||||
|
d.Command(CLOCKDIV)
|
||||||
|
d.Command(0xF0)
|
||||||
|
d.Command(PRECHARGEA)
|
||||||
|
d.Command(0x64)
|
||||||
|
d.Command(PRECHARGEB)
|
||||||
|
d.Command(0x78)
|
||||||
|
d.Command(PRECHARGEC)
|
||||||
|
d.Command(0x64)
|
||||||
|
d.Command(PRECHARGELEVEL)
|
||||||
|
d.Command(0x3A)
|
||||||
|
d.Command(VCOMH)
|
||||||
|
d.Command(0x3E)
|
||||||
|
d.Command(MASTERCURRENT)
|
||||||
|
d.Command(0x06)
|
||||||
|
d.Command(CONTRASTA)
|
||||||
|
d.Command(0x91)
|
||||||
|
d.Command(CONTRASTB)
|
||||||
|
d.Command(0x50)
|
||||||
|
d.Command(CONTRASTC)
|
||||||
|
d.Command(0x7D)
|
||||||
|
d.Command(DISPLAYON)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display does nothing, there's no buffer as it might be too big for some boards
|
||||||
|
func (d *Device) Display() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPixel sets a pixel in the screen
|
||||||
|
func (d *Device) SetPixel(x int16, y int16, c color.RGBA) {
|
||||||
|
if x < 0 || y < 0 || x >= d.width || y >= d.height {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.FillRectangle(x, y, 1, 1, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setWindow prepares the screen to be modified at a given rectangle
|
||||||
|
func (d *Device) setWindow(x, y, w, h int16) {
|
||||||
|
/*d.Tx([]uint8{SETCOLUMN}, true)
|
||||||
|
d.Tx([]uint8{uint8(x), uint8(x + w - 1)}, false)
|
||||||
|
d.Tx([]uint8{SETROW}, true)
|
||||||
|
d.Tx([]uint8{uint8(y), uint8(y + h - 1)}, false)*/
|
||||||
|
d.Command(SETCOLUMN)
|
||||||
|
d.Command(uint8(x))
|
||||||
|
d.Command(uint8(x + w - 1))
|
||||||
|
d.Command(SETROW)
|
||||||
|
d.Command(uint8(y))
|
||||||
|
d.Command(uint8(y + h - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillRectangle fills a rectangle at a given coordinates with a color
|
||||||
|
func (d *Device) FillRectangle(x, y, width, height int16, c color.RGBA) error {
|
||||||
|
if x < 0 || y < 0 || width <= 0 || height <= 0 ||
|
||||||
|
x >= d.width || (x+width) > d.width || y >= d.height || (y+height) > d.height {
|
||||||
|
return errors.New("rectangle coordinates outside display area")
|
||||||
|
}
|
||||||
|
d.setWindow(x, y, width, height)
|
||||||
|
c565 := RGBATo565(c)
|
||||||
|
c1 := uint8(c565 >> 8)
|
||||||
|
c2 := uint8(c565)
|
||||||
|
|
||||||
|
var i int16
|
||||||
|
for i = 0; i < d.batchLength; i++ {
|
||||||
|
d.batchData[i*2] = c1
|
||||||
|
d.batchData[i*2+1] = c2
|
||||||
|
}
|
||||||
|
i = width * height
|
||||||
|
for i > 0 {
|
||||||
|
if i >= d.batchLength {
|
||||||
|
d.Tx(d.batchData, false)
|
||||||
|
} else {
|
||||||
|
d.Tx(d.batchData[:i*2], false)
|
||||||
|
}
|
||||||
|
i -= d.batchLength
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillRectangle fills a rectangle at a given coordinates with a buffer
|
||||||
|
func (d *Device) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
||||||
|
if x < 0 || y < 0 || width <= 0 || height <= 0 ||
|
||||||
|
x >= d.width || (x+width) > d.width || y >= d.height || (y+height) > d.height {
|
||||||
|
return errors.New("rectangle coordinates outside display area")
|
||||||
|
}
|
||||||
|
k := width * height
|
||||||
|
l := int16(len(buffer))
|
||||||
|
if k != l {
|
||||||
|
return errors.New("buffer length does not match with rectangle size")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.setWindow(x, y, width, height)
|
||||||
|
|
||||||
|
offset := int16(0)
|
||||||
|
for k > 0 {
|
||||||
|
for i := int16(0); i < d.batchLength; i++ {
|
||||||
|
if offset+i < l {
|
||||||
|
c565 := RGBATo565(buffer[offset+i])
|
||||||
|
c1 := uint8(c565 >> 8)
|
||||||
|
c2 := uint8(c565)
|
||||||
|
d.batchData[i*2] = c1
|
||||||
|
d.batchData[i*2+1] = c2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k >= d.batchLength {
|
||||||
|
d.Tx(d.batchData, false)
|
||||||
|
} else {
|
||||||
|
d.Tx(d.batchData[:k*2], false)
|
||||||
|
}
|
||||||
|
k -= d.batchLength
|
||||||
|
offset += d.batchLength
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawFastVLine draws a vertical line faster than using SetPixel
|
||||||
|
func (d *Device) DrawFastVLine(x, y0, y1 int16, c color.RGBA) {
|
||||||
|
if y0 > y1 {
|
||||||
|
y0, y1 = y1, y0
|
||||||
|
}
|
||||||
|
d.FillRectangle(x, y0, 1, y1-y0+1, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawFastHLine draws a horizontal line faster than using SetPixel
|
||||||
|
func (d *Device) DrawFastHLine(x0, x1, y int16, c color.RGBA) {
|
||||||
|
if x0 > x1 {
|
||||||
|
x0, x1 = x1, x0
|
||||||
|
}
|
||||||
|
d.FillRectangle(x0, y, x1-x0+1, y, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillScreen fills the screen with a given color
|
||||||
|
func (d *Device) FillScreen(c color.RGBA) {
|
||||||
|
d.FillRectangle(0, 0, d.width, d.height, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContrast sets the three contrast values (A, B & C)
|
||||||
|
func (d *Device) SetContrast(contrastA, contrastB, contrastC uint8) {
|
||||||
|
d.Command(CONTRASTA)
|
||||||
|
d.Command(contrastA)
|
||||||
|
d.Command(CONTRASTB)
|
||||||
|
d.Command(contrastB)
|
||||||
|
d.Command(CONTRASTC)
|
||||||
|
d.Command(contrastC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command sends a command to the display
|
||||||
|
func (d *Device) Command(command uint8) {
|
||||||
|
d.Tx([]byte{command}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command sends a data to the display
|
||||||
|
func (d *Device) Data(data uint8) {
|
||||||
|
d.Tx([]byte{data}, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tx sends data to the display
|
||||||
|
func (d *Device) Tx(data []byte, isCommand bool) {
|
||||||
|
if isCommand {
|
||||||
|
d.csPin.High()
|
||||||
|
d.dcPin.Low()
|
||||||
|
d.csPin.Low()
|
||||||
|
|
||||||
|
d.bus.Tx(data, nil)
|
||||||
|
d.csPin.High()
|
||||||
|
} else {
|
||||||
|
d.csPin.High()
|
||||||
|
d.dcPin.High()
|
||||||
|
d.csPin.Low()
|
||||||
|
|
||||||
|
d.bus.Tx(data, nil)
|
||||||
|
d.csPin.High()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the current size of the display.
|
||||||
|
func (d *Device) Size() (w, h int16) {
|
||||||
|
return d.width, d.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBGR changes the color mode (RGB/BGR)
|
||||||
|
func (d *Device) IsBGR(bgr bool) {
|
||||||
|
d.isBGR = bgr
|
||||||
|
}
|
||||||
|
|
||||||
|
// RGBATo565 converts a color.RGBA to uint16 used in the display
|
||||||
|
func RGBATo565(c color.RGBA) uint16 {
|
||||||
|
r, g, b, _ := c.RGBA()
|
||||||
|
return uint16((r & 0xF800) +
|
||||||
|
((g & 0xFC00) >> 5) +
|
||||||
|
((b & 0xF800) >> 11))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user