Skip to content

Commit 8441db8

Browse files
committed
ssd1306: bring back the lost exported methods
1 parent fd49267 commit 8441db8

File tree

3 files changed

+100
-77
lines changed

3 files changed

+100
-77
lines changed

ssd1306/ssd1306.go

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ type Config struct {
4949
}
5050

5151
type Buser interface {
52-
configure(address uint16, size int16) []byte // configure the bus with the given configuration and return the buffer to use
52+
configure(address uint16, size int16) []byte // configure the bus and return the image buffer to use
5353
command(cmd uint8) error // send a command to the display
54-
flush() error // send the data in the buffer to the display
54+
flush() error // send the image to the display, faster than "tx()" in i2c case since avoids slice copy
55+
tx(data []byte, isCommand bool) error // generic transmit function
5556
}
5657

5758
type VccMode uint8
@@ -89,65 +90,76 @@ func (d *Device) Configure(cfg Config) {
8990
d.buffer = d.bus.configure(cfg.Address, d.width*d.height/8)
9091

9192
time.Sleep(100 * time.Nanosecond)
92-
d.bus.command(DISPLAYOFF)
93-
d.bus.command(SETDISPLAYCLOCKDIV)
94-
d.bus.command(0x80)
95-
d.bus.command(SETMULTIPLEX)
96-
d.bus.command(uint8(d.height - 1))
97-
d.bus.command(SETDISPLAYOFFSET)
98-
d.bus.command(0x0)
99-
d.bus.command(SETSTARTLINE | 0x0)
100-
d.bus.command(CHARGEPUMP)
93+
d.Command(DISPLAYOFF)
94+
d.Command(SETDISPLAYCLOCKDIV)
95+
d.Command(0x80)
96+
d.Command(SETMULTIPLEX)
97+
d.Command(uint8(d.height - 1))
98+
d.Command(SETDISPLAYOFFSET)
99+
d.Command(0x0)
100+
d.Command(SETSTARTLINE | 0x0)
101+
d.Command(CHARGEPUMP)
101102
if d.vccState == EXTERNALVCC {
102-
d.bus.command(0x10)
103+
d.Command(0x10)
103104
} else {
104-
d.bus.command(0x14)
105+
d.Command(0x14)
105106
}
106-
d.bus.command(MEMORYMODE)
107-
d.bus.command(0x00)
107+
d.Command(MEMORYMODE)
108+
d.Command(0x00)
108109

109110
d.SetRotation(cfg.Rotation)
110111

111112
if (d.width == 128 && d.height == 64) || (d.width == 64 && d.height == 48) { // 128x64 or 64x48
112-
d.bus.command(SETCOMPINS)
113-
d.bus.command(0x12)
114-
d.bus.command(SETCONTRAST)
113+
d.Command(SETCOMPINS)
114+
d.Command(0x12)
115+
d.Command(SETCONTRAST)
115116
if d.vccState == EXTERNALVCC {
116-
d.bus.command(0x9F)
117+
d.Command(0x9F)
117118
} else {
118-
d.bus.command(0xCF)
119+
d.Command(0xCF)
119120
}
120121
} else if d.width == 128 && d.height == 32 { // 128x32
121-
d.bus.command(SETCOMPINS)
122-
d.bus.command(0x02)
123-
d.bus.command(SETCONTRAST)
124-
d.bus.command(0x8F)
122+
d.Command(SETCOMPINS)
123+
d.Command(0x02)
124+
d.Command(SETCONTRAST)
125+
d.Command(0x8F)
125126
} else if d.width == 96 && d.height == 16 { // 96x16
126-
d.bus.command(SETCOMPINS)
127-
d.bus.command(0x2)
128-
d.bus.command(SETCONTRAST)
127+
d.Command(SETCOMPINS)
128+
d.Command(0x2)
129+
d.Command(SETCONTRAST)
129130
if d.vccState == EXTERNALVCC {
130-
d.bus.command(0x10)
131+
d.Command(0x10)
131132
} else {
132-
d.bus.command(0xAF)
133+
d.Command(0xAF)
133134
}
134135
} else {
135136
// fail silently, it might work
136137
println("there's no configuration for this display's size")
137138
}
138139

139-
d.bus.command(SETPRECHARGE)
140+
d.Command(SETPRECHARGE)
140141
if d.vccState == EXTERNALVCC {
141-
d.bus.command(0x22)
142+
d.Command(0x22)
142143
} else {
143-
d.bus.command(0xF1)
144+
d.Command(0xF1)
144145
}
145-
d.bus.command(SETVCOMDETECT)
146-
d.bus.command(0x40)
147-
d.bus.command(DISPLAYALLON_RESUME)
148-
d.bus.command(NORMALDISPLAY)
149-
d.bus.command(DEACTIVATE_SCROLL)
150-
d.bus.command(DISPLAYON)
146+
d.Command(SETVCOMDETECT)
147+
d.Command(0x40)
148+
d.Command(DISPLAYALLON_RESUME)
149+
d.Command(NORMALDISPLAY)
150+
d.Command(DEACTIVATE_SCROLL)
151+
d.Command(DISPLAYON)
152+
153+
}
154+
155+
// Command sends a command to the display
156+
func (d *Device) Command(command uint8) {
157+
d.bus.command(command)
158+
}
159+
160+
// Tx sends data to the display; if isCommand is false, this also updates the image buffer.
161+
func (d *Device) Tx(data []byte, isCommand bool) error {
162+
return d.bus.tx(data, isCommand)
151163
}
152164

