-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
SH1106.hpp
401 lines (356 loc) · 12.5 KB
/
SH1106.hpp
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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
#pragma once
//=====================================================================//
/*! @file
@brief SH1106 OLED ドライバー @n
Copyright 2022 Kunihito Hiramatsu
@author 平松邦仁 ([email protected])
*/
//=====================================================================//
#include <cstdint>
#include "common/delay.hpp"
namespace chip {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief SH1106 テンプレートクラス
@param[in] CSI_IO CSI(SPI) 制御クラス
@param[in] CS デバイス選択、レジスター選択、制御クラス
@param[in] DC データ、コマンド切り替え、制御クラス
@param[in] RES リセット、制御クラス
@param[in] EXTVCC EXTERNAL VCC の場合「true」
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class CSI_IO, class CS, class DC, class RES, bool EXT_VCC = false>
class SH1106 {
CSI_IO& csi_;
enum class CMD : uint8_t {
SETCONTRAST = 0x81,
DISPLAYALLON_RESUME = 0xA4,
DISPLAYALLON = 0xA5,
NORMALDISPLAY = 0xA6,
INVERTDISPLAY = 0xA7,
DISPLAYOFF = 0xAE,
DISPLAYON = 0xAF,
SETDISPLAYOFFSET = 0xD3,
SETCOMPINS = 0xDA,
SETVCOMDETECT = 0xDB,
SETDISPLAYCLOCKDIV = 0xD5,
SETPRECHARGE = 0xD9,
SETMULTIPLEX = 0xA8,
SETLOWCOLUMN = 0x00,
SETHIGHCOLUMN = 0x10,
SETSTARTLINE = 0x40,
MEMORYMODE = 0x20,
COLUMNADDR = 0x21,
PAGEADDR = 0x22,
COMSCANINC = 0xC0,
COMSCANDEC = 0xC8,
SEGREMAP0 = 0xA0,
SEGREMAP1 = 0xA1,
CHARGEPUMP = 0x8D,
EXTERNALVCC = 0x1,
SWITCHCAPVCC = 0x2,
// Scrolling
ACTIVATE_SCROLL = 0x2F,
DEACTIVATE_SCROLL = 0x2E,
SET_VERTICAL_SCROLL_AREA = 0xA3,
RIGHT_HORIZONTAL_SCROLL = 0x26,
LEFT_HORIZONTAL_SCROLL = 0x27,
VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29,
VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A,
};
void write_cmd_(CMD c)
{
//digitalWrite(dc, LOW);
DC::P = 0;
//digitalWrite(cs, LOW);
CS::P = 0;
//fastSPIwrite(c);
csi_.xchg(static_cast<uint8_t>(c));
//digitalWrite(cs, HIGH);
CS::P = 1;
#if 0
// I2C
uint8_t control = 0x00; // Co = 0, D/C = 0
Wire.beginTransmission(_i2caddr);
WIRE_WRITE(control);
WIRE_WRITE(c);
Wire.endTransmission();
#endif
}
void write_data_(uint8_t c)
{
// SPI
//digitalWrite(dc, HIGH);
DC::P = 1;
//digitalWrite(cs, LOW);
CS::P = 0;
//fastSPIwrite(c);
csi_.xchg(c);
//digitalWrite(cs, HIGH);
CS::P = 1;
#if 0
// I2C
uint8_t control = 0x40; // Co = 0, D/C = 1
Wire.beginTransmission(_i2caddr);
WIRE_WRITE(control);
WIRE_WRITE(c);
Wire.endTransmission();
#endif
}
#if 0
// startscrollright
// Activate a right handed scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
//void Adafruit_SH1106::startscrollright(uint8_t start, uint8_t stop){
SH1106_command(SH1106_RIGHT_HORIZONTAL_SCROLL);
SH1106_command(0X00);
SH1106_command(start);
SH1106_command(0X00);
SH1106_command(stop);
SH1106_command(0X00);
SH1106_command(0XFF);
SH1106_command(SH1106_ACTIVATE_SCROLL);
}
// startscrollleft
// Activate a right handed scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void Adafruit_SH1106::startscrollleft(uint8_t start, uint8_t stop){
SH1106_command(SH1106_LEFT_HORIZONTAL_SCROLL);
SH1106_command(0X00);
SH1106_command(start);
SH1106_command(0X00);
SH1106_command(stop);
SH1106_command(0X00);
SH1106_command(0XFF);
SH1106_command(SH1106_ACTIVATE_SCROLL);
}
// startscrolldiagright
// Activate a diagonal scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void Adafruit_SH1106::startscrolldiagright(uint8_t start, uint8_t stop){
SH1106_command(SH1106_SET_VERTICAL_SCROLL_AREA);
SH1106_command(0X00);
SH1106_command(SH1106_LCDHEIGHT);
SH1106_command(SH1106_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
SH1106_command(0X00);
SH1106_command(start);
SH1106_command(0X00);
SH1106_command(stop);
SH1106_command(0X01);
SH1106_command(SH1106_ACTIVATE_SCROLL);
}
// startscrolldiagleft
// Activate a diagonal scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void Adafruit_SH1106::startscrolldiagleft(uint8_t start, uint8_t stop){
SH1106_command(SH1106_SET_VERTICAL_SCROLL_AREA);
SH1106_command(0X00);
SH1106_command(SH1106_LCDHEIGHT);
SH1106_command(SH1106_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
SH1106_command(0X00);
SH1106_command(start);
SH1106_command(0X00);
SH1106_command(stop);
SH1106_command(0X01);
SH1106_command(SH1106_ACTIVATE_SCROLL);
}
void Adafruit_SH1106::stopscroll(void){
SH1106_command(SH1106_DEACTIVATE_SCROLL);
}
#if defined SH1106_128_32
// Init sequence for 128x32 OLED module
SH1106_command(SH1106_DISPLAYOFF); // 0xAE
SH1106_command(SH1106_SETDISPLAYCLOCKDIV); // 0xD5
SH1106_command(0x80); // the suggested ratio 0x80
SH1106_command(SH1106_SETMULTIPLEX); // 0xA8
SH1106_command(0x1F);
SH1106_command(SH1106_SETDISPLAYOFFSET); // 0xD3
SH1106_command(0x0); // no offset
SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0
SH1106_command(SH1106_CHARGEPUMP); // 0x8D
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x10); }
else
{ SH1106_command(0x14); }
SH1106_command(SH1106_MEMORYMODE); // 0x20
SH1106_command(0x00); // 0x0 act like ks0108
SH1106_command(SH1106_SEGREMAP | 0x1);
SH1106_command(SH1106_COMSCANDEC);
SH1106_command(SH1106_SETCOMPINS); // 0xDA
SH1106_command(0x02);
SH1106_command(SH1106_SETCONTRAST); // 0x81
SH1106_command(0x8F);
SH1106_command(SH1106_SETPRECHARGE); // 0xd9
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x22); }
else
{ SH1106_command(0xF1); }
SH1106_command(SH1106_SETVCOMDETECT); // 0xDB
SH1106_command(0x40);
SH1106_command(SH1106_DISPLAYALLON_RESUME); // 0xA4
SH1106_command(SH1106_NORMALDISPLAY); // 0xA6
#endif
#if defined SH1106_128_64
// Init sequence for 128x64 OLED module
SH1106_command(SH1106_DISPLAYOFF); // 0xAE
SH1106_command(SH1106_SETDISPLAYCLOCKDIV); // 0xD5
SH1106_command(0x80); // the suggested ratio 0x80
SH1106_command(SH1106_SETMULTIPLEX); // 0xA8
SH1106_command(0x3F);
SH1106_command(SH1106_SETDISPLAYOFFSET); // 0xD3
SH1106_command(0x00); // no offset
SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0 0x40
SH1106_command(SH1106_CHARGEPUMP); // 0x8D
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x10); }
else
{ SH1106_command(0x14); }
SH1106_command(SH1106_MEMORYMODE); // 0x20
SH1106_command(0x00); // 0x0 act like ks0108
SH1106_command(SH1106_SEGREMAP | 0x1);
SH1106_command(SH1106_COMSCANDEC);
SH1106_command(SH1106_SETCOMPINS); // 0xDA
SH1106_command(0x12);
SH1106_command(SH1106_SETCONTRAST); // 0x81
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x9F); }
else
{ SH1106_command(0xCF); }
SH1106_command(SH1106_SETPRECHARGE); // 0xd9
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x22); }
else
{ SH1106_command(0xF1); }
SH1106_command(SH1106_SETVCOMDETECT); // 0xDB
SH1106_command(0x40);
SH1106_command(SH1106_DISPLAYALLON_RESUME); // 0xA4
SH1106_command(SH1106_NORMALDISPLAY); // 0xA6
#endif
#if defined SH1106_96_16
// Init sequence for 96x16 OLED module
SH1106_command(SH1106_DISPLAYOFF); // 0xAE
SH1106_command(SH1106_SETDISPLAYCLOCKDIV); // 0xD5
SH1106_command(0x80); // the suggested ratio 0x80
SH1106_command(SH1106_SETMULTIPLEX); // 0xA8
SH1106_command(0x0F);
SH1106_command(SH1106_SETDISPLAYOFFSET); // 0xD3
SH1106_command(0x00); // no offset
SH1106_command(SH1106_SETSTARTLINE | 0x0); // line #0
SH1106_command(SH1106_CHARGEPUMP); // 0x8D
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x10); }
else
{ SH1106_command(0x14); }
SH1106_command(SH1106_MEMORYMODE); // 0x20
SH1106_command(0x00); // 0x0 act like ks0108
SH1106_command(SH1106_SEGREMAP | 0x1);
SH1106_command(SH1106_COMSCANDEC);
SH1106_command(SH1106_SETCOMPINS); // 0xDA
SH1106_command(0x2); //ada x12
SH1106_command(SH1106_SETCONTRAST); // 0x81
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x10); }
else
{ SH1106_command(0xAF); }
SH1106_command(SH1106_SETPRECHARGE); // 0xd9
if (vccstate == SH1106_EXTERNALVCC)
{ SH1106_command(0x22); }
else
{ SH1106_command(0xF1); }
SH1106_command(SH1106_SETVCOMDETECT); // 0xDB
SH1106_command(0x40);
SH1106_command(SH1106_DISPLAYALLON_RESUME); // 0xA4
SH1106_command(SH1106_NORMALDISPLAY); // 0xA6
#endif
SH1106_command(SH1106_DISPLAYON);//--turn on oled panel
#endif
public:
//-----------------------------------------------------------------//
/*!
@brief コンストラクター
*/
//-----------------------------------------------------------------//
SH1106(CSI_IO& csi) : csi_(csi) { }
//-----------------------------------------------------------------//
/*!
@brief 開始
@param[in] contrast コントラスト
@param[in] comrvs コモンライン・リバースの場合:true
@param[in] bias9 BIAS9 選択の場合「true」
@param[in] vratio ボルテージ・レシオ
*/
//-----------------------------------------------------------------//
void start()
{
CS::DIR = 1; // (/CS) output
DC::DIR = 1; // (A0) output
RES::DIR = 1; // (/RES) output
CS::P = 1;
DC::P = 0;
RES::P = 0; // assert /RES signal
utils::delay::milli_second(100);
RES::P = 1; // negate /RES signal
utils::delay::milli_second(10);
// 128 x 64 pixel
write_cmd_(CMD::DISPLAYOFF);
write_cmd_(CMD::SETDISPLAYCLOCKDIV);
write_cmd_(static_cast<CMD>(0x80)); // the suggested ratio 0x80
write_cmd_(CMD::SETMULTIPLEX);
write_cmd_(static_cast<CMD>(0x3F));
write_cmd_(CMD::SETDISPLAYOFFSET);
write_cmd_(static_cast<CMD>(0x00));
write_cmd_(CMD::SETSTARTLINE); // line #0 0x40
write_cmd_(CMD::CHARGEPUMP);
if(EXT_VCC) {
write_cmd_(static_cast<CMD>(0x10));
} else {
write_cmd_(static_cast<CMD>(0x14));
}
write_cmd_(CMD::MEMORYMODE);
write_cmd_(static_cast<CMD>(0x00)); // 0x0 act like ks0108
write_cmd_(CMD::SEGREMAP1);
write_cmd_(CMD::COMSCANDEC);
write_cmd_(CMD::SETCOMPINS);
write_cmd_(static_cast<CMD>(0x12));
write_cmd_(CMD::SETCONTRAST);
if(EXT_VCC) {
write_cmd_(static_cast<CMD>(0x9F));
} else {
write_cmd_(static_cast<CMD>(0xCF));
}
write_cmd_(CMD::SETPRECHARGE);
if(EXT_VCC) {
write_cmd_(static_cast<CMD>(0x22));
} else {
write_cmd_(static_cast<CMD>(0xF1));
}
write_cmd_(CMD::SETVCOMDETECT);
write_cmd_(static_cast<CMD>(0x40));
write_cmd_(CMD::DISPLAYALLON_RESUME);
write_cmd_(CMD::NORMALDISPLAY);
// end of 128 x 64 pixel
write_cmd_(CMD::DISPLAYON);
write_cmd_(CMD::SETLOWCOLUMN); // low col = 0
write_cmd_(CMD::SETHIGHCOLUMN); // hi col = 0
write_cmd_(CMD::SETSTARTLINE); // line #0
}
//-----------------------------------------------------------------//
/*!
@brief 画面反転の許可
@param[in] ena 画面反転をしない場合「false」
*/
//-----------------------------------------------------------------//
void invert_enable(bool ena = true)
{
if(ena) {
write_cmd_(CMD::INVERTDISPLAY);
} else {
write_cmd_(CMD::NORMALDISPLAY);
}
}
};
}