Made column differential work for SSD1306 (#444)

pull/1/head
Denis Luchkin-Zhou 6 years ago committed by GitHub
parent 0fbde4244b
commit 8fe00338c0

@ -25,6 +25,36 @@ import (
"periph.io/x/periph/devices/ssd1306/image1bit"
)
const (
_CHARGEPUMP = 0x8D
_COLUMNADDR = 0x21
_COMSCANDEC = 0xC8
_COMSCANINC = 0xC0
_DISPLAYALLON = 0xA5
_DISPLAYALLON_RESUME = 0xA4
_DISPLAYOFF = 0xAE
_DISPLAYON = 0xAF
_EXTERNALVCC = 0x1
_INVERTDISPLAY = 0xA7
_MEMORYMODE = 0x20
_NORMALDISPLAY = 0xA6
_PAGEADDR = 0x22
_PAGESTARTADDRESS = 0xB0
_SEGREMAP = 0xA0
_SETCOMPINS = 0xDA
_SETCONTRAST = 0x81
_SETDISPLAYCLOCKDIV = 0xD5
_SETDISPLAYOFFSET = 0xD3
_SETHIGHCOLUMN = 0x10
_SETLOWCOLUMN = 0x00
_SETMULTIPLEX = 0xA8
_SETPRECHARGE = 0xD9
_SETSEGMENTREMAP = 0xA1
_SETSTARTLINE = 0x40
_SETVCOMDETECT = 0xDB
_SWITCHCAPVCC = 0x2
)
// FrameRate determines scrolling speed.
type FrameRate byte
@ -387,30 +417,28 @@ func (d *Dev) calculateSubset(next []byte) (int, int, int, int, bool) {
// Early exit, the image is exactly the same.
return 0, 0, 0, 0, true
}
// TODO(maruel): This currently corrupts the screen. Likely a small error
// in the way the commands are sent.
/*
// Left.
for ; startCol < endCol; startCol++ {
for i := startPage; i < endPage; i++ {
x := i*pageSize + startCol
if d.buffer[x] != next[x] {
goto breakLeft
}
}
// Left.
for ; startCol < endCol; startCol++ {
for i := startPage; i < endPage; i++ {
x := i*pageSize + startCol
if d.buffer[x] != next[x] {
goto breakLeft
}
breakLeft:
// Right.
for ; endCol > startCol; endCol-- {
for i := startPage; i < endPage; i++ {
x := i*pageSize + endCol - 1
if d.buffer[x] != next[x] {
goto breakRight
}
}
}
}
breakLeft:
// Right.
for ; endCol > startCol; endCol-- {
for i := startPage; i < endPage; i++ {
x := i*pageSize + endCol - 1
if d.buffer[x] != next[x] {
goto breakRight
}
breakRight:
*/
}
}
breakRight:
}
return startPage, endPage, startCol, endCol, false
}
@ -428,18 +456,25 @@ func (d *Dev) drawInternal(next []byte) error {
d.endPage = endPage
d.startCol = startCol
d.endCol = endCol
cmd := []byte{
0x21, uint8(d.startCol), uint8(d.endCol - 1), // Set column address (Width)
0x22, uint8(d.startPage), uint8(d.endPage - 1), // Set page address (Pages)
}
pageSize := d.rect.Dx()
for page := d.startPage; page < d.endPage; page++ {
err := d.sendCommand([]byte{
_PAGESTARTADDRESS | byte(page),
_SETLOWCOLUMN | (byte(d.startCol) & 0x0F),
_SETHIGHCOLUMN | (byte(d.startCol) >> 4),
})
if err != nil {
return err
}
if err := d.sendCommand(cmd); err != nil {
pageStart := page * pageSize
err = d.sendData(d.buffer[pageStart+d.startCol : pageStart+d.endCol])
if err != nil {
return err
}
}
// Write the subset of the data as needed.
pageSize := d.rect.Dx()
return d.sendData(d.buffer[startPage*pageSize+startCol : (endPage-1)*pageSize+endCol])
return nil
}
func (d *Dev) sendData(c []byte) error {

@ -68,15 +68,42 @@ func TestI2C_String(t *testing.T) {
func TestI2C_Draw_VerticalLSD_fast(t *testing.T) {
// Exercise the fast path.
buf := make([]byte, 1025)
buf := make([]byte, 129)
buf[0] = i2cData
buf[23] = 1
emptyBuf := make([]byte, 129)
emptyBuf[0] = i2cData
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Startup initialization.
{Addr: 0x3c, W: initCmdI2C()},
// Actual draw buffer.
// Page 1
{Addr: 0x3c, W: []byte{0x00, 0xB0, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 2
{Addr: 0x3c, W: []byte{0x00, 0xB1, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 3
{Addr: 0x3c, W: []byte{0x00, 0xB2, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 4
{Addr: 0x3c, W: []byte{0x00, 0xB3, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 5
{Addr: 0x3c, W: []byte{0x00, 0xB4, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 6
{Addr: 0x3c, W: []byte{0x00, 0xB5, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 7
{Addr: 0x3c, W: []byte{0x00, 0xB6, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 8
{Addr: 0x3c, W: []byte{0x00, 0xB7, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
},
}
dev, err := NewI2C(&bus, &DefaultOpts)
@ -95,19 +122,43 @@ func TestI2C_Draw_VerticalLSD_fast(t *testing.T) {
func TestI2C_Halt_Write(t *testing.T) {
// Exercise the fast path.
buf := make([]byte, 1025)
buf := make([]byte, 129)
buf[0] = i2cData
buf[23] = 1
emptyBuf := make([]byte, 129)
emptyBuf[0] = i2cData
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Startup initialization.
{Addr: 0x3c, W: initCmdI2C()},
// Halt()
{Addr: 0x3c, W: []byte{0x0, 0xae}},
// transparent resume
{Addr: 0x3c, W: []byte{0x0, 0xaf}},
// Actual draw buffer.
// transparent resume & page 1 setup
{Addr: 0x3c, W: []byte{0x0, 0xaf, 0xB0, 0x00, 0x10}},
// Page 1
{Addr: 0x3c, W: buf},
// Page 2
{Addr: 0x3c, W: []byte{0x00, 0xB1, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 3
{Addr: 0x3c, W: []byte{0x00, 0xB2, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 4
{Addr: 0x3c, W: []byte{0x00, 0xB3, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 5
{Addr: 0x3c, W: []byte{0x00, 0xB4, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 6
{Addr: 0x3c, W: []byte{0x00, 0xB5, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 7
{Addr: 0x3c, W: []byte{0x00, 0xB6, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
// Page 8
{Addr: 0x3c, W: []byte{0x00, 0xB7, 0x00, 0x10}},
{Addr: 0x3c, W: emptyBuf},
},
}
dev, err := NewI2C(&bus, &DefaultOpts)
@ -212,12 +263,36 @@ func TestI2C_Draw_fail(t *testing.T) {
}
func TestI2C_DrawGray(t *testing.T) {
buf := append([]byte{i2cData}, grayCheckboard()...)
bus := i2ctest.Playback{
Ops: []i2ctest.IO{
// Startup initialization.
{Addr: 0x3c, W: initCmdI2C()},
// Actual draw buffer.
{Addr: 0x3c, W: append([]byte{i2cData}, grayCheckboard()...)},
// Page 1
{Addr: 0x3c, W: []byte{0x00, 0xB0, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 2
{Addr: 0x3c, W: []byte{0x00, 0xB1, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 3
{Addr: 0x3c, W: []byte{0x00, 0xB2, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 4
{Addr: 0x3c, W: []byte{0x00, 0xB3, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 5
{Addr: 0x3c, W: []byte{0x00, 0xB4, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 6
{Addr: 0x3c, W: []byte{0x00, 0xB5, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 7
{Addr: 0x3c, W: []byte{0x00, 0xB6, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
// Page 8
{Addr: 0x3c, W: []byte{0x00, 0xB7, 0x00, 0x10}},
{Addr: 0x3c, W: buf},
},
}
dev, err := NewI2C(&bus, &DefaultOpts)
@ -402,8 +477,8 @@ func TestSPI_4wire_String(t *testing.T) {
}
func TestSPI_4wire_Write_differential(t *testing.T) {
buf1 := make([]byte, 1024)
buf1[130] = 1
buf1 := make([]byte, 128)
buf1[29] = 1
buf2 := make([]byte, 128)
buf2[130-128] = 1
buf2[131-128] = 2
@ -411,10 +486,35 @@ func TestSPI_4wire_Write_differential(t *testing.T) {
Playback: conntest.Playback{
Ops: []conntest.IO{
{W: getInitCmd(&Opts{W: 128, H: 64, Rotated: false})},
// Page 1
{W: []byte{0xB0, 0x00, 0x10}},
{W: buf1},
// Reset to write only to the first page.
{W: []byte{0x21, 0x0, 0x7f, 0x22, 0x1, 0x1}},
{W: buf2},
// Page 2
{W: []byte{0xB1, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 3
{W: []byte{0xB2, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 4
{W: []byte{0xB3, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 5
{W: []byte{0xB4, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 6
{W: []byte{0xB5, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 7
{W: []byte{0xB6, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 8
{W: []byte{0xB7, 0x00, 0x10}},
{W: make([]byte, 128)},
// Only write to column 3 of page 1
{W: []byte{0xB1, 0x03, 0x10}},
{W: []byte{0x02}},
},
},
}
@ -423,7 +523,7 @@ func TestSPI_4wire_Write_differential(t *testing.T) {
t.Fatal(err)
}
pix := make([]byte, 1024)
pix[130] = 1
pix[29] = 1
if n, err := dev.Write(pix); n != len(pix) || err != nil {
t.Fatal(n, err)
}
@ -437,13 +537,36 @@ func TestSPI_4wire_Write_differential(t *testing.T) {
}
func TestSPI_4wire_Write_differential_fail(t *testing.T) {
buf1 := make([]byte, 1024)
buf1[130] = 1
buf1 := make([]byte, 128)
buf1[29] = 1
port := spitest.Playback{
Playback: conntest.Playback{
Ops: []conntest.IO{
{W: getInitCmd(&Opts{W: 128, H: 64, Rotated: false})},
// Page 1
{W: []byte{0xB0, 0x00, 0x10}},
{W: buf1},
// Page 2
{W: []byte{0xB1, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 3
{W: []byte{0xB2, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 4
{W: []byte{0xB3, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 5
{W: []byte{0xB4, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 6
{W: []byte{0xB5, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 7
{W: []byte{0xB6, 0x00, 0x10}},
{W: make([]byte, 128)},
// Page 8
{W: []byte{0xB7, 0x00, 0x10}},
{W: make([]byte, 128)},
},
DontPanic: true,
},
@ -453,11 +576,11 @@ func TestSPI_4wire_Write_differential_fail(t *testing.T) {
t.Fatal(err)
}
pix := make([]byte, 1024)
pix[130] = 1
pix[29] = 1
if n, err := dev.Write(pix); n != len(pix) || err != nil {
t.Fatal(n, err)
}
pix[131] = 2
pix[29] = 2
if n, err := dev.Write(pix); n != 0 || !conntest.IsErr(err) {
t.Fatalf("expected conntest error: %v", err)
}
@ -529,7 +652,7 @@ func getI2CPlayback() *i2ctest.Playback {
}
func grayCheckboard() []byte {
buf := make([]byte, 1024)
buf := make([]byte, 128)
for i := range buf {
if i&1 == 0 {
buf[i] = 0xaa

Loading…
Cancel
Save