Krolyxon
Commit 3120783

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8U8g2srcclibu8x8_d_ssd1322.c

872 lines · 30.0 KB · C

1/*
2
3 u8x8_d_ssd1322.c
4
5 Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
6
7 Copyright (c) 2016, 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 SSD1322:
36 480 x 128 dot matrix
37 16 gray scale
38
39
40*/
41#include "u8x8.h"
42
43
44
45
46static const uint8_t u8x8_d_ssd1322_powersave0_seq[] = {
47 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
48 U8X8_C(0x0af), /* ssd1322: display on */
49 U8X8_END_TRANSFER(), /* disable chip */
50 U8X8_END() /* end of sequence */
51};
52
53static const uint8_t u8x8_d_ssd1322_powersave1_seq[] = {
54 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
55 U8X8_C(0x0ae), /* ssd1322: display off */
56 U8X8_END_TRANSFER(), /* disable chip */
57 U8X8_END() /* end of sequence */
58};
59
60
61
62/* interpret b as a monochrome bit pattern, write value 15 for high bit and value 0 for a low bit */
63/* topbit (msb) is sent last */
64/* example: b = 0x083 will send 0xff, 0x00, 0x00, 0xf0 */
65
66/* 4 Jan 2017: I think this procedure not required any more. Delete? */
67/*
68static uint8_t u8x8_write_byte_to_16gr_device(u8x8_t *u8x8, uint8_t b)
69{
70 static uint8_t buf[4];
71 static uint8_t map[4] = { 0, 0x00f, 0x0f0, 0x0ff };
72 buf [3] = map[b & 3];
73 b>>=2;
74 buf [2] = map[b & 3];
75 b>>=2;
76 buf [1] = map[b & 3];
77 b>>=2;
78 buf [0] = map[b & 3];
79 return u8x8_cad_SendData(u8x8, 4, buf);
80}
81*/
82
83
84/*
85 input:
86 one tile (8 Bytes)
87 output:
88 Tile for SSD1325 (32 Bytes)
89*/
90
91static uint8_t u8x8_ssd1322_to32_dest_buf[32];
92
93static uint8_t *u8x8_ssd1322_8to32(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
94{
95 uint8_t v;
96 uint8_t a,b;
97 uint8_t i, j;
98 uint8_t *dest;
99
100 for( j = 0; j < 4; j++ )
101 {
102 dest = u8x8_ssd1322_to32_dest_buf;
103 dest += j;
104 a =*ptr;
105 ptr++;
106 b = *ptr;
107 ptr++;
108 for( i = 0; i < 8; i++ )
109 {
110 v = 0;
111 if ( a&1 ) v |= 0xf0;
112 if ( b&1 ) v |= 0x0f;
113 *dest = v;
114 dest+=4;
115 a >>= 1;
116 b >>= 1;
117 }
118 }
119
120 return u8x8_ssd1322_to32_dest_buf;
121}
122
123static uint8_t *u8x8_ssd1322_4to32(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
124{
125 uint8_t v;
126 uint8_t a;
127 uint8_t i, j;
128 uint8_t *dest;
129
130 for( j = 0; j < 4; j++ )
131 {
132 dest = u8x8_ssd1322_to32_dest_buf;
133 dest += j;
134 a =*ptr;
135 ptr++;
136 for( i = 0; i < 8; i++ )
137 {
138 v = 0;
139 if ( a&1 ) v = 0xff;
140 *dest = v;
141 dest+=4;
142 a >>= 1;
143 }
144 }
145
146 return u8x8_ssd1322_to32_dest_buf;
147}
148
149
150uint8_t u8x8_d_ssd1322_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
151{
152 uint8_t x;
153 uint8_t y, c;
154 uint8_t *ptr;
155 switch(msg)
156 {
157 /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
158 /*
159 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
160 break;
161 case U8X8_MSG_DISPLAY_INIT:
162 u8x8_d_helper_display_init(u8x8);
163 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_init_seq);
164 break;
165 */
166 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
167 if ( arg_int == 0 )
168 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_powersave0_seq);
169 else
170 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_powersave1_seq);
171 break;
172#ifdef U8X8_WITH_SET_CONTRAST
173 case U8X8_MSG_DISPLAY_SET_CONTRAST:
174 u8x8_cad_StartTransfer(u8x8);
175 u8x8_cad_SendCmd(u8x8, 0x0C1 );
176 u8x8_cad_SendArg(u8x8, arg_int ); /* ssd1322 has range from 0 to 255 */
177 u8x8_cad_EndTransfer(u8x8);
178 break;
179#endif
180 case U8X8_MSG_DISPLAY_DRAW_TILE:
181 u8x8_cad_StartTransfer(u8x8);
182 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
183 x *= 2; // only every 4th col can be addressed
184 x += u8x8->x_offset;
185
186 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
187 y *= 8;
188
189
190 u8x8_cad_SendCmd(u8x8, 0x075 ); /* set row address, moved out of the loop (issue 302) */
191 u8x8_cad_SendArg(u8x8, y);
192 u8x8_cad_SendArg(u8x8, y+7);
193
194 do
195 {
196 c = ((u8x8_tile_t *)arg_ptr)->cnt;
197 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
198
199 do
200 {
201 u8x8_cad_SendCmd(u8x8, 0x015 ); /* set column address */
202 u8x8_cad_SendArg(u8x8, x ); /* start */
203 u8x8_cad_SendArg(u8x8, x+1 ); /* end */
204
205 u8x8_cad_SendCmd(u8x8, 0x05c ); /* write to ram */
206
207 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1322_8to32(u8x8, ptr));
208
209 ptr += 8;
210 x += 2;
211 c--;
212 } while( c > 0 );
213
214 //x += 2;
215 arg_int--;
216 } while( arg_int > 0 );
217
218 u8x8_cad_EndTransfer(u8x8);
219 break;
220 default:
221 return 0;
222 }
223 return 1;
224}
225
226/*=========================================================*/
227
228static const uint8_t u8x8_d_ssd1322_256x64_flip0_seq[] = {
229 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
230 U8X8_CAA(0x0a0, 0x006, 0x011), /* remap */
231 U8X8_END_TRANSFER(), /* disable chip */
232 U8X8_END() /* end of sequence */
233};
234
235static const uint8_t u8x8_d_ssd1322_256x64_flip1_seq[] = {
236 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
237 U8X8_CAA(0x0a0, 0x014, 0x011), /* remap */
238 U8X8_END_TRANSFER(), /* disable chip */
239 U8X8_END() /* end of sequence */
240};
241
242static const u8x8_display_info_t u8x8_ssd1322_256x64_display_info =
243{
244 /* chip_enable_level = */ 0,
245 /* chip_disable_level = */ 1,
246
247 /* post_chip_enable_wait_ns = */ 20,
248 /* pre_chip_disable_wait_ns = */ 10,
249 /* reset_pulse_width_ms = */ 100, /* SSD1322: 2 us */
250 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
251 /* sda_setup_time_ns = */ 50, /* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
252 /* sck_pulse_width_ns = */ 50, /* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
253 /* 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) */
254 /* spi_mode = */ 0, /* active high, rising edge */
255 /* i2c_bus_clock_100kHz = */ 4,
256 /* data_setup_time_ns = */ 10,
257 /* write_pulse_width_ns = */ 150, /* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
258 /* tile_width = */ 32, /* 256 pixel, so we require 32 bytes for this */
259 /* tile_height = */ 8,
260 /* default_x_offset = */ 0x01c, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
261 /* flipmode_x_offset = */ 0x01c,
262 /* pixel_width = */ 256,
263 /* pixel_height = */ 64
264};
265
266
267static const uint8_t u8x8_d_ssd1322_256x64_init_seq[] = {
268
269 U8X8_DLY(1),
270 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
271 U8X8_DLY(1),
272
273 U8X8_CA(0xfd, 0x12), /* unlock */
274 U8X8_C(0xae), /* display off */
275 U8X8_CA(0xb3, 0x91), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
276 U8X8_CA(0xca, 0x3f), /* multiplex ratio 1/64 Duty (0x0F~0x3F) */
277 U8X8_CA(0xa2, 0x00), /* display offset, shift mapping ram counter */
278 U8X8_CA(0xa1, 0x00), /* display start line */
279 //U8X8_CAA(0xa0, 0x14, 0x11), /* Set Re-Map / Dual COM Line Mode */
280 U8X8_CAA(0xa0, 0x06, 0x011), /* Set Re-Map / Dual COM Line Mode */
281 U8X8_CA(0xab, 0x01), /* Enable Internal VDD Regulator */
282 U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd), /* Display Enhancement A */
283 U8X8_CA(0xc1, 0x9f), /* contrast */
284 U8X8_CA(0xc7, 0x0f), /* Set Scale Factor of Segment Output Current Control */
285 U8X8_C(0xb9), /* linear grayscale */
286 U8X8_CA(0xb1, 0xe2), /* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */
287 U8X8_CAA(0xd1, 0x082|0x020, 0x020), /* Display Enhancement B */
288 U8X8_CA(0xbb, 0x1f), /* precharge voltage */
289 U8X8_CA(0xb6, 0x08), /* precharge period */
290 U8X8_CA(0xbe, 0x07), /* vcomh */
291 U8X8_C(0xa6), /* normal display */
292 U8X8_C(0xa9), /* exit partial display */
293
294
295 U8X8_DLY(1), /* delay 2ms */
296
297
298 U8X8_END_TRANSFER(), /* disable chip */
299 U8X8_END() /* end of sequence */
300};
301
302
303uint8_t u8x8_d_ssd1322_nhd_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
304{
305 switch(msg)
306 {
307 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
308 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_256x64_display_info);
309 break;
310 case U8X8_MSG_DISPLAY_INIT:
311 u8x8_d_helper_display_init(u8x8);
312 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_init_seq);
313 break;
314 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
315 if ( arg_int == 0 )
316 {
317 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip0_seq);
318 u8x8->x_offset = u8x8->display_info->default_x_offset;
319 }
320 else
321 {
322 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip1_seq);
323 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
324 }
325 break;
326
327 default:
328 return u8x8_d_ssd1322_common(u8x8, msg, arg_int, arg_ptr);
329 }
330 return 1;
331}
332
333/*=========================================================*/
334/*
335https://github.com/olikraus/u8g2/issues/2386
336*/
337
338
339static const u8x8_display_info_t u8x8_ssd1322_zjy_256x64_display_info =
340{
341 /* chip_enable_level = */ 0,
342 /* chip_disable_level = */ 1,
343
344 /* post_chip_enable_wait_ns = */ 20,
345 /* pre_chip_disable_wait_ns = */ 10,
346 /* reset_pulse_width_ms = */ 100, /* SSD1322: 2 us */
347 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
348 /* sda_setup_time_ns = */ 50, /* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
349 /* sck_pulse_width_ns = */ 50, /* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
350 /* 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) */
351 /* spi_mode = */ 0, /* active high, rising edge */
352 /* i2c_bus_clock_100kHz = */ 4,
353 /* data_setup_time_ns = */ 10,
354 /* write_pulse_width_ns = */ 150, /* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
355 /* tile_width = */ 32, /* 256 pixel, so we require 32 bytes for this */
356 /* tile_height = */ 8,
357 /* default_x_offset = */ 0x018, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
358 /* flipmode_x_offset = */ 0x018,
359 /* pixel_width = */ 256,
360 /* pixel_height = */ 64
361};
362
363
364static const uint8_t u8x8_d_ssd1322_zjy_256x64_init_seq[] = {
365
366 U8X8_DLY(1),
367 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
368 U8X8_DLY(1),
369
370 U8X8_CA(0xfd, 0x12), /* unlock */
371 U8X8_C(0xae), /* display off */
372 U8X8_CA(0xb3, 0x91), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
373 U8X8_CA(0xca, 0x3f), /* multiplex ratio 1/64 Duty (0x0F~0x3F) */
374 U8X8_CA(0xa2, 0x00), /* display offset, shift mapping ram counter */
375 U8X8_CA(0xa1, 0x00), /* display start line */
376 //U8X8_CAA(0xa0, 0x14, 0x11), /* Set Re-Map / Dual COM Line Mode */
377 U8X8_CAA(0xa0, 0x16, 0x011), /* Set Re-Map / Dual COM Line Mode */
378 U8X8_CA(0xab, 0x01), /* Enable Internal VDD Regulator */
379 U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd), /* Display Enhancement A */
380 U8X8_CA(0xc1, 0x9f), /* contrast */
381 U8X8_CA(0xc7, 0x0f), /* Set Scale Factor of Segment Output Current Control */
382 U8X8_C(0xb9), /* linear grayscale */
383 U8X8_CA(0xb1, 0xe2), /* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */
384 U8X8_CAA(0xd1, 0x082|0x020, 0x020), /* Display Enhancement B */
385 U8X8_CA(0xbb, 0x1f), /* precharge voltage */
386 U8X8_CA(0xb6, 0x08), /* precharge period */
387 U8X8_CA(0xbe, 0x07), /* vcomh */
388 U8X8_C(0xa6), /* normal display */
389 U8X8_C(0xa9), /* exit partial display */
390
391
392 U8X8_DLY(1), /* delay 2ms */
393
394
395 U8X8_END_TRANSFER(), /* disable chip */
396 U8X8_END() /* end of sequence */
397};
398
399
400uint8_t u8x8_d_ssd1322_zjy_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
401{
402 switch(msg)
403 {
404 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
405 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_zjy_256x64_display_info);
406 break;
407 case U8X8_MSG_DISPLAY_INIT:
408 u8x8_d_helper_display_init(u8x8);
409 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_zjy_256x64_init_seq);
410 break;
411 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
412 if ( arg_int == 0 )
413 {
414 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip0_seq);
415 u8x8->x_offset = u8x8->display_info->default_x_offset;
416 }
417 else
418 {
419 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip1_seq);
420 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
421 }
422 break;
423
424 default:
425 return u8x8_d_ssd1322_common(u8x8, msg, arg_int, arg_ptr);
426 }
427 return 1;
428}
429
430
431/*=========================================================*/
432/*
433https://github.com/olikraus/u8g2/issues/2092
434*/
435
436
437static const u8x8_display_info_t u8x8_ssd1322_240x128_display_info =
438{
439 /* chip_enable_level = */ 0,
440 /* chip_disable_level = */ 1,
441
442 /* post_chip_enable_wait_ns = */ 20,
443 /* pre_chip_disable_wait_ns = */ 10,
444 /* reset_pulse_width_ms = */ 100, /* SSD1322: 2 us */
445 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
446 /* sda_setup_time_ns = */ 50, /* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
447 /* sck_pulse_width_ns = */ 50, /* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
448 /* 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) */
449 /* spi_mode = */ 0, /* active high, rising edge */
450 /* i2c_bus_clock_100kHz = */ 4,
451 /* data_setup_time_ns = */ 10,
452 /* write_pulse_width_ns = */ 150, /* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
453 /* tile_width = */ 30, /* 256 pixel, so we require 32 bytes for this */
454 /* tile_height = */ 16,
455 /* default_x_offset = */ 24, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
456 /* flipmode_x_offset = */ 0x000,
457 /* pixel_width = */ 240,
458 /* pixel_height = */ 128
459};
460
461
462static const uint8_t u8x8_d_ssd1322_240x128_init_seq[] = {
463
464 U8X8_DLY(1),
465 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
466 U8X8_DLY(1),
467
468 U8X8_CA(0xfd, 0x12), /* unlock */
469 U8X8_C(0xae), /* display off */
470 U8X8_CA(0xb3, 0x91), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
471 U8X8_CA(0xca, 0x7f), /* multiplex ratio 1/128 Duty (0x0F~0x7F) */
472 U8X8_CA(0xa2, 0x00), /* display offset, shift mapping ram counter */
473 U8X8_CA(0xa1, 0x00), /* display start line */
474 //U8X8_CAA(0xa0, 0x14, 0x11), /* Set Re-Map / Dual COM Line Mode */
475 U8X8_CAA(0xa0, 0x36, 0x011), /* Set Re-Map / Dual COM Line Mode */
476 U8X8_CA(0xab, 0x01), /* Enable Internal VDD Regulator */
477 U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd), /* Display Enhancement A */
478 U8X8_CA(0xc1, 0x9f), /* contrast */
479 U8X8_CA(0xc7, 0x0f), /* Set Scale Factor of Segment Output Current Control */
480 U8X8_C(0xb9), /* linear grayscale */
481 U8X8_CA(0xb1, 0xe2), /* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */
482 U8X8_CAA(0xd1, 0x082|0x020, 0x020), /* Display Enhancement B */
483 U8X8_CA(0xbb, 0x1f), /* precharge voltage */
484 U8X8_CA(0xb6, 0x08), /* precharge period */
485 U8X8_CA(0xbe, 0x07), /* vcomh */
486 U8X8_C(0xa6), /* normal display */
487 U8X8_C(0xa9), /* exit partial display */
488
489
490 U8X8_DLY(1), /* delay 2ms */
491
492
493 U8X8_END_TRANSFER(), /* disable chip */
494 U8X8_END() /* end of sequence */
495};
496
497
498uint8_t u8x8_d_ssd1322_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
499{
500 switch(msg)
501 {
502 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
503 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_240x128_display_info);
504 break;
505 case U8X8_MSG_DISPLAY_INIT:
506 u8x8_d_helper_display_init(u8x8);
507 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_240x128_init_seq);
508 break;
509 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
510 if ( arg_int == 0 )
511 {
512 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip0_seq);
513 u8x8->x_offset = u8x8->display_info->default_x_offset;
514 }
515 else
516 {
517 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip1_seq);
518 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
519 }
520 break;
521
522 default:
523 return u8x8_d_ssd1322_common(u8x8, msg, arg_int, arg_ptr);
524 }
525 return 1;
526}
527
528
529
530/*=========================================================*/
531/*
532
533 Top Win OLED 240x128
534
535 Discussion: https://github.com/olikraus/u8g2/discussions/2308
536 Issue: https://github.com/olikraus/u8g2/issues/2310
537
538 The main difference to the previous device seems to be the dual com line mode
539 (0x0a0 command)
540
541*/
542
543static const uint8_t u8x8_d_ssd1322_topwin_240x128_flip0_seq[] = {
544 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
545 U8X8_CAA(0x0a0, 0x036, 0x001), /* remap */
546 U8X8_END_TRANSFER(), /* disable chip */
547 U8X8_END() /* end of sequence */
548};
549
550static const uint8_t u8x8_d_ssd1322_topwin_240x128_flip1_seq[] = {
551 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
552 U8X8_CAA(0x0a0, 0x024, 0x001), /* remap */
553 U8X8_END_TRANSFER(), /* disable chip */
554 U8X8_END() /* end of sequence */
555};
556
557
558static const u8x8_display_info_t u8x8_ssd1322_topwin_240x128_display_info =
559{
560 /* chip_enable_level = */ 0,
561 /* chip_disable_level = */ 1,
562
563 /* post_chip_enable_wait_ns = */ 20,
564 /* pre_chip_disable_wait_ns = */ 10,
565 /* reset_pulse_width_ms = */ 100, /* SSD1322: 2 us */
566 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
567 /* sda_setup_time_ns = */ 50, /* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
568 /* sck_pulse_width_ns = */ 50, /* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
569 /* 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) */
570 /* spi_mode = */ 0, /* active high, rising edge */
571 /* i2c_bus_clock_100kHz = */ 4,
572 /* data_setup_time_ns = */ 10,
573 /* write_pulse_width_ns = */ 150, /* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
574 /* tile_width = */ 30, /* 240 pixel, so we require 30 bytes for this */
575 /* tile_height = */ 16,
576 /* default_x_offset = */ 24, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
577 /* flipmode_x_offset = */ 0x000,
578 /* pixel_width = */ 240,
579 /* pixel_height = */ 128
580};
581
582
583static const uint8_t u8x8_d_ssd1322_topwin_240x128_init_seq[] = {
584
585 U8X8_DLY(1),
586 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
587 U8X8_DLY(1),
588
589 U8X8_CA(0xfd, 0x12), /* unlock */
590 U8X8_C(0xae), /* display off */
591 U8X8_CA(0xb3, 0x91), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
592 U8X8_CA(0xca, 0x7f), /* multiplex ratio 1/128 Duty (0x0F~0x7F) */
593 U8X8_CA(0xa2, 0x00), /* display offset, shift mapping ram counter */
594 U8X8_CA(0xa1, 0x00), /* display start line */
595 U8X8_CAA(0xa0, 0x36, 0x001), /* Set Re-Map / Dual COM Line Mode, https://github.com/olikraus/u8g2/discussions/2308 */
596 U8X8_CA(0xab, 0x01), /* Enable Internal VDD Regulator */
597 U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd), /* Display Enhancement A */
598 U8X8_CA(0xc1, 0x9f), /* contrast */
599 U8X8_CA(0xc7, 0x0f), /* Set Scale Factor of Segment Output Current Control */
600 U8X8_C(0xb9), /* linear grayscale */
601 U8X8_CA(0xb1, 0xe2), /* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */
602 U8X8_CAA(0xd1, 0x082|0x020, 0x020), /* Display Enhancement B */
603 U8X8_CA(0xbb, 0x1f), /* precharge voltage */
604 U8X8_CA(0xb6, 0x08), /* precharge period */
605 U8X8_CA(0xbe, 0x07), /* vcomh */
606 U8X8_C(0xa6), /* normal display */
607 U8X8_C(0xa9), /* exit partial display */
608
609
610 U8X8_DLY(1), /* delay 2ms */
611
612
613 U8X8_END_TRANSFER(), /* disable chip */
614 U8X8_END() /* end of sequence */
615};
616
617
618uint8_t u8x8_d_ssd1322_topwin_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
619{
620 switch(msg)
621 {
622 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
623 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_topwin_240x128_display_info);
624 break;
625 case U8X8_MSG_DISPLAY_INIT:
626 u8x8_d_helper_display_init(u8x8);
627 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_topwin_240x128_init_seq);
628 break;
629 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
630 if ( arg_int == 0 )
631 {
632 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_topwin_240x128_flip0_seq);
633 u8x8->x_offset = u8x8->display_info->default_x_offset;
634 }
635 else
636 {
637 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_topwin_240x128_flip1_seq);
638 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
639 }
640 break;
641
642 default:
643 return u8x8_d_ssd1322_common(u8x8, msg, arg_int, arg_ptr);
644 }
645 return 1;
646}
647
648
649/*=========================================================*/
650/*
651 NHD-2.7-12864WDW3-M
652 http://www.newhavendisplay.com/nhd2712864wdw3m-p-9546.html
653 http://www.newhavendisplay.com/specs/NHD-2.7-12864WDW3-M.pdf
654
655 It looks like that only every second pixel is connected to the OLED
656*/
657
658uint8_t u8x8_d_ssd1322_common2(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
659{
660 uint8_t x;
661 uint8_t y, c;
662 uint8_t *ptr;
663 switch(msg)
664 {
665 /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
666 /*
667 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
668 break;
669 case U8X8_MSG_DISPLAY_INIT:
670 u8x8_d_helper_display_init(u8x8);
671 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_init_seq);
672 break;
673 */
674 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
675 if ( arg_int == 0 )
676 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_powersave0_seq);
677 else
678 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_powersave1_seq);
679 break;
680#ifdef U8X8_WITH_SET_CONTRAST
681 case U8X8_MSG_DISPLAY_SET_CONTRAST:
682 u8x8_cad_StartTransfer(u8x8);
683 u8x8_cad_SendCmd(u8x8, 0x0C1 );
684 u8x8_cad_SendArg(u8x8, arg_int ); /* ssd1322 has range from 0 to 255 */
685 u8x8_cad_EndTransfer(u8x8);
686 break;
687#endif
688 case U8X8_MSG_DISPLAY_DRAW_TILE:
689 u8x8_cad_StartTransfer(u8x8);
690 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
691 x *= 2; // only every 4th col can be addressed
692 x *= 2; // only every second pixel is used in the 128x64 NHD OLED
693
694 x += u8x8->x_offset;
695
696 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
697 y *= 8;
698
699 u8x8_cad_SendCmd(u8x8, 0x075 ); /* set row address, moved out of the loop (issue 302) */
700 u8x8_cad_SendArg(u8x8, y);
701 u8x8_cad_SendArg(u8x8, y+7);
702
703 do
704 {
705 c = ((u8x8_tile_t *)arg_ptr)->cnt;
706 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
707
708 do
709 {
710 u8x8_cad_SendCmd(u8x8, 0x015 ); /* set column address */
711 u8x8_cad_SendArg(u8x8, x ); /* start */
712 u8x8_cad_SendArg(u8x8, x+1 ); /* end */
713 u8x8_cad_SendCmd(u8x8, 0x05c ); /* write to ram */
714 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1322_4to32(u8x8, ptr));
715 ptr += 4;
716 x += 2;
717
718 u8x8_cad_SendCmd(u8x8, 0x015 ); /* set column address */
719 u8x8_cad_SendArg(u8x8, x ); /* start */
720 u8x8_cad_SendArg(u8x8, x+1 ); /* end */
721 u8x8_cad_SendCmd(u8x8, 0x05c ); /* write to ram */
722 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1322_4to32(u8x8, ptr));
723 ptr += 4;
724 x += 2;
725
726 c--;
727 } while( c > 0 );
728
729 //x += 2;
730 arg_int--;
731 } while( arg_int > 0 );
732
733 u8x8_cad_EndTransfer(u8x8);
734 break;
735 default:
736 return 0;
737 }
738 return 1;
739}
740
741
742static const uint8_t u8x8_d_ssd1322_128x64_flip0_seq[] = {
743 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
744 U8X8_CAA(0x0a0, 0x016, 0x011), /* remap */
745 U8X8_END_TRANSFER(), /* disable chip */
746 U8X8_END() /* end of sequence */
747};
748
749static const uint8_t u8x8_d_ssd1322_128x64_flip1_seq[] = {
750 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
751 U8X8_CAA(0x0a0, 0x004, 0x011), /* remap */
752 U8X8_END_TRANSFER(), /* disable chip */
753 U8X8_END() /* end of sequence */
754};
755
756static const u8x8_display_info_t u8x8_ssd1322_128x64_display_info =
757{
758 /* chip_enable_level = */ 0,
759 /* chip_disable_level = */ 1,
760
761 /* post_chip_enable_wait_ns = */ 20,
762 /* pre_chip_disable_wait_ns = */ 10,
763 /* reset_pulse_width_ms = */ 100, /* SSD1322: 2 us */
764 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
765 /* sda_setup_time_ns = */ 50, /* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
766 /* sck_pulse_width_ns = */ 50, /* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
767 /* 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) */
768 /* spi_mode = */ 0, /* active high, rising edge */
769 /* i2c_bus_clock_100kHz = */ 4,
770 /* data_setup_time_ns = */ 10,
771 /* write_pulse_width_ns = */ 150, /* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
772 /* tile_width = */ 16, /* 128 pixel */
773 /* tile_height = */ 8,
774 /* default_x_offset = */ 28, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
775 /* flipmode_x_offset = */ 28,
776 /* pixel_width = */ 128,
777 /* pixel_height = */ 64
778};
779
780
781static const uint8_t u8x8_d_ssd1322_128x64_init_seq[] = {
782
783 U8X8_DLY(1),
784 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
785 U8X8_DLY(1),
786
787 U8X8_CA(0xfd, 0x12), /* unlock */
788 U8X8_C(0xae), /* display off */
789 U8X8_CA(0xb3, 0x91), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
790 U8X8_CA(0xca, 0x3f), /* multiplex ratio 1/64 Duty (0x0F~0x3F) */
791 U8X8_CA(0xa2, 0x00), /* display offset, shift mapping ram counter */
792
793 U8X8_CA(0xa1, 0x00), /* display start line */
794 U8X8_CA(0xab, 0x01), /* Enable Internal VDD Regulator */
795/*
796 A[0]=0b, Horizontal address increment [reset] ***
797 A[0]=1b, Vertical address increment
798
799 A[1]=0b, Disable Column Address Re-map [reset]
800 A[1]=1b, Enable Column Address Re-map ***
801
802 A[2]=0b, Disable Nibble Re-map [reset]
803 A[2]=1b, Enable Nibble Re-map ***
804
805 A[4]=0b, Scan from COM0 to COM[N –1] [reset]
806 A[4]=1b, Scan from COM[N-1] to COM0, where N is the ***
807
808 Multiplex ratio
809 A[5]=0b, Disable COM Split Odd Even [reset] ***
810 A[5]=1b, Enable COM Split Odd Even
811
812 B[4], Enable / disable Dual COM Line mode
813 0b, Disable Dual COM mode [reset]
814 1b, Enable Dual COM mode (MUX ≤ 63)
815
816 0x16 = 00010110
817*/
818 //U8X8_CAA(0xa0, 0x14, 0x11), /* Set Re-Map / Dual COM Line Mode */
819 //U8X8_CAA(0xa0, 0x06, 0x011), /* Set Re-Map / Dual COM Line Mode */
820 U8X8_CAA(0xa0, 0x16, 0x011), /* Set Re-Map / Dual COM Line Mode (NHD-2.7-12864WDW3-M datasheet) */
821 U8X8_CA(0xc7, 0x0f), /* Set Scale Factor of Segment Output Current Control */
822 U8X8_CA(0xc1, 0x9f), /* contrast */
823 //U8X8_CA(0xb1, 0xe2), /* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */
824 U8X8_CA(0xb1, 0xf2), /* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment (NHD-2.7-12864WDW3-M datasheet) */
825 U8X8_CA(0xbb, 0x1f), /* precharge voltage */
826 //U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd), /* Display Enhancement A */
827 U8X8_CAA(0xb4, 0xa0, 0x0fd), /* Display Enhancement A (NHD-2.7-12864WDW3-M datasheet) */
828 U8X8_CA(0xbe, 0x04), /* vcomh (NHD-2.7-12864WDW3-M datasheet) */
829 U8X8_C(0xb9), /* linear grayscale */
830 //U8X8_CAA(0xd1, 0x082|0x020, 0x020), /* Display Enhancement B */
831 //U8X8_CA(0xb6, 0x08), /* precharge period */
832 U8X8_C(0xa6), /* normal display */
833 U8X8_C(0xa9), /* exit partial display */
834
835
836 U8X8_DLY(1), /* delay 2ms */
837
838
839 U8X8_END_TRANSFER(), /* disable chip */
840 U8X8_END() /* end of sequence */
841};
842
843uint8_t u8x8_d_ssd1322_nhd_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
844{
845 switch(msg)
846 {
847 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
848 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_128x64_display_info);
849 break;
850 case U8X8_MSG_DISPLAY_INIT:
851 u8x8_d_helper_display_init(u8x8);
852 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_128x64_init_seq);
853 break;
854 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
855 if ( arg_int == 0 )
856 {
857 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_128x64_flip0_seq);
858 u8x8->x_offset = u8x8->display_info->default_x_offset;
859 }
860 else
861 {
862 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_128x64_flip1_seq);
863 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
864 }
865 break;
866
867 default:
868 return u8x8_d_ssd1322_common2(u8x8, msg, arg_int, arg_ptr);
869 }
870 return 1;
871}
872