Krolyxon
Commit 1d55752

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8U8g2srcclibu8x8_d_sh1107.c

868 lines · 28.8 KB · C

1/*
2
3 u8x8_d_sh1107.c
4
5 Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
6
7 Copyright (c) 2017, olikraus@gmail.com
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without modification,
11 are permitted provided that the following conditions are met:
12
13 * Redistributions of source code must retain the above copyright notice, this list
14 of conditions and the following disclaimer.
15
16 * Redistributions in binary form must reproduce the above copyright notice, this
17 list of conditions and the following disclaimer in the documentation and/or other
18 materials provided with the distribution.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36
37#include "u8x8.h"
38
39/* code copyied from SSD1306 */
40
41
42
43static const uint8_t u8x8_d_sh1107_64x128_noname_powersave0_seq[] = {
44 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
45 U8X8_C(0x0af), /* display on */
46 U8X8_END_TRANSFER(), /* disable chip */
47 U8X8_END() /* end of sequence */
48};
49
50static const uint8_t u8x8_d_sh1107_64x128_noname_powersave1_seq[] = {
51 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
52 U8X8_C(0x0ae), /* display off */
53 U8X8_END_TRANSFER(), /* disable chip */
54 U8X8_END() /* end of sequence */
55};
56
57static const uint8_t u8x8_d_sh1107_64x128_noname_flip0_seq[] = {
58 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
59 U8X8_C(0x0a1), /* segment remap a0/a1*/
60 U8X8_C(0x0c8), /* c0: scan dir normal, c8: reverse */
61 U8X8_END_TRANSFER(), /* disable chip */
62 U8X8_END() /* end of sequence */
63};
64
65static const uint8_t u8x8_d_sh1107_64x128_noname_flip1_seq[] = {
66 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
67 U8X8_C(0x0a0), /* segment remap a0/a1*/
68 U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */
69 U8X8_END_TRANSFER(), /* disable chip */
70 U8X8_END() /* end of sequence */
71};
72
73static uint8_t u8x8_d_sh1107_HJR_OEL1M0201_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
74{
75 uint8_t x, c;
76 uint8_t *ptr;
77 switch(msg)
78 {
79 /* handled by the calling function
80 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
81 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_64x128_noname_display_info);
82 break;
83 */
84 /* handled by the calling function
85 case U8X8_MSG_DISPLAY_INIT:
86 u8x8_d_helper_display_init(u8x8);
87 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_init_seq);
88 break;
89 */
90 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
91 if ( arg_int == 0 )
92 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_powersave0_seq);
93 else
94 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_powersave1_seq);
95 break;
96 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
97 if ( arg_int == 0 )
98 {
99 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_flip0_seq);
100 u8x8->x_offset = u8x8->display_info->default_x_offset;
101 }
102 else
103 {
104 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_flip1_seq);
105 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
106 }
107 break;
108#ifdef U8X8_WITH_SET_CONTRAST
109 case U8X8_MSG_DISPLAY_SET_CONTRAST:
110 u8x8_cad_StartTransfer(u8x8);
111 u8x8_cad_SendCmd(u8x8, 0x081 );
112 u8x8_cad_SendArg(u8x8, arg_int ); /* sh1107 has range from 0 to 255 */
113 u8x8_cad_EndTransfer(u8x8);
114 break;
115#endif
116 case U8X8_MSG_DISPLAY_DRAW_TILE:
117 u8x8_cad_StartTransfer(u8x8);
118 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
119 x *= 8;
120 x += u8x8->x_offset;
121
122 //u8x8_cad_SendCmd(u8x8, 0x040 ); /* set line offset to 0 */
123
124 // set column address
125 u8x8_cad_SendCmd(u8x8, 0x010 | (x >> 4));
126 u8x8_cad_SendCmd(u8x8, 0x000 | ((x & 15))); /* probably wrong, should be SendCmd */
127
128 // set page address
129 u8x8_cad_SendCmd(u8x8, 0x0b0 | (2+(((u8x8_tile_t *)arg_ptr)->y_pos))); /* probably wrong, should be SendCmd */
130
131 do
132 {
133 c = ((u8x8_tile_t *)arg_ptr)->cnt;
134 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
135 u8x8_cad_SendData(u8x8, c*8, ptr); /* note: SendData can not handle more than 255 bytes */
136 /*
137 do
138 {
139 u8x8_cad_SendData(u8x8, 8, ptr);
140 ptr += 8;
141 c--;
142 } while( c > 0 );
143 */
144 arg_int--;
145 } while( arg_int > 0 );
146
147 u8x8_cad_EndTransfer(u8x8);
148 break;
149 default:
150 return 0;
151 }
152 return 1;
153}
154
155static uint8_t u8x8_d_sh1107_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
156{
157 uint8_t x, c;
158 uint8_t *ptr;
159 switch(msg)
160 {
161 /* handled by the calling function
162 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
163 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_64x128_noname_display_info);
164 break;
165 */
166 /* handled by the calling function
167 case U8X8_MSG_DISPLAY_INIT:
168 u8x8_d_helper_display_init(u8x8);
169 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_init_seq);
170 break;
171 */
172 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
173 if ( arg_int == 0 )
174 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_powersave0_seq);
175 else
176 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_powersave1_seq);
177 break;
178 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
179 if ( arg_int == 0 )
180 {
181 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_flip0_seq);
182 u8x8->x_offset = u8x8->display_info->default_x_offset;
183 }
184 else
185 {
186 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_flip1_seq);
187 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
188 }
189 break;
190#ifdef U8X8_WITH_SET_CONTRAST
191 case U8X8_MSG_DISPLAY_SET_CONTRAST:
192 u8x8_cad_StartTransfer(u8x8);
193 u8x8_cad_SendCmd(u8x8, 0x081 );
194 u8x8_cad_SendArg(u8x8, arg_int ); /* sh1107 has range from 0 to 255 */
195 u8x8_cad_EndTransfer(u8x8);
196 break;
197#endif
198 case U8X8_MSG_DISPLAY_DRAW_TILE:
199 u8x8_cad_StartTransfer(u8x8);
200 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
201 x *= 8;
202 x += u8x8->x_offset;
203
204 //u8x8_cad_SendCmd(u8x8, 0x040 ); /* set line offset to 0 */
205
206 // set column address
207 u8x8_cad_SendCmd(u8x8, 0x010 | (x >> 4));
208 u8x8_cad_SendCmd(u8x8, 0x000 | ((x & 15))); /* probably wrong, should be SendCmd */
209
210 // set page address
211 u8x8_cad_SendCmd(u8x8, 0x0b0 | (((u8x8_tile_t *)arg_ptr)->y_pos)); /* probably wrong, should be SendCmd */
212
213 do
214 {
215 c = ((u8x8_tile_t *)arg_ptr)->cnt;
216 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
217 u8x8_cad_SendData(u8x8, c*8, ptr); /* note: SendData can not handle more than 255 bytes */
218 /*
219 do
220 {
221 u8x8_cad_SendData(u8x8, 8, ptr);
222 ptr += 8;
223 c--;
224 } while( c > 0 );
225 */
226 arg_int--;
227 } while( arg_int > 0 );
228
229 u8x8_cad_EndTransfer(u8x8);
230 break;
231 default:
232 return 0;
233 }
234 return 1;
235}
236
237/*==================================================*/
238
239/* QG-6428TSWKG01 */
240static const uint8_t u8x8_d_sh1107_64x128_noname_init_seq[] = {
241
242 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
243
244
245 U8X8_C(0x0ae), /* display off */
246 U8X8_CA(0x0dc, 0x000), /* start line */
247 U8X8_CA(0x081, 0x02f), /* [2] set contrast control */
248 U8X8_C(0x020), /* addressing mode */
249
250 // U8X8_C(0x0a1), /* segment remap a0/a1*/
251 // U8X8_C(0x0c8), /* c0: scan dir normal, c8: reverse */
252 // Flipmode
253 U8X8_C(0x0a0), /* segment remap a0/a1*/
254 U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */
255
256 U8X8_CA(0x0a8, 0x7f), /* 0x03f) multiplex ratio */
257 U8X8_CA(0x0d3, 0x060), /* display offset */
258 U8X8_CA(0x0d5, 0x051), /* clock divide ratio (0x00=1) and oscillator frequency (0x8) */
259 U8X8_CA(0x0d9, 0x022), /* [2] pre-charge period 0x022/f1*/
260 U8X8_CA(0x0db, 0x035), /* vcomh deselect level */
261
262 U8X8_C(0x0b0), /* set page address */
263 U8X8_CA(0x0da, 0x012), /* set com pins */
264 U8X8_C(0x0a4), /* output ram to display */
265 U8X8_C(0x0a6), /* none inverted normal display mode */
266
267 U8X8_END_TRANSFER(), /* disable chip */
268 U8X8_END() /* end of sequence */
269};
270
271static const u8x8_display_info_t u8x8_sh1107_64x128_noname_display_info =
272{
273 /* chip_enable_level = */ 0,
274 /* chip_disable_level = */ 1,
275
276 /* post_chip_enable_wait_ns = */ 20,
277 /* pre_chip_disable_wait_ns = */ 10,
278 /* reset_pulse_width_ms = */ 100, /* sh1107: 3 us */
279 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
280 /* sda_setup_time_ns = */ 50, /* sh1107: 15ns, but cycle time is 100ns, so use 100/2 */
281 /* sck_pulse_width_ns = */ 50, /* sh1107: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
282 /* sck_clock_hz = */ 8000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
283 /* spi_mode = */ 0, /* active high, rising edge */
284 /* i2c_bus_clock_100kHz = */ 4,
285 /* data_setup_time_ns = */ 40,
286 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
287 /* tile_width = */ 8,
288 /* tile_height = */ 16,
289 /* default_x_offset = */ 0,
290 /* flipmode_x_offset = */ 0,
291 /* pixel_width = */ 64,
292 /* pixel_height = */ 128
293};
294
295uint8_t u8x8_d_sh1107_64x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
296{
297
298 if ( u8x8_d_sh1107_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
299 return 1;
300
301 switch(msg)
302 {
303 case U8X8_MSG_DISPLAY_INIT:
304 u8x8_d_helper_display_init(u8x8);
305 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_init_seq);
306 break;
307 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
308 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_64x128_noname_display_info);
309 break;
310 default:
311 return 0;
312 }
313 return 1;
314}
315
316/*==================================================*/
317
318/* init sequence from Grove OLED 96x96 */
319static const uint8_t u8x8_d_sh1107_seeed_96x96_init_seq[] = {
320
321 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
322
323
324 U8X8_C(0x0ae), /* display off */
325 U8X8_CA(0x0d5, 0x050), /* clock divide ratio (0x00=1) and oscillator frequency (0x5) */
326 U8X8_C(0x020), /* use page addressing mode */
327 //U8X8_CA(0x0a8, 0x03f), /* multiplex ratio */
328 U8X8_CA(0x0d3, 0x000), /* display offset */
329 U8X8_CA(0x0dc, 0x000), /* start line */
330 //U8X8_CA(0x020, 0x000), /* horizontal addressing mode */
331
332 U8X8_C(0x0a1), /* segment remap a0/a1*/
333 U8X8_C(0x0c8), /* c0: scan dir normal, c8: reverse */
334 // Flipmode
335 // U8X8_C(0x0a0), /* segment remap a0/a1*/
336 // U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */
337
338 //U8X8_CA(0x0da, 0x012), /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */
339
340 U8X8_CA(0x081, 0x080), /* [2] set contrast control */
341 U8X8_CA(0x0ad, 0x080), /* */
342 U8X8_CA(0x0d9, 0x01f), /* [2] pre-charge period 0x022/f1*/
343 U8X8_CA(0x0db, 0x027), /* vcomh deselect level */
344 // if vcomh is 0, then this will give the biggest range for contrast control issue #98
345 // restored the old values for the noname constructor, because vcomh=0 will not work for all OLEDs, #116
346
347 //U8X8_C(0x02e), /* Deactivate scroll */
348 U8X8_C(0x0a4), /* output ram to display */
349 U8X8_C(0x0a6), /* none inverted normal display mode */
350
351 U8X8_END_TRANSFER(), /* disable chip */
352 U8X8_END() /* end of sequence */
353};
354
355static const u8x8_display_info_t u8x8_sh1107_seeed_96x96_display_info =
356{
357 /* chip_enable_level = */ 0,
358 /* chip_disable_level = */ 1,
359
360 /* post_chip_enable_wait_ns = */ 20,
361 /* pre_chip_disable_wait_ns = */ 10,
362 /* reset_pulse_width_ms = */ 100, /* */
363 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
364 /* sda_setup_time_ns = */ 100, /* cycle time is 100ns, so use 100/2 */
365 /* sck_pulse_width_ns = */ 100, /* cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
366 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
367 /* spi_mode = */ 0, /* active high, rising edge */
368 /* i2c_bus_clock_100kHz = */ 4,
369 /* data_setup_time_ns = */ 40,
370 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
371 /* tile_width = */ 12,
372 /* tile_height = */ 12,
373 /* default_x_offset = */ 0,
374 /* flipmode_x_offset = */ 0,
375 /* pixel_width = */ 96,
376 /* pixel_height = */ 96
377};
378
379uint8_t u8x8_d_sh1107_seeed_96x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
380{
381
382 if ( u8x8_d_sh1107_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
383 return 1;
384
385 switch(msg)
386 {
387 case U8X8_MSG_DISPLAY_INIT:
388 u8x8_d_helper_display_init(u8x8);
389 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_seeed_96x96_init_seq);
390 break;
391 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
392 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_seeed_96x96_display_info);
393 break;
394 default:
395 return 0;
396 }
397 return 1;
398}
399
400
401
402
403static const uint8_t u8x8_d_sh1107_HJR_OEL1M0201_96x96_init_seq[] = {
404
405 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
406
407 U8X8_C(0xAE),//
408
409 U8X8_C(0x0F),//
410 U8X8_C(0x17),//
411
412
413 U8X8_C(0xD9),//
414 U8X8_C(0x89), //
415
416 U8X8_CA(0x0d3, 0x000), /* display offset */
417 U8X8_CA(0x0dc, 0x070), /* start line */
418
419 U8X8_C(0x0a0), /* segment remap a0/a1 A0��??A1?���?a|��1D����*/
420 U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */
421
422 U8X8_C(0xD5),//
423 U8X8_C(0xB0),//
424
425 U8X8_C(0x20),//
426
427 U8X8_C(0xDB),//
428 U8X8_C(0x35),//
429
430 U8X8_C(0x81),//
431
432 U8X8_C(0xC7),//
433
434 U8X8_C(0xA4),//A5����????��
435
436 U8X8_C(0xA6),//A6��??A7?���?a?��??��|?
437
438 U8X8_C(0xAD),//
439 U8X8_C(0x80),//
440 U8X8_END_TRANSFER(), /* disable chip */
441 U8X8_END() /* end of sequence */
442};
443
444
445uint8_t u8x8_d_sh1107_hjr_oel1m0201_96x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
446{
447 if ( u8x8_d_sh1107_HJR_OEL1M0201_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
448 return 1;
449
450 switch(msg)
451 {
452 case U8X8_MSG_DISPLAY_INIT:
453 u8x8_d_helper_display_init(u8x8);
454 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_HJR_OEL1M0201_96x96_init_seq);
455 break;
456 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
457 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_seeed_96x96_display_info);
458 break;
459 default:
460 return 0;
461 }
462 return 1;
463}
464
465/*==================================================*/
466/* 128x128 OLED: this display has a very strange x offset */
467
468/*
4696 Feb 2025:
470There is an issue
471https://github.com/olikraus/u8g2/issues/2581#issuecomment-2628394758
472Looks like there are displays where the x offset must be 0
473*/
474
475
476/* sequence taken over from 64x128 sequence, because it seems to work mostly */
477static const uint8_t u8x8_d_sh1107_128x128_init_seq[] = {
478
479 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
480
481
482 U8X8_C(0x0ae), /* display off */
483 U8X8_CA(0x0dc, 0x000), /* start line */
484 U8X8_CA(0x081, 0x02f), /* [2] set contrast control */
485 U8X8_C(0x020), /* use page addressing mode */
486
487 // U8X8_C(0x0a1), /* segment remap a0/a1*/
488 // U8X8_C(0x0c8), /* c0: scan dir normal, c8: reverse */
489 // Flipmode
490 U8X8_C(0x0a0), /* segment remap a0/a1*/
491 U8X8_C(0x0c0), /* c0: scan dir normal, c8: reverse */
492
493 U8X8_CA(0x0a8, 0x7f), /* 0x03f multiplex ratio */
494 //U8X8_CA(0x0d3, 0x060), /* display offset (removed, not in datasheet ) */
495 U8X8_CA(0x0d5, 0x050), /* clock divide ratio (0x00=1) and oscillator frequency (0x8), changed to 0x051, issue 501 */
496 U8X8_CA(0x0d9, 0x022), /* [2] pre-charge period 0x022/f1*/
497 U8X8_CA(0x0db, 0x035), /* vcomh deselect level */
498
499 U8X8_C(0x0b0), /* set page address */
500 U8X8_CA(0x0da, 0x012), /* set com pins */
501 U8X8_C(0x0a4), /* output ram to display */
502 U8X8_C(0x0a6), /* none inverted normal display mode */
503
504 U8X8_END_TRANSFER(), /* disable chip */
505 U8X8_END() /* end of sequence */
506};
507
508
509static const u8x8_display_info_t u8x8_sh1107_128x128_display_info =
510{
511 /* chip_enable_level = */ 0,
512 /* chip_disable_level = */ 1,
513
514 /* post_chip_enable_wait_ns = */ 20,
515 /* pre_chip_disable_wait_ns = */ 10,
516 /* reset_pulse_width_ms = */ 100, /* */
517 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
518 /* sda_setup_time_ns = */ 100, /* cycle time is 100ns, so use 100/2 */
519 /* sck_pulse_width_ns = */ 100, /* cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
520 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
521 /* spi_mode = */ 0, /* active high, rising edge */
522 /* i2c_bus_clock_100kHz = */ 4,
523 /* data_setup_time_ns = */ 40,
524 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
525 /* tile_width = */ 16,
526 /* tile_height = */ 16,
527 /* default_x_offset = */ 96,
528 /* flipmode_x_offset = */ 96,
529 /* pixel_width = */ 128,
530 /* pixel_height = */ 128
531};
532
533uint8_t u8x8_d_sh1107_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
534{
535
536 if ( u8x8_d_sh1107_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
537 return 1;
538
539 switch(msg)
540 {
541 case U8X8_MSG_DISPLAY_INIT:
542 u8x8_d_helper_display_init(u8x8);
543 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_128x128_init_seq);
544 break;
545 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
546 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_128x128_display_info);
547 break;
548 default:
549 return 0;
550 }
551 return 1;
552}
553
554/*==================================================*/
555/* 128x80 OLED, copyied from SEEED 128x128 oled, this display has a very strange x offset */
556/* https://github.com/olikraus/u8g2/issues/1598 */
557/* this is actually a 80x128 display, but let's keep the 128x80 name */
558
559
560static const u8x8_display_info_t u8x8_sh1107_128x80_display_info =
561{
562 /* chip_enable_level = */ 0,
563 /* chip_disable_level = */ 1,
564
565 /* post_chip_enable_wait_ns = */ 20,
566 /* pre_chip_disable_wait_ns = */ 10,
567 /* reset_pulse_width_ms = */ 100, /* */
568 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
569 /* sda_setup_time_ns = */ 100, /* cycle time is 100ns, so use 100/2 */
570 /* sck_pulse_width_ns = */ 100, /* cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
571 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
572 /* spi_mode = */ 0, /* active high, rising edge */
573 /* i2c_bus_clock_100kHz = */ 4,
574 /* data_setup_time_ns = */ 40,
575 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
576 /* tile_width = */ 10,
577 /* tile_height = */ 16,
578 /* default_x_offset = */ 24,
579 /* flipmode_x_offset = */ 24,
580 /* pixel_width = */ 80,
581 /* pixel_height = */ 128
582};
583
584uint8_t u8x8_d_sh1107_128x80(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
585{
586
587 if ( u8x8_d_sh1107_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
588 return 1;
589
590 switch(msg)
591 {
592 case U8X8_MSG_DISPLAY_INIT:
593 u8x8_d_helper_display_init(u8x8);
594 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_128x128_init_seq);
595 break;
596 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
597 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_128x80_display_info);
598 break;
599 default:
600 return 0;
601 }
602 return 1;
603}
604
605/*==================================================*/
606/* pimoroni_128x128_display */
607
608static const u8x8_display_info_t u8x8_sh1107_pimoroni_128x128_display_info =
609{
610 /* chip_enable_level = */ 0,
611 /* chip_disable_level = */ 1,
612
613 /* post_chip_enable_wait_ns = */ 20,
614 /* pre_chip_disable_wait_ns = */ 10,
615 /* reset_pulse_width_ms = */ 100, /* */
616 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
617 /* sda_setup_time_ns = */ 100, /* cycle time is 100ns, so use 100/2 */
618 /* sck_pulse_width_ns = */ 100, /* cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
619 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
620 /* spi_mode = */ 0, /* active high, rising edge */
621 /* i2c_bus_clock_100kHz = */ 4,
622 /* data_setup_time_ns = */ 40,
623 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
624 /* tile_width = */ 16,
625 /* tile_height = */ 16,
626 /* default_x_offset = */ 0,
627 /* flipmode_x_offset = */ 0,
628 /* pixel_width = */ 128,
629 /* pixel_height = */ 128
630};
631
632uint8_t u8x8_d_sh1107_pimoroni_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
633{
634
635 if ( u8x8_d_sh1107_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
636 return 1;
637
638 switch(msg)
639 {
640 case U8X8_MSG_DISPLAY_INIT:
641 u8x8_d_helper_display_init(u8x8);
642 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_128x128_init_seq);
643 break;
644 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
645 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_pimoroni_128x128_display_info);
646 break;
647 default:
648 return 0;
649 }
650 return 1;
651}
652
653/*==================================================*/
654/*
655Name: SH1107_seeed_128x128
656URL: https://www.seeedstudio.com/Grove-OLED-Display-1-12-V2.html
657Display is there in my lab. Backside PCB label: "OLED Display 1.12 inch v1.0"
658Tookover code from SSD1327_SEEED_96X96 because none of the other displays did work
659and at least the 96x96 driver did show something.
660*/
661
662static const u8x8_display_info_t u8x8_seeed_128x128_display_info =
663{
664 /* chip_enable_level = */ 0,
665 /* chip_disable_level = */ 1,
666
667 /* post_chip_enable_wait_ns = */ 20,
668 /* pre_chip_disable_wait_ns = */ 10,
669 /* reset_pulse_width_ms = */ 100, /* */
670 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
671 /* sda_setup_time_ns = */ 100, /* cycle time is 100ns, so use 100/2 */
672 /* sck_pulse_width_ns = */ 100, /* cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
673 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
674 /* spi_mode = */ 0, /* active high, rising edge */
675 /* i2c_bus_clock_100kHz = */ 2, // 400kHz does not work, but 200kHz seems to be ok
676 /* data_setup_time_ns = */ 40,
677 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
678 /* tile_width = */ 16,
679 /* tile_height = */ 16,
680 /* default_x_offset = */ 0,
681 /* flipmode_x_offset = */ 0,
682 /* pixel_width = */ 128,
683 /* pixel_height = */ 128
684};
685
686uint8_t u8x8_d_sh1107_seeed_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
687{
688
689 if ( u8x8_d_sh1107_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
690 return 1;
691
692 switch(msg)
693 {
694 case U8X8_MSG_DISPLAY_INIT:
695 u8x8_d_helper_display_init(u8x8);
696 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_128x128_init_seq);
697 break;
698 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
699 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_seeed_128x128_display_info);
700 break;
701 default:
702 return 0;
703 }
704 return 1;
705}
706static const uint8_t u8x8_d_sh1107_80x128_init_seq[] = {
707
708 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
709 U8X8_C(0xAE), /*display off*/
710 U8X8_C(0x00), /*set lower column address*/
711 U8X8_C(0x10), /*set higher column address*/
712 U8X8_C(0x20), /* Set Memory addressing mode (0x20/0x21) */
713 U8X8_C(0x81), /*contract control*/
714 U8X8_C(0x6f), /*b0*/
715 U8X8_C(0xA0), /*set segment remap*/
716 U8X8_C(0xC0), /*Com scan direction*/
717 U8X8_C(0xA4), /*Disable Entire Display On (0xA4/0xA5)*/
718 U8X8_C(0xA6), /*normal / reverse*/
719 U8X8_C(0xD5), /*set osc division*/
720 U8X8_C(0x91),
721 U8X8_C(0xD9), /*set pre-charge period*/
722 U8X8_C(0x22),
723 U8X8_C(0xdb), /*set vcomh*/
724 U8X8_C(0x3f),
725 U8X8_C(0xA8), /*multiplex ratio*/
726 U8X8_C(0x4F), /*duty = 1/80*/
727 U8X8_C(0xD3), /*set display offset*/
728 U8X8_C(0x68), /*18*/
729 U8X8_C(0xdc), /*Set Display Start Line*/
730 U8X8_C(0x00),
731 U8X8_C(0xad), /*set charge pump enable*/
732 U8X8_C(0x8a), /*Set DC-DC enable (a=0:disable, a=1:enable) */
733// OLED_Clear(),
734 U8X8_C(0xAF), /*display ON*/
735
736
737
738 //U8X8_CA(0x0dc, 0x000), /* start line */
739 // U8X8_CA(0x081, 0x02f), /* [2] set contrast control */
740
741
742 U8X8_END_TRANSFER(), /* disable chip */
743 U8X8_END() /* end of sequence */
744};
745static uint8_t u8x8_d_sh1107_TK078F288_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
746{
747 uint8_t x, c;
748 uint8_t *ptr;
749 switch(msg)
750 {
751 /* handled by the calling function
752 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
753 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sh1107_64x128_noname_display_info);
754 break;
755 */
756 /* handled by the calling function
757 case U8X8_MSG_DISPLAY_INIT:
758 u8x8_d_helper_display_init(u8x8);
759 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_init_seq);
760 break;
761 */
762 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
763 if ( arg_int == 0 )
764 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_powersave0_seq);
765 else
766 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_powersave1_seq);
767 break;
768 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
769 if ( arg_int == 0 )
770 {
771 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_flip0_seq);
772 u8x8->x_offset = u8x8->display_info->default_x_offset;
773 }
774 else
775 {
776 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_64x128_noname_flip1_seq);
777 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
778 }
779 break;
780#ifdef U8X8_WITH_SET_CONTRAST
781 case U8X8_MSG_DISPLAY_SET_CONTRAST:
782 u8x8_cad_StartTransfer(u8x8);
783 u8x8_cad_SendCmd(u8x8, 0x081 );
784 u8x8_cad_SendArg(u8x8, arg_int ); /* sh1107 has range from 0 to 255 */
785 u8x8_cad_EndTransfer(u8x8);
786 break;
787#endif
788 case U8X8_MSG_DISPLAY_DRAW_TILE:
789 u8x8_cad_StartTransfer(u8x8);
790 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
791 x *= 8;
792 x += u8x8->x_offset;
793
794 //u8x8_cad_SendCmd(u8x8, 0x040 ); /* set line offset to 0 */
795
796 // set column address
797 u8x8_cad_SendCmd(u8x8, 0x010 | (x >> 4));
798 u8x8_cad_SendCmd(u8x8, 0x000 | ((x & 15))); /* probably wrong, should be SendCmd */
799
800 // set page address
801 u8x8_cad_SendCmd(u8x8, 0x0b0 | (((u8x8_tile_t *)arg_ptr)->y_pos)); /* probably wrong, should be SendCmd */
802
803 do
804 {
805 c = ((u8x8_tile_t *)arg_ptr)->cnt;
806 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
807 u8x8_cad_SendData(u8x8, c*8, ptr); /* note: SendData can not handle more than 255 bytes */
808 /*
809 do
810 {
811 u8x8_cad_SendData(u8x8, 8, ptr);
812 ptr += 8;
813 c--;
814 } while( c > 0 );
815 */
816 arg_int--;
817 } while( arg_int > 0 );
818
819 u8x8_cad_EndTransfer(u8x8);
820 break;
821 default:
822 return 0;
823 }
824 return 1;
825}
826static const u8x8_display_info_t u8x8_TK078F288_80x128_display_info =
827{
828 /* chip_enable_level = */ 0,
829 /* chip_disable_level = */ 1,
830
831 /* post_chip_enable_wait_ns = */ 20,
832 /* pre_chip_disable_wait_ns = */ 10,
833 /* reset_pulse_width_ms = */ 100, /* */
834 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
835 /* sda_setup_time_ns = */ 100, /* cycle time is 100ns, so use 100/2 */
836 /* sck_pulse_width_ns = */ 100, /* cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
837 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
838 /* spi_mode = */ 0, /* active high, rising edge */
839 /* i2c_bus_clock_100kHz = */ 2, // 400kHz does not work, but 200kHz seems to be ok
840 /* data_setup_time_ns = */ 40,
841 /* write_pulse_width_ns = */ 150, /* sh1107: cycle time is 300ns, so use 300/2 = 150 */
842 /* tile_width = */ 10,
843 /* tile_height = */ 16,
844 /* default_x_offset = */ 0,
845 /* flipmode_x_offset = */ 0,
846 /* pixel_width = */ 80,
847 /* pixel_height = */ 128
848};
849uint8_t u8x8_d_sh1107_tk078f288_80x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
850{
851
852 if ( u8x8_d_sh1107_TK078F288_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
853 return 1;
854
855 switch(msg)
856 {
857 case U8X8_MSG_DISPLAY_INIT:
858 u8x8_d_helper_display_init(u8x8);
859 u8x8_cad_SendSequence(u8x8, u8x8_d_sh1107_80x128_init_seq);
860 break;
861 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
862 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_TK078F288_80x128_display_info);
863 break;
864 default:
865 return 0;
866 }
867 return 1;
868}