153165
// ClearBuffer clears the image buffer
@@ -170,12 +182,12 @@ func (d *Device) Display() error {
170182
// In the 128x64 (SPI) screen resetting to 0x0 after 128 times corrupt the buffer
171183
// Since we're printing the whole buffer, avoid resetting it in this case
172184
if d.canReset {
173-
d.bus.command(COLUMNADDR)
174-
d.bus.command(d.resetCol[0])
175-
d.bus.command(d.resetCol[1])
176-
d.bus.command(PAGEADDR)
177-
d.bus.command(d.resetPage[0])
178-
d.bus.command(d.resetPage[1])
185+
d.Command(COLUMNADDR)
186+
d.Command(d.resetCol[0])
187+
d.Command(d.resetCol[1])
188+
d.Command(PAGEADDR)
189+
d.Command(d.resetPage[0])
190+
d.Command(d.resetPage[1])
179191
}
180192

181193
return d.bus.flush()
@@ -250,15 +262,15 @@ func (d *Device) SetRotation(rotation drivers.Rotation) error {
250262
d.rotation = rotation
251263
switch d.rotation {
252264
case drivers.Rotation0:
253-
d.bus.command(SEGREMAP | 0x1) // Reverse horizontal mapping
254-
d.bus.command(COMSCANDEC) // Reverse vertical mapping
265+
d.Command(SEGREMAP | 0x1) // Reverse horizontal mapping
266+
d.Command(COMSCANDEC) // Reverse vertical mapping
255267
case drivers.Rotation180:
256-
d.bus.command(SEGREMAP) // Normal horizontal mapping
257-
d.bus.command(COMSCANINC) // Normal vertical mapping
268+
d.Command(SEGREMAP) // Normal horizontal mapping
269+
d.Command(COMSCANINC) // Normal vertical mapping
258270
// nothing to do
259271
default:
260-
d.bus.command(SEGREMAP | 0x1) // Reverse horizontal mapping
261-
d.bus.command(COMSCANDEC) // Reverse vertical mapping
272+
d.Command(SEGREMAP | 0x1) // Reverse horizontal mapping
273+
d.Command(COMSCANDEC) // Reverse vertical mapping
262274
}
263275
return nil
264276
}
@@ -268,9 +280,9 @@ func (d *Device) SetRotation(rotation drivers.Rotation) error {
268280
// should be kept.
269281
func (d *Device) Sleep(sleepEnabled bool) error {
270282
if sleepEnabled {
271-
d.bus.command(DISPLAYOFF)
283+
d.Command(DISPLAYOFF)
272284
} else {
273-
d.bus.command(DISPLAYON)
285+
d.Command(DISPLAYON)
274286
}
275287
return nil
276288
}

ssd1306/ssd1306_i2c.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
type I2CBus struct {
88
wire drivers.I2C
99
address uint16
10-
buffer []byte
10+
buffer []byte // buffer to avoid heap allocations
1111
}
1212

1313
// NewI2C creates a new SSD1306 connection. The I2C wire must already be configured.
@@ -22,15 +22,11 @@ func NewI2C(bus drivers.I2C) Device {
2222

2323
// configure address for the I2C bus and allocate the buffer
2424
func (b *I2CBus) configure(address uint16, size int16) []byte {
25-
b.address = address
26-
b.buffer = make([]byte, size+2) // +2 for the commands
27-
return b.buffer[2:] // return the buffer without the command part
28-
}
29-
30-
// flush sends the data part of the buffer to the display
31-
func (b *I2CBus) flush() error {
32-
b.buffer[1] = 0x40 // Data mode
33-
return b.wire.Tx(b.address, b.buffer[1:], nil)
25+
if address != 0 {
26+
b.address = address
27+
}
28+
b.buffer = make([]byte, size+2) // +1 for the mode and +1 for a command
29+
return b.buffer[2:] // return the image buffer
3430
}
3531

3632
// command sends a command to the display
@@ -39,3 +35,18 @@ func (b *I2CBus) command(cmd uint8) error {
3935
b.buffer[1] = cmd
4036
return b.wire.Tx(b.address, b.buffer[:2], nil)
4137
}
38+
39+
// flush sends the image to the display
40+
func (b *I2CBus) flush() error {
41+
b.buffer[1] = 0x40 // Data mode
42+
return b.wire.Tx(b.address, b.buffer[1:], nil)
43+
}
44+
45+
// tx sends data to the display
46+
func (b *I2CBus) tx(data []byte, isCommand bool) error {
47+
if isCommand {
48+
return b.command(data[0])
49+
}
50+
copy(b.buffer[2:], data)
51+
return b.flush()
52+
}

ssd1306/ssd1306_spi.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type SPIBus struct {
1212
dcPin machine.Pin
1313
resetPin machine.Pin
1414
csPin machine.Pin
15-
buffer []byte
15+
buffer []byte // buffer to avoid heap allocations
1616
}
1717

1818
// NewSPI creates a new SSD1306 connection. The SPI wire must already be configured.
@@ -42,27 +42,27 @@ func (b *SPIBus) configure(address uint16, size int16) []byte {
4242
time.Sleep(10 * time.Millisecond)
4343
b.resetPin.High()
4444

45-
b.buffer = make([]byte, size+1) // +1 for the command
46-
return b.buffer[1:] // return the buffer without the command part
47-
}
48-
49-
// flush sends the data part of the buffer to the display
50-
func (b *SPIBus) flush() error {
51-
b.csPin.High()
52-
b.dcPin.High()
53-
b.csPin.Low()
54-
err := b.wire.Tx(b.buffer[1:], nil)
55-
b.csPin.High()
56-
return err
45+
b.buffer = make([]byte, size+1) // +1 for a command
46+
return b.buffer[1:] // return the image buffer
5747
}
5848

5949
// command sends a command to the display
6050
func (b *SPIBus) command(cmd uint8) error {
6151
b.buffer[0] = cmd
52+
return b.tx(b.buffer[:1], true)
53+
}
54+
55+
// flush sends the image to the display
56+
func (b *SPIBus) flush() error {
57+
return b.tx(b.buffer[1:], false)
58+
}
59+
60+
// tx sends data to the display
61+
func (b *SPIBus) tx(data []byte, isCommand bool) error {
6262
b.csPin.High()
63-
b.dcPin.Low()
63+
b.dcPin.Set(!isCommand)
6464
b.csPin.Low()
65-
err := b.wire.Tx(b.buffer[:1], nil)
65+
err := b.wire.Tx(data, nil)
6666
b.csPin.High()
6767
return err
6868
}

0 commit comments

Comments
 (0)