mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-19 22:23:58 +00:00
Add sharpmem (#724)
sharpmem: add implementation of sharpmem display driver * Implement Configure, Clear and ClearBuffer, add some tests, add documentation/comments * Reverse white * Inverted bits, fix and improve ClearBuffer, cleanup * Refine doc comment * Driver refactor, optimizations toggle, additional tests & support for all SKUs * Fix address overflow padding, add wire-level tests for assumed address encoding * Minor rename * Cleanup and doc fixes * Add device configs * Bounds check * Add example and smoketest entry * Use uf2 output file format * Refine example
This commit is contained in:
committed by
GitHub
parent
486949686c
commit
f57b5ecee9
@@ -0,0 +1,225 @@
|
||||
package sharpmem
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math/rand/v2"
|
||||
"testing"
|
||||
|
||||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func Test_setBit(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
v := uint8(1) << i
|
||||
|
||||
c.Assert(setBit(0x00, i), qt.Equals, v)
|
||||
c.Assert(setBit(0x00, (i+1)%8), qt.Not(qt.Equals), v)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_unsetBit(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
v := uint8(1) << i
|
||||
|
||||
c.Assert(unsetBit(v, i), qt.Equals, uint8(0x00))
|
||||
c.Assert(unsetBit(v, (i+1)%8), qt.Not(qt.Equals), uint8(0x00))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_hasBit(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
v := uint8(1) << i
|
||||
|
||||
c.Assert(hasBit(v, i), qt.Equals, true)
|
||||
c.Assert(hasBit(v, (i+1)%8), qt.Equals, false)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_bitfieldBufLen(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
for i := int16(1); i < 536; i++ {
|
||||
requiredBufferSize := i / 8
|
||||
wouldOverflow := i % 8
|
||||
|
||||
if wouldOverflow > 0 {
|
||||
requiredBufferSize += 1
|
||||
}
|
||||
|
||||
c.Assert(bitfieldBufLen(i), qt.Equals, requiredBufferSize)
|
||||
}
|
||||
}
|
||||
|
||||
type mockBus struct {
|
||||
b []byte
|
||||
}
|
||||
|
||||
func (m *mockBus) Tx(w, _ []byte) error {
|
||||
m.b = append(m.b, w...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockBus) Transfer(b byte) (byte, error) {
|
||||
m.b = append(m.b, b)
|
||||
return 0x00, nil
|
||||
}
|
||||
|
||||
type mockPin struct{}
|
||||
|
||||
func (m mockPin) High() {
|
||||
}
|
||||
|
||||
func (m mockPin) Low() {
|
||||
}
|
||||
|
||||
func Test_Device(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
cfgs := []Config{
|
||||
ConfigLS010B7DH04,
|
||||
ConfigLS011B7DH03,
|
||||
ConfigLS012B7DD01,
|
||||
ConfigLS013B7DH03,
|
||||
ConfigLS013B7DH05,
|
||||
ConfigLS018B7DH02,
|
||||
ConfigLS027B7DH01,
|
||||
ConfigLS027B7DH01A,
|
||||
ConfigLS032B7DD02,
|
||||
ConfigLS044Q7DH01,
|
||||
}
|
||||
|
||||
cfgLen := len(cfgs)
|
||||
for i := 0; i < cfgLen; i++ {
|
||||
cfgs = append(cfgs, Config{
|
||||
Width: cfgs[i].Width,
|
||||
Height: cfgs[i].Height,
|
||||
DisableOptimizations: true,
|
||||
})
|
||||
}
|
||||
|
||||
spi := &mockBus{}
|
||||
pin := mockPin{}
|
||||
display := New(spi, pin)
|
||||
|
||||
for _, cfg := range cfgs {
|
||||
display.Configure(cfg)
|
||||
|
||||
x, y := display.Size()
|
||||
c.Assert(x, qt.Equals, cfg.Width)
|
||||
c.Assert(y, qt.Equals, cfg.Height)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
x := int16(rand.IntN(int(cfg.Width)))
|
||||
y := int16(rand.IntN(int(cfg.Height)))
|
||||
display.SetPixel(x, y, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
x := int16(rand.IntN(int(cfg.Width)))
|
||||
y := int16(rand.IntN(int(cfg.Height)))
|
||||
display.SetPixel(x, y, color.RGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
}
|
||||
|
||||
err := display.Display()
|
||||
c.Assert(err, qt.Equals, nil)
|
||||
|
||||
err = display.ClearDisplay()
|
||||
c.Assert(err, qt.Equals, nil)
|
||||
|
||||
display.ClearBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_HiPad(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
spi := &mockBus{}
|
||||
pin := mockPin{}
|
||||
display := New(spi, pin)
|
||||
|
||||
t.Run("LS011B7DH03, 8-bit address", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
spi.b = nil
|
||||
})
|
||||
|
||||
display.Configure(ConfigLS011B7DH03)
|
||||
|
||||
display.SetPixel(0, display.height-1, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
||||
err := display.Display()
|
||||
c.Assert(err, qt.Equals, nil)
|
||||
|
||||
// 160 perfectly divisible by 16, so 20 bytes of pixel data
|
||||
c.Assert(spi.b, qt.HasLen, 2+20+2)
|
||||
|
||||
// line is 1-indexed on the wire (67+1)
|
||||
// 68 in binary
|
||||
// 0b01000100
|
||||
|
||||
// DDDDDMMM
|
||||
c.Assert(spi.b[0], qt.Equals, uint8(0b00000011)) // mode 1, vcom is high on first run
|
||||
|
||||
c.Assert(spi.b[1], qt.Equals, uint8(0b01000100)) // the actual address
|
||||
})
|
||||
|
||||
t.Run("LS018B7DH02, 9-bit address", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
spi.b = nil
|
||||
})
|
||||
|
||||
display.Configure(ConfigLS018B7DH02)
|
||||
|
||||
display.SetPixel(0, display.height-1, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
||||
err := display.Display()
|
||||
c.Assert(err, qt.Equals, nil)
|
||||
|
||||
// 2 first bytes command+address
|
||||
// 230 bits are not divisible by 16, 240 is (15*16), so 30 bytes for line data
|
||||
// 2 trailing bytes
|
||||
c.Assert(spi.b, qt.HasLen, 2+30+2)
|
||||
|
||||
// line is 1-indexed on the wire (302+1)
|
||||
// 303 in binary (split in 2 bytes)
|
||||
// R
|
||||
// 0b00000001 0b00101111
|
||||
// ^
|
||||
|
||||
// RDDDDMMM
|
||||
c.Assert(spi.b[0], qt.Equals, uint8(0b10000011)) // mode 1, vcom is high on first run
|
||||
// ^
|
||||
|
||||
c.Assert(spi.b[1], qt.Equals, uint8(0b00101111)) // rest of the address (low 8 bits)
|
||||
})
|
||||
|
||||
t.Run("LS032B7DD02, 10-bit address", func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
spi.b = nil
|
||||
})
|
||||
|
||||
display.Configure(ConfigLS032B7DD02)
|
||||
|
||||
display.SetPixel(0, display.height-1, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
||||
err := display.Display()
|
||||
c.Assert(err, qt.Equals, nil)
|
||||
|
||||
c.Assert(spi.b, qt.HasLen, 2+336/8+2) // 2 command+address, width / 2, 2 trailing bytes
|
||||
|
||||
// line is 1-indexed on the wire (535+1)
|
||||
// 536 in binary (split in 2 bytes)
|
||||
// RR
|
||||
// 0b00000010 0b00011000
|
||||
// ^^
|
||||
|
||||
// RRDDDMMM
|
||||
c.Assert(spi.b[0], qt.Equals, uint8(0b10000011)) // mode 1, vcom is high on first run
|
||||
// ^^
|
||||
|
||||
c.Assert(spi.b[1], qt.Equals, uint8(0b00011000)) // rest of the address (low 8 bits)
|
||||
})
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user