Krolyxon
Commit 1d55752

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8U8g2srcclibu8x8_d_ssd1362.c

538 lines · 16.1 KB · C

1/*
2
3 u8x8_d_ssd1362.c
4
5 https://github.com/olikraus/u8g2/issues/2051
6
7 Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
8
9 Copyright (c) 2022, olikraus@gmail.com
10 All rights reserved.
11
12 Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14
15 * Redistributions of source code must retain the above copyright notice, this list
16 of conditions and the following disclaimer.
17
18 * Redistributions in binary form must reproduce the above copyright notice, this
19 list of conditions and the following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36
37 SSD1362:
38 256 x 64 (ssd1322: 480 x 128)
39 16 gray scale
40
41
42 Note: Currently the external IREF is activated.
43 Maybe we need a constructor with internal IREF
44
45*/
46#include "u8x8.h"
47
48
49
50
51static const uint8_t u8x8_d_ssd1362_powersave0_seq[] = {
52 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
53 U8X8_C(0x0af), /* ssd1362: display on */
54 U8X8_END_TRANSFER(), /* disable chip */
55 U8X8_END() /* end of sequence */
56};
57
58static const uint8_t u8x8_d_ssd1362_powersave1_seq[] = {
59 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
60 U8X8_C(0x0ae), /* ssd1362: display off */
61 U8X8_END_TRANSFER(), /* disable chip */
62 U8X8_END() /* end of sequence */
63};
64
65
66
67
68/*
69 input:
70 one tile (8 Bytes)
71 output:
72 Tile for SSD1362 (32 Bytes)
73*/
74
75static uint8_t u8x8_ssd1362_to32_dest_buf[32];
76
77static uint8_t *u8x8_ssd1362_8to32(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
78{
79 uint8_t v;
80 uint8_t a,b;
81 uint8_t i, j;
82 uint8_t *dest;
83
84 for( j = 0; j < 4; j++ )
85 {
86 dest = u8x8_ssd1362_to32_dest_buf;
87 dest += j;
88 a =*ptr;
89 ptr++;
90 b = *ptr;
91 ptr++;
92 for( i = 0; i < 8; i++ )
93 {
94 v = 0;
95 if ( a&1 ) v |= 0xf0;
96 if ( b&1 ) v |= 0x0f;
97 *dest = v;
98 dest+=4;
99 a >>= 1;
100 b >>= 1;
101 }
102 }
103
104 return u8x8_ssd1362_to32_dest_buf;
105}
106
107/* special case for the 206x36 display: send only half of the last tile */
108static uint8_t *u8x8_ssd1362_8to24(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
109{
110 uint8_t v;
111 uint8_t a,b;
112 uint8_t i, j;
113 uint8_t *dest;
114
115 for( j = 0; j < 3; j++ )
116 {
117 dest = u8x8_ssd1362_to32_dest_buf;
118 dest += j;
119 a =*ptr;
120 ptr++;
121 b = *ptr;
122 ptr++;
123 for( i = 0; i < 8; i++ )
124 {
125 v = 0;
126 if ( a&1 ) v |= 0xf0;
127 if ( b&1 ) v |= 0x0f;
128 *dest = v;
129 dest+=3;
130 a >>= 1;
131 b >>= 1;
132 }
133 }
134
135 return u8x8_ssd1362_to32_dest_buf;
136}
137
138
139uint8_t u8x8_d_ssd1362_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
140{
141 uint8_t x;
142 uint8_t y, c;
143 uint8_t *ptr;
144 switch(msg)
145 {
146 /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
147 /*
148 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
149 break;
150 case U8X8_MSG_DISPLAY_INIT:
151 u8x8_d_helper_display_init(u8x8);
152 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_init_seq);
153 break;
154 */
155 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
156 if ( arg_int == 0 )
157 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_powersave0_seq);
158 else
159 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_powersave1_seq);
160 break;
161#ifdef U8X8_WITH_SET_CONTRAST
162 case U8X8_MSG_DISPLAY_SET_CONTRAST:
163 u8x8_cad_StartTransfer(u8x8);
164 u8x8_cad_SendCmd(u8x8, 0x081 );
165 u8x8_cad_SendArg(u8x8, arg_int ); /* ssd1362 has range from 0 to 255 */
166 u8x8_cad_EndTransfer(u8x8);
167 break;
168#endif
169 case U8X8_MSG_DISPLAY_DRAW_TILE:
170 u8x8_cad_StartTransfer(u8x8);
171 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
172 x *= 4; // convert from tile pos to display column
173 x += u8x8->x_offset;
174
175 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
176 y *= 8;
177
178
179 u8x8_cad_SendCmd(u8x8, 0x075 ); /* set row address, moved out of the loop (issue 302) */
180 u8x8_cad_SendArg(u8x8, y);
181 u8x8_cad_SendArg(u8x8, y+7);
182
183 do
184 {
185 c = ((u8x8_tile_t *)arg_ptr)->cnt;
186 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
187
188 do
189 {
190 u8x8_cad_SendCmd(u8x8, 0x015 ); /* set column address */
191 u8x8_cad_SendArg(u8x8, x ); /* start */
192 u8x8_cad_SendArg(u8x8, x+3 ); /* end */
193 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1362_8to32(u8x8, ptr));
194
195 ptr += 8;
196 x += 4;
197 c--;
198 } while( c > 0 );
199
200 arg_int--;
201
202 } while( arg_int > 0 );
203
204 u8x8_cad_EndTransfer(u8x8);
205 break;
206 default:
207 return 0;
208 }
209 return 1;
210}
211
212
213uint8_t u8x8_d_ssd1362_common_0_75(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
214{
215 uint8_t x;
216 uint8_t y, c;
217 uint8_t *ptr;
218 switch(msg)
219 {
220 /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
221 /*
222 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
223 break;
224 case U8X8_MSG_DISPLAY_INIT:
225 u8x8_d_helper_display_init(u8x8);
226 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_init_seq);
227 break;
228 */
229 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
230 if ( arg_int == 0 )
231 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_powersave0_seq);
232 else
233 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_powersave1_seq);
234 break;
235#ifdef U8X8_WITH_SET_CONTRAST
236 case U8X8_MSG_DISPLAY_SET_CONTRAST:
237 u8x8_cad_StartTransfer(u8x8);
238 u8x8_cad_SendCmd(u8x8, 0x081 );
239 u8x8_cad_SendArg(u8x8, arg_int ); /* ssd1362 has range from 0 to 255 */
240 u8x8_cad_EndTransfer(u8x8);
241 break;
242#endif
243 case U8X8_MSG_DISPLAY_DRAW_TILE:
244 u8x8_cad_StartTransfer(u8x8);
245 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
246 x *= 4; // convert from tile pos to display column
247 x += u8x8->x_offset;
248
249 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
250 y *= 8;
251
252
253 u8x8_cad_SendCmd(u8x8, 0x075 ); /* set row address, moved out of the loop (issue 302) */
254 u8x8_cad_SendArg(u8x8, y);
255 u8x8_cad_SendArg(u8x8, y+7);
256
257 do
258 {
259 c = ((u8x8_tile_t *)arg_ptr)->cnt;
260 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
261
262 do
263 {
264 u8x8_cad_SendCmd(u8x8, 0x015 ); /* set column address */
265 if ( x < 123 )
266 {
267 u8x8_cad_SendArg(u8x8, x ); /* start */
268 u8x8_cad_SendArg(u8x8, x+3 ); /* end */
269 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1362_8to32(u8x8, ptr));
270 }
271 else
272 {
273 u8x8_cad_SendArg(u8x8, x ); /* start */
274 u8x8_cad_SendArg(u8x8, x+2 ); /* end */
275 u8x8_cad_SendData(u8x8, 24, u8x8_ssd1362_8to24(u8x8, ptr));
276 }
277
278 ptr += 8;
279 x += 4;
280 c--;
281 } while( c > 0 );
282
283 arg_int--;
284
285 } while( arg_int > 0 );
286
287 u8x8_cad_EndTransfer(u8x8);
288 break;
289 default:
290 return 0;
291 }
292 return 1;
293}
294
295
296
297/*=========================================================*/
298
299static const uint8_t u8x8_d_ssd1362_256x64_flip0_seq[] = {
300 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
301 U8X8_CA(0xa0, 0xc3), //Set Remap c3 = 11000011
302
303 U8X8_END_TRANSFER(), /* disable chip */
304 U8X8_END() /* end of sequence */
305};
306
307static const uint8_t u8x8_d_ssd1362_256x64_flip1_seq[] = {
308 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
309 U8X8_CA(0xa0, 0xd0),
310 U8X8_END_TRANSFER(), /* disable chip */
311 U8X8_END() /* end of sequence */
312};
313
314static const u8x8_display_info_t u8x8_ssd1362_256x64_display_info =
315{
316 /* chip_enable_level = */ 0,
317 /* chip_disable_level = */ 1,
318
319 /* post_chip_enable_wait_ns = */ 20,
320 /* pre_chip_disable_wait_ns = */ 10,
321 /* reset_pulse_width_ms = */ 100, /* ssd1362: 2 us */
322 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
323 /* sda_setup_time_ns = */ 50, /* ssd1362: 15ns, but cycle time is 100ns, so use 100/2 */
324 /* sck_pulse_width_ns = */ 50, /* ssd1362: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
325 /* sck_clock_hz = */ 10000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215), 10 MHz (issue 301) */
326 /* spi_mode = */ 0, /* active high, rising edge */
327 /* i2c_bus_clock_100kHz = */ 4,
328 /* data_setup_time_ns = */ 10,
329 /* write_pulse_width_ns = */ 150, /* ssd1362: cycle time is 300ns, so use 300/2 = 150 */
330 /* tile_width = */ 32, /* 256 pixel, so we require 32 bytes for this */
331 /* tile_height = */ 8,
332 /* default_x_offset = */ 0, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
333 /* flipmode_x_offset = */ 0,
334 /* pixel_width = */ 256,
335 /* pixel_height = */ 64
336};
337
338
339/* https://github.com/olikraus/u8g2/issues/2051 */
340static const uint8_t u8x8_d_ssd1362_256x64_init_seq[] = {
341
342 U8X8_DLY(1),
343 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
344 U8X8_DLY(1),
345
346 U8X8_CA(0xfd, 0x12), /* unlock */
347 U8X8_C(0xae), /* display off */
348 U8X8_CA(0x23, 0x00), //POR 0x00; Disable fade mode
349 U8X8_CA(0x81, 0x9f), //Set contrast
350
351/*
352Re- map setting in Graphic Display Data RAM
353(GDDRAM)
354
355A[0] = 0b, Disable Column Address Re-map (RESET)
356A[0] = 1b, Enable Column Address Re-map ***
357
358A[1] = 0b, Disable Nibble Re-map (RESET)
359A[1] = 1b, Enable Nibble Re-map ***
360
361A[2] = 0b, Enable Horizontal Address Increment (RESET) ***
362A[2] = 1b, Enable Vertical Address Increment
363
364A[4] = 0b, Disable COM Re-map (RESET)
365A[4] = 1b, Enable COM Re-map
366
367A[6] = 0b, Disable SEG Split Odd Even ***
368A[6] = 1b, Enable SEG Split Odd Even (RESET)
369
370A[7] = 0b, Disable SEG left/right remap (RESET)
371A[7] = 1b, Enable SEG left/right remap
372
373*/
374 U8X8_CA(0xa0, 0xc3),
375 U8X8_CA(0xa1, 0), //Set Display Start Line
376 U8X8_CA(0xa2, 0), //Set Display Offset
377 U8X8_C(0xa4), //Normal Display
378 U8X8_CA(0xa8, 63), //Set Multiplex Ratio: (63 rows)
379 U8X8_CA(0xab, 1), //Set VDD regulator
380 U8X8_CA(0xad, 0x8e), //External /Internal IREF Selection, 9e: internal, 8e: external
381 U8X8_CA(0xb1, 0x22), //Set Phase Length, reset: 0x82
382 U8X8_CA(0xb3, 0xa0), //Display clock Divider
383 U8X8_CA(0xb6, 0x04), //Set Second precharge Period
384 U8X8_C(0xb9), //Set Linear LUT
385 U8X8_CA(0xbc, 0x1f), //Set pre-charge voltage level, 0..0x1f, 0x1f = 0.51*Vcc
386 U8X8_CA(0xbd, 1), //Pre-charge voltage capacitor Selection, 0: without, 1: with Vp capacitor
387 U8X8_CA(0xbe, 7), //Set cOM deselect voltage level, 7 = 0.86*Vcc
388 U8X8_DLY(1), /* delay 1ms */
389
390
391 U8X8_END_TRANSFER(), /* disable chip */
392 U8X8_END() /* end of sequence */
393};
394
395
396uint8_t u8x8_d_ssd1362_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
397{
398 switch(msg)
399 {
400 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
401 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1362_256x64_display_info);
402 break;
403 case U8X8_MSG_DISPLAY_INIT:
404 u8x8_d_helper_display_init(u8x8);
405 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_init_seq);
406 break;
407 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
408 if ( arg_int == 0 )
409 {
410 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_flip0_seq);
411 u8x8->x_offset = u8x8->display_info->default_x_offset;
412 }
413 else
414 {
415 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_flip1_seq);
416 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
417 }
418 break;
419
420 default:
421 return u8x8_d_ssd1362_common(u8x8, msg, arg_int, arg_ptr);
422 }
423 return 1;
424}
425
426/*=========================================================*/
427
428static const u8x8_display_info_t u8x8_ssd1362_206x36_display_info =
429{
430 /* chip_enable_level = */ 0,
431 /* chip_disable_level = */ 1,
432
433 /* post_chip_enable_wait_ns = */ 20,
434 /* pre_chip_disable_wait_ns = */ 10,
435 /* reset_pulse_width_ms = */ 100, /* ssd1362: 2 us */
436 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
437 /* sda_setup_time_ns = */ 50, /* ssd1362: 15ns, but cycle time is 100ns, so use 100/2 */
438 /* sck_pulse_width_ns = */ 50, /* ssd1362: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
439 /* sck_clock_hz = */ 10000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215), 10 MHz (issue 301) */
440 /* spi_mode = */ 0, /* active high, rising edge */
441 /* i2c_bus_clock_100kHz = */ 4,
442 /* data_setup_time_ns = */ 10,
443 /* write_pulse_width_ns = */ 150, /* ssd1362: cycle time is 300ns, so use 300/2 = 150 */
444 /* tile_width = */ 26, /* 26*8 = 208 */
445 /* tile_height = */ 5, /* 5*8 = 40 */
446 /* default_x_offset = */ 0, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
447 /* flipmode_x_offset = */ 25,
448 /* pixel_width = */ 206,
449 /* pixel_height = */ 36
450};
451
452
453/* https://github.com/olikraus/u8g2/issues/2051 */
454static const uint8_t u8x8_d_ssd1362_206x36_init_seq[] = {
455
456 U8X8_DLY(1),
457 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
458 U8X8_DLY(1),
459
460 U8X8_CA(0xfd, 0x12), /* unlock */
461 U8X8_C(0xae), /* display off */
462 U8X8_CA(0x23, 0x00), //POR 0x00; Disable fade mode
463 U8X8_CA(0x81, 0x9f), //Set contrast
464
465/*
466Re- map setting in Graphic Display Data RAM
467(GDDRAM)
468
469A[0] = 0b, Disable Column Address Re-map (RESET)
470A[0] = 1b, Enable Column Address Re-map ***
471
472A[1] = 0b, Disable Nibble Re-map (RESET)
473A[1] = 1b, Enable Nibble Re-map ***
474
475A[2] = 0b, Enable Horizontal Address Increment (RESET) ***
476A[2] = 1b, Enable Vertical Address Increment
477
478A[4] = 0b, Disable COM Re-map (RESET)
479A[4] = 1b, Enable COM Re-map
480
481A[6] = 0b, Disable SEG Split Odd Even ***
482A[6] = 1b, Enable SEG Split Odd Even (RESET)
483
484A[7] = 0b, Disable SEG left/right remap (RESET)
485A[7] = 1b, Enable SEG left/right remap
486
487*/
488 U8X8_CA(0xa0, 0xc3),
489 U8X8_CA(0xa1, 50), //Set Display Start Line
490 U8X8_CA(0xa2, 0), //Set Display Offset
491 U8X8_C(0xa4), //Normal Display
492 U8X8_CA(0xa8, 63), //Set Multiplex Ratio
493 U8X8_CA(0xab, 1), //Set VDD regulator
494 U8X8_CA(0xad, 0x8e), //External /Internal IREF Selection, 9e: internal, 8e: external
495 U8X8_CA(0xb1, 0x22), //Set Phase Length, reset: 0x82
496 U8X8_CA(0xb3, 0xa0), //Display clock Divider
497 U8X8_CA(0xb6, 0x04), //Set Second precharge Period
498 U8X8_C(0xb9), //Set Linear LUT
499 U8X8_CA(0xbc, 0x1f), //Set pre-charge voltage level, 0..0x1f, 0x1f = 0.51*Vcc
500 U8X8_CA(0xbd, 1), //Pre-charge voltage capacitor Selection, 0: without, 1: with Vp capacitor
501 U8X8_CA(0xbe, 7), //Set cOM deselect voltage level, 7 = 0.86*Vcc
502 U8X8_DLY(1), /* delay 1ms */
503
504
505 U8X8_END_TRANSFER(), /* disable chip */
506 U8X8_END() /* end of sequence */
507};
508
509
510uint8_t u8x8_d_ssd1362_206x36(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
511{
512 switch(msg)
513 {
514 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
515 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1362_206x36_display_info);
516 break;
517 case U8X8_MSG_DISPLAY_INIT:
518 u8x8_d_helper_display_init(u8x8);
519 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_206x36_init_seq);
520 break;
521 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
522 if ( arg_int == 0 )
523 {
524 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_flip0_seq);
525 u8x8->x_offset = u8x8->display_info->default_x_offset;
526 }
527 else
528 {
529 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1362_256x64_flip1_seq);
530 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
531 }
532 break;
533
534 default:
535 return u8x8_d_ssd1362_common_0_75(u8x8, msg, arg_int, arg_ptr);
536 }
537 return 1;
538}