/
SSD1331.go
370 lines (305 loc) · 7.96 KB
/
SSD1331.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
package OLED
import (
"image"
"io"
"math"
"time"
"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
"periph.io/x/conn/v3/spi/spireg"
"periph.io/x/host/v3"
)
const (
high = gpio.High
low = gpio.Low
width = 96
height = 64
bufferLen = (width * height) * 2
)
// SSD1331 96*64 pixels, 16bit color OLED.
type SSD1331 struct {
Name string
Frequency physic.Frequency
ResetPin gpio.PinIO
DCPin gpio.PinIO
connect spi.Conn
clorser spi.PortCloser
Status DisplayStatus
buffer []byte
}
type DisplayOnOff byte
const (
DisplayOnInDim DisplayOnOff = 0xAC
DisplayOff DisplayOnOff = 0xAE
DisplayON DisplayOnOff = 0xAF
)
type DisplayMode byte
const (
Nomal DisplayMode = iota + 0xA4
EntireON
EntireOFF
Inverse
)
type ScrollStep byte
const (
Frames6 ScrollStep = iota
Frames10
Frames100
Frames200
)
type DisplayStatus struct {
Mode DisplayMode
Display DisplayOnOff
Scroll struct {
IsScroll bool
Step ScrollStep
}
LOCKED bool
}
func (s DisplayOnOff) IsTurnOn() bool {
switch s {
case DisplayON, DisplayOnInDim:
return true
}
return false
}
// 7.4, 7.9 in Datasheeets.
func (oled *SSD1331) reset() {
oled.ResetPin.Out(low)
time.Sleep(5 * time.Microsecond)
oled.ResetPin.Out(high)
time.Sleep(5 * time.Microsecond)
time.Sleep(150 * time.Millisecond)
}
// Init Initialize oled.
func (oled *SSD1331) Init() error {
_, err := host.Init()
if err != nil {
return err
}
if _, err := driverreg.Init(); err != nil {
return err
}
p, err := spireg.Open(oled.Name)
if err != nil {
return err
}
oled.clorser = p
c, err := p.Connect(oled.Frequency, spi.Mode3, 8)
if err != nil {
return err
}
oled.connect = c
// Reset the oled.
oled.reset()
// Send initial commands.
oled.sendCommand([]byte{
0xAE, // display off
0x15, 0x00, 0x5F, // column addr
0x75, 0x00, 0x3F, // column addr
0x87, 0x07, // master current
0xA0, 0x72, // remap, color depth setting (65k color)
0xA1, 0x00, // set display start line by row
0xA2, 0x00, // set v offset by com
0xA4, // normal
0xA8, 0x3F, // multiplex ratio
0xAD, 0x8E, // master configuration
0xB0, 0x0B, // power save mode, How many save current???
0xB1, 0x31, // phase 1 and 2 period adjustment
0xB3, 0xF0, // display clock div, oscillator freq
0xBB, 0x3E, // pre-charge voltage
0xBE, 0x3E, // set VCOMH
0xAF, // display on
})
oled.Status = DisplayStatus{Nomal, DisplayON, oled.Status.Scroll, false}
oled.buffer = make([]byte, bufferLen)
return nil
}
// Close Close the port.
func (oled *SSD1331) Close() error {
// oled.DisplayOff()
return oled.clorser.Close()
}
// Resolution Returns the resolution of OLED.
func (oled *SSD1331) Resolution() (int, int) {
return width, height
}
// Buffer Raw buffer.
func (oled *SSD1331) Buffer() *[]byte {
return &oled.buffer
}
// DisplayOn Turn on the OLED.
func (oled *SSD1331) DisplayOn() {
oled.sendCommand([]byte{0xAF})
oled.Status.Display = DisplayON
}
// DisplayOnDim Turn on the OLED in dim mode.
func (oled *SSD1331) DisplayOnDim() {
oled.sendCommand([]byte{0xAC})
oled.Status.Display = DisplayOnInDim
}
// DisplayOff Turn off the OLED.
func (oled *SSD1331) DisplayOff() {
oled.sendCommand([]byte{0xAE})
oled.Status.Display = DisplayOff
}
// SettingDimMode Configure dim mode setting
// r, g, b <= 255, preChargeVoltage <= 31
func (oled *SSD1331) SettingDimMode(r, g, b, preChargeVoltage byte) {
oled.sendCommand(append([]byte{0xAB, 0}, r, g, b, preChargeVoltage))
}
// SetDisplayMode Change the display mode.
func (oled *SSD1331) SetDisplayMode(mode DisplayMode) {
oled.sendCommand([]byte{byte(mode)})
oled.Status.Mode = mode
}
// SetRGBContrast value <= 128.
func (oled *SSD1331) SetRGBContrast(r, g, b byte) {
oled.sendCommand([]byte{0x81, r, 0x82, g, 0x83})
}
// Display Send buffer to the OLED.
func (oled *SSD1331) Display() {
oled.sendDate(oled.buffer)
}
// Clear Clear the buffer.
func (oled *SSD1331) Clear() {
oled.buffer = make([]byte, bufferLen)
}
// ClearDisplay Clear the buffer then apply display.
func (oled *SSD1331) ClearDisplay() {
oled.Clear()
oled.Display()
}
// GetPixel Get the pixel from the ""buffer"".
func (oled *SSD1331) GetPixel(x, y int) uint16 {
idx := ((y * width) + x) * 2
most := oled.buffer[idx]
least := oled.buffer[idx+1]
return (uint16(most) << 8) | uint16(least)
}
// SetPixel Set the pixel in the buffer.
func (oled *SSD1331) SetPixel(x, y, r, g, b int) {
startIDX := ((y * width) + x) * 2
colorH := (r & 0b11111000) | (g >> 5)
colorL := ((g << 3) & 0b11100000) | (b >> 3)
oled.buffer[startIDX] = byte(colorH)
oled.buffer[startIDX+1] = byte(colorL)
}
// SetLine Write a line on the OLED.
func (oled *SSD1331) SetLine(x0, y0, x1, y1, r, g, b int) {
// I referred to this(https://ja.wikipedia.org/wiki/ブレゼンハムのアルゴリズム/).
dx := x1 - x0 // Abs
dy := y1 - y0 // Abs
err := dx - dy
for {
oled.SetPixel(x0, y0, r, g, b)
if x0 == x1 && y0 == y1 {
break
}
e2 := 2 * err
if e2 > -dy {
err -= dy
x0 += -1
}
if e2 < dx {
err += dx
y0 += -1
}
}
}
func (oled *SSD1331) SetVLine(x, y, h, r, g, b int) {
for i := 0; i < h; i++ {
oled.SetPixel(x, y+i, r, g, b)
}
}
func (oled *SSD1331) SetHLine(x, y, w, r, g, b int) {
for i := 0; i < w; i++ {
oled.SetPixel(x+i, y, r, g, b)
}
}
// DrawRect Draw a rectangle to the OLED.
func (oled *SSD1331) DrawRect(x0, y0, x1, y1, lineColorR, lineColorG, lineColorB, fillColorR, fillColorG, fillColorB int, fill bool) {
var f byte = 0xA1
if !fill {
f = 0xA0
}
oled.sendCommand([]byte{
0x26, f,
0x22, byte(x0), byte(y0), byte(x1), byte(y1),
byte(lineColorR), byte(lineColorG), byte(lineColorB),
byte(fillColorR), byte(fillColorG), byte(fillColorB),
})
time.Sleep(2 * time.Millisecond)
}
// DrawCircle Draw the circle.
//
// cx,xy Positions the circle.
// r Size of circle.
// a R color
// b G color
// c B color
func (oled *SSD1331) SetCircle(cx, cy int, r float64, a, b, c int) {
for d := .0; d < 360.0; d++ {
x := int(float64(cx) + (r * math.Cos(d*math.Pi/180.0)))
y := int(float64(cy) + (r * math.Sin(d*math.Pi/180.0)))
oled.SetPixel(x, y, a, b, c)
}
}
// Fill Fill the display buffer.
func (oled *SSD1331) Fill(r, g, b int) {
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
oled.SetPixel(x, y, r, g, b)
}
}
}
// SetImage Set the image pixels to buffer. Support resolutions are display width and height.
func (oled *SSD1331) SetImage(img image.Image) {
bounds := img.Bounds()
for y := 0; y < bounds.Max.Y; y++ {
for x := 0; x < bounds.Max.X; x++ {
r, g, b, _ := img.At(x, y).RGBA()
oled.SetPixel(x, y, int(r>>8), int(g>>8), int(b>>8))
}
}
}
// ActiveScroll Scrool the display.
//
// horScrlOffset Set number of column as horizontal scroll offset.
// startRowAddr Define start row address.
// horRowScrl Set number of rows to be horizontal scrolled.
// verScrlOffset Set number of row as vertical scroll offset.
// scrlInterval Set time interval between each scroll step.
func (oled *SSD1331) ActiveScroll(horScrlOffset, startRowAddr, horRowScrl, verScrlOffset byte, scrlInterval ScrollStep) {
oled.sendCommand([]byte{
0x27, horRowScrl, startRowAddr, horRowScrl, verScrlOffset, byte(scrlInterval),
0x2F,
})
oled.Status.Scroll.IsScroll = true
oled.Status.Scroll.Step = scrlInterval
}
// DeactiveScrool If Scrool function is Active then stop the scrool.
func (oled *SSD1331) DeactiveScrool() {
oled.sendCommand([]byte{0x2E})
oled.Status.Scroll.IsScroll = false
}
// LOCK MCU interface will no longer accept commands.
func (oled *SSD1331) LOCK() {
oled.sendCommand([]byte{0xFD, 0x16})
oled.Status.LOCKED = true
}
// UNLOCK Unlock the LOCK function.
func (oled *SSD1331) UNLOCK() {
oled.sendCommand([]byte{0xFD, 0x12})
oled.Status.LOCKED = false
}
func (oled *SSD1331) sendCommand(b []byte) {
oled.DCPin.Out(low)
oled.connect.(io.Writer).Write(b)
}
func (oled *SSD1331) sendDate(b []byte) {
oled.DCPin.Out(high)
oled.connect.(io.Writer).Write(b)
}