Krolyxon
Commit 3120783

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8U8g2srcclibu8x8_d_ssd1320.c

888 lines · 31.9 KB · C

1/*
2
3 u8x8_d_ssd1320.c
4
5 Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
6
7 Copyright (c) 2020, 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 https://github.com/olikraus/u8g2/issues/1351
36 SSD1320:
37 160 x 160 dot matrix
38 16 gray scale
39
40 Adapted from u8x8_d_ssd1322.c with the command set of the SSD1320 controller
41 "official" procedure is described here: https://github.com/olikraus/u8g2/wiki/internal
42
43 NOTE: U8x8 does NOT work! --> not clear, needs to be checked
44
45
46 https://github.com/olikraus/u8g2/issues/1816
47
48*/
49
50#include "u8x8.h"
51
52static const uint8_t u8x8_d_ssd1320_cs1_160x132_nhd_powersave0_seq[] = {
53 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
54 U8X8_C(0x0af), /* ssd1320: display on */
55 U8X8_END_TRANSFER(), /* disable chip */
56 U8X8_END() /* end of sequence */
57};
58
59static const uint8_t u8x8_d_ssd1320_cs1_160x132_nhd_powersave1_seq[] = {
60 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
61 U8X8_C(0x0ae), /* ssd1320: display off */
62 U8X8_END_TRANSFER(), /* disable chip */
63 U8X8_END() /* end of sequence */
64};
65
66
67/*
68 input:32
69 one tile (8 Bytes; 1 byte per column)
70 output:
71 Tile for SSD1320 (32 Bytes)
72
73*/
74
75static uint8_t u8x8_ssd1320_to32_dest_buf[32];
76
77
78
79static uint8_t *u8x8_ssd1320_8to32(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
80{
81 uint8_t v;
82 uint8_t a,b;
83 uint8_t i, j;
84 uint8_t *dest;
85
86 for( j = 0; j < 4; j++ )
87 {
88 dest = u8x8_ssd1320_to32_dest_buf;
89 dest += j;
90 a =*ptr;
91 ptr++;
92 b = *ptr;
93 ptr++;
94 for( i = 0; i < 8; i++ )
95 {
96 v = 0;
97 if ( a&1 ) v |= 0x0f;
98 if ( b&1 ) v |= 0xf0;
99 *dest = v;
100 dest+=4;
101 a >>= 1;
102 b >>= 1;
103 }
104 }
105 return u8x8_ssd1320_to32_dest_buf;
106}
107
108uint8_t u8x8_d_ssd1320_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
109{
110 uint8_t x;
111 uint8_t y, c;
112 uint8_t *ptr;
113 switch(msg)
114 {
115 /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
116 /*
117 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
118 break;
119 case U8X8_MSG_DISPLAY_INIT:
120 u8x8_d_helper_display_init(u8x8);
121 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_256x64_init_seq);
122 break;
123 */
124 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
125 if ( arg_int == 0 )
126 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_nhd_powersave0_seq);
127 else
128 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_nhd_powersave1_seq);
129 break;
130
131#ifdef U8X8_WITH_SET_CONTRAST
132 case U8X8_MSG_DISPLAY_SET_CONTRAST:
133 u8x8_cad_StartTransfer(u8x8);
134 u8x8_cad_SendCmd(u8x8, 0x081 );
135 u8x8_cad_SendArg(u8x8, arg_int ); /* ssd1320 has range from 1 to 255 */
136 u8x8_cad_EndTransfer(u8x8);
137 break;
138#endif
139
140 case U8X8_MSG_DISPLAY_DRAW_TILE:
141 u8x8_cad_StartTransfer(u8x8);
142 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
143 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
144 x += u8x8->x_offset;
145
146 y *= 8;
147
148
149 u8x8_cad_SendCmd(u8x8, 0x022 ); /* set row address, moved out of the loop (issue 302) */
150 u8x8_cad_SendArg(u8x8, y);
151 u8x8_cad_SendArg(u8x8, y+7);
152
153 do {
154 c = ((u8x8_tile_t *)arg_ptr)->cnt;
155 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
156
157 do {
158 u8x8_cad_SendCmd(u8x8, 0x021 ); /* set column address */
159 u8x8_cad_SendArg(u8x8, x ); /* start */
160 u8x8_cad_SendArg(u8x8, x+3 ); /* end */
161
162 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1320_8to32(u8x8, ptr));
163
164 ptr += 8;
165 x += 4;
166 c--;
167 } while( c > 0 );
168
169 //x += 2;
170 arg_int--;
171 } while( arg_int > 0 );
172
173 u8x8_cad_EndTransfer(u8x8);
174 break;
175
176 default:
177 return 0;
178 }
179 return 1;
180}
181
182
183
184
185static uint8_t *u8x8_ssd1320_8to32_2(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
186{
187 uint8_t v;
188 uint8_t a,b;
189 uint8_t i, j;
190 uint8_t *dest;
191
192 for( j = 0; j < 4; j++ )
193 {
194 dest = u8x8_ssd1320_to32_dest_buf;
195 dest += j;
196 a =*ptr;
197 ptr++;
198 b = *ptr;
199 ptr++;
200 for( i = 0; i < 8; i++ )
201 {
202 v = 0;
203 if ( a&1 ) v |= 0xf0; // changed from 0x0f to 0xf0, https://github.com/olikraus/u8g2/issues/1816
204 if ( b&1 ) v |= 0x0f; // changed from 0xf0 to 0x0f, https://github.com/olikraus/u8g2/issues/1816
205 *dest = v;
206 dest+=4;
207 a >>= 1;
208 b >>= 1;
209 }
210 }
211 return u8x8_ssd1320_to32_dest_buf;
212}
213
214uint8_t u8x8_d_ssd1320_common_2(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
215{
216 uint8_t x;
217 uint8_t y, c;
218 uint8_t *ptr;
219 switch(msg)
220 {
221 /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
222 /*
223 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
224 break;
225 case U8X8_MSG_DISPLAY_INIT:
226 u8x8_d_helper_display_init(u8x8);
227 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_256x64_init_seq);
228 break;
229 */
230 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
231 if ( arg_int == 0 )
232 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_nhd_powersave0_seq);
233 else
234 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_nhd_powersave1_seq);
235 break;
236
237#ifdef U8X8_WITH_SET_CONTRAST
238 case U8X8_MSG_DISPLAY_SET_CONTRAST:
239 u8x8_cad_StartTransfer(u8x8);
240 u8x8_cad_SendCmd(u8x8, 0x081 );
241 u8x8_cad_SendArg(u8x8, arg_int ); /* ssd1320 has range from 1 to 255 */
242 u8x8_cad_EndTransfer(u8x8);
243 break;
244#endif
245
246 case U8X8_MSG_DISPLAY_DRAW_TILE:
247 u8x8_cad_StartTransfer(u8x8);
248 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
249 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
250 x += u8x8->x_offset;
251
252 y *= 8;
253
254
255 u8x8_cad_SendCmd(u8x8, 0x022 ); /* set row address, moved out of the loop (issue 302) */
256 u8x8_cad_SendArg(u8x8, y);
257 u8x8_cad_SendArg(u8x8, y+7);
258
259 do {
260 c = ((u8x8_tile_t *)arg_ptr)->cnt;
261 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
262
263 do {
264 u8x8_cad_SendCmd(u8x8, 0x021 ); /* set column address */
265 u8x8_cad_SendArg(u8x8, x ); /* start */
266 u8x8_cad_SendArg(u8x8, x+3 ); /* end */
267
268 u8x8_cad_SendData(u8x8, 32, u8x8_ssd1320_8to32_2(u8x8, ptr));
269
270 ptr += 8;
271 x += 4;
272 c--;
273 } while( c > 0 );
274
275 //x += 2;
276 arg_int--;
277 } while( arg_int > 0 );
278
279 u8x8_cad_EndTransfer(u8x8);
280 break;
281
282 default:
283 return 0;
284 }
285 return 1;
286}
287
288
289/*=========================================================*/
290/* 160x32 */
291
292static const uint8_t u8x8_d_ssd1320_cs1_160x32_nhd_flip0_seq[] = {
293 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
294 U8X8_C(0x0a0), /* remap */
295 U8X8_END_TRANSFER(), /* disable chip */
296 U8X8_END() /* end of sequence */
297};
298
299static const uint8_t u8x8_d_ssd1320_cs1_160x32_nhd_flip1_seq[] = {
300 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
301 U8X8_C(0x0a1), /* remap */
302 U8X8_END_TRANSFER(), /* disable chip */
303 U8X8_END() /* end of sequence */
304};
305
306static const u8x8_display_info_t u8x8_d_ssd1320_cs1_160x32_display_info =
307{
308 /* chip_enable_level = */ 0,
309 /* chip_disable_level = */ 1,
310
311 /* post_chip_enable_wait_ns = */ 20,
312 /* pre_chip_disable_wait_ns = */ 10,
313 /* reset_pulse_width_ms = */ 100, /* ssd1320: 2 us */
314 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
315 /* sda_setup_time_ns = */ 50, /* ssd1320: 15ns, but cycle time is 100ns, so use 100/2 */
316 /* sck_pulse_width_ns = */ 50, /* ssd1320: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
317 /* 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) */
318 /* spi_mode = */ 0, /* active high, rising edge */
319 /* i2c_bus_clock_100kHz = */ 4,
320 /* data_setup_time_ns = */ 10,
321 /* write_pulse_width_ns = */ 150, /* ssd1320: cycle time is 300ns, so use 300/2 = 150 */
322 /* tile_width = */ 20, /* 160 pixel, so we require 20 bytes for this */
323 /* tile_height = */ 4,
324 /* default_x_offset = */ 0, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
325 /* flipmode_x_offset = */ 0,
326 /* pixel_width = */ 160,
327 /* pixel_height = */ 32
328};
329
330// initialisation sequence from the Arduino Library
331// (see https://github.com/sparkfun/SparkFun_SSD1320_OLED_Arduino_Library)
332static const uint8_t u8x8_d_ssd1320_cs1_160x32_init_seq[] = {
333
334 U8X8_DLY(1),
335 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
336 U8X8_DLY(1),
337
338 U8X8_C(0xae), /* display off */
339 U8X8_CA(0xd5, 0xC2), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
340 U8X8_CA(0xa8, 0x1f), /* multiplex ratio 1/64 Duty (0x0F~0x3F) */
341 U8X8_CA(0xa2, 0x00), /* display start line */
342
343 U8X8_C(0xa0), /* Set Segment Re-Map: column address 0 mapped to SEG0 CS1 */
344 // U8X8_C(0xa1), /* Set Segment Re-Map: column address 0 mapped to SEG0 CS2 */
345
346 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode CS1 */
347 // U8X8_C(0xc0), /* Set COM Output Scan Direction: normal mode CS2 */
348
349 U8X8_CA(0xd3, 0x72), /* CS1 */
350 // U8X8_CA(0xd3, 0x92), /* CS2 */
351
352 U8X8_CA(0xda, 0x12), /* Set SEG Pins Hardware Configuration: */
353 U8X8_CA(0x81, 0x5a), /* contrast */
354 U8X8_CA(0xd9, 0x22), /* Set Phase Length */
355 U8X8_CA(0xdb, 0x30), /* VCOMH Deselect Level */
356 U8X8_CA(0xad, 0x10), /* Internal IREF Enable */
357 U8X8_CA(0x20, 0x00), /* Memory Addressing Mode: Horizontal */
358 U8X8_CA(0x8d, 0x01), /* disable internal charge pump 1 */
359 U8X8_CA(0xac, 0x00), /* disable internal charge pump 2 */
360 U8X8_C(0xa4), /* display on */
361 U8X8_C(0xa6), /* normal display */
362
363 U8X8_DLY(1), /* delay 2ms */
364
365 U8X8_END_TRANSFER(), /* disable chip */
366 U8X8_END() /* end of sequence */
367};
368
369
370uint8_t u8x8_d_ssd1320_160x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
371{
372 switch(msg)
373 {
374 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
375 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_d_ssd1320_cs1_160x32_display_info);
376 break;
377
378 case U8X8_MSG_DISPLAY_INIT:
379 u8x8_d_helper_display_init(u8x8);
380 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x32_init_seq);
381 break;
382
383 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
384 if ( arg_int == 0 ){
385 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x32_nhd_flip0_seq);
386 u8x8->x_offset = u8x8->display_info->default_x_offset;
387 }
388 else{
389 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x32_nhd_flip1_seq);
390 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
391 }
392 break;
393
394 default:
395 return u8x8_d_ssd1320_common(u8x8, msg, arg_int, arg_ptr);
396 }
397 return 1;
398}
399
400/*=========================================================*/
401/* 160x132 (actually 320x132) */
402
403static const uint8_t u8x8_d_ssd1320_cs1_160x132_nhd_flip0_seq[] = {
404 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
405 U8X8_C(0x0a0), /* remap */
406 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode CS1 */
407 U8X8_CA(0xd3, 0x0e), /* CS1 */
408 U8X8_END_TRANSFER(), /* disable chip */
409 U8X8_END() /* end of sequence */
410};
411
412static const uint8_t u8x8_d_ssd1320_cs1_160x132_nhd_flip1_seq[] = {
413 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
414 U8X8_C(0x0a1), /* remap */
415 U8X8_C(0xc0), /* Set COM Output Scan Direction: normal mode CS1 */
416 U8X8_CA(0xd3, 0x92), /* CS1 */
417 U8X8_END_TRANSFER(), /* disable chip */
418 U8X8_END() /* end of sequence */
419};
420
421static const u8x8_display_info_t u8x8_d_ssd1320_cs1_160x132_display_info =
422{
423 /* chip_enable_level = */ 0,
424 /* chip_disable_level = */ 1,
425
426 /* post_chip_enable_wait_ns = */ 20,
427 /* pre_chip_disable_wait_ns = */ 10,
428 /* reset_pulse_width_ms = */ 100, /* ssd1320: 2 us */
429 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
430 /* sda_setup_time_ns = */ 50, /* ssd1320: 15ns, but cycle time is 100ns, so use 100/2 */
431 /* sck_pulse_width_ns = */ 50, /* ssd1320: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
432 /* 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) */
433 /* spi_mode = */ 0, /* active high, rising edge */
434 /* i2c_bus_clock_100kHz = */ 4,
435 /* data_setup_time_ns = */ 10,
436 /* write_pulse_width_ns = */ 150, /* ssd1320: cycle time is 300ns, so use 300/2 = 150 */
437 /* tile_width = */ 20, /* 160 pixel, so we require 20 bytes for this */
438 /* tile_height = */ 17,
439 /* default_x_offset = */ 0, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
440 /* flipmode_x_offset = */ 0,
441 /* pixel_width = */ 160,
442 /* pixel_height = */ 132
443};
444
445
446/* the following sequence will work, but requires contrast to be very high */
447/* added #ifdef to avoid compiler warning, issue 1802 */
448#ifdef NOT_USED
449static const uint8_t u8x8_d_ssd1320_cs1_160x132_init_seq[] = {
450
451 U8X8_DLY(1),
452 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
453 U8X8_DLY(1),
454
455 U8X8_C(0xae), /* display off */
456 U8X8_CA(0xd5, 0xC2), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
457 U8X8_CA(0xa8, 0x83), /* multiplex ratio 1/132 Duty */
458 U8X8_CA(0xa2, 0x00), /* display start line */
459
460 U8X8_C(0xa0), /* Set Segment Re-Map: column address 0 mapped to SEG0 CS1 */
461 // U8X8_C(0xa1), /* Set Segment Re-Map: column address 0 mapped to SEG0 CS2 */
462
463 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode CS1 */
464 // U8X8_C(0xc0), /* Set COM Output Scan Direction: normal mode CS2 */
465
466 U8X8_CA(0xd3, 0x0e), /* CS1 */
467 // U8X8_CA(0xd3, 0x92), /* CS2 */
468
469 U8X8_CA(0xda, 0x12), /* Set SEG Pins Hardware Configuration: */
470 U8X8_CA(0x81, 0x5a), /* contrast */
471 U8X8_CA(0xd9, 0x22), /* Set Phase Length */
472 U8X8_CA(0xdb, 0x30), /* VCOMH Deselect Level */
473 U8X8_CA(0xad, 0x10), /* Internal IREF Enable */
474 U8X8_CA(0x20, 0x00), /* Memory Addressing Mode: Horizontal */
475 U8X8_CA(0x8d, 0x01), /* disable internal charge pump 1 */
476 U8X8_CA(0xac, 0x00), /* disable internal charge pump 2 */
477 U8X8_C(0xa4), /* display on */
478 U8X8_C(0xa6), /* normal display */
479
480 U8X8_DLY(1), /* delay 2ms */
481
482 U8X8_END_TRANSFER(), /* disable chip */
483 U8X8_END() /* end of sequence */
484};
485#endif
486
487/*
488OLED_WR_Byte(0xae,OLED_CMD);//Display OFF
489OLED_WR_Byte(0xfd,OLED_CMD);//Set Command Lock
490OLED_WR_Byte(0x12,OLED_CMD);
491OLED_WR_Byte(0x20,OLED_CMD);//Set Memory Addressing Mode
492OLED_WR_Byte(0x00,OLED_CMD);
493OLED_WR_Byte(0x25,OLED_CMD);//Set Portrait Addressing Mode
494OLED_WR_Byte(0x00,OLED_CMD);//Normal Addressing Mode
495OLED_WR_Byte(0x81,OLED_CMD);//Set Contrast Control
496OLED_WR_Byte(0x6b,OLED_CMD);
497OLED_WR_Byte1(0xa0,OLED_CMD,1);//Set Seg Remap LEFT DISPLAY
498OLED_WR_Byte1(0xa1,OLED_CMD,2);//Set Seg Remap RIGHT DISPLAY
499OLED_WR_Byte(0xa2,OLED_CMD);//Set Display Start Line
500OLED_WR_Byte(0x00,OLED_CMD);
501OLED_WR_Byte(0xa4,OLED_CMD);//Resume to RAM content display
502OLED_WR_Byte(0xa6,OLED_CMD);//Set Normal Display
503
504OLED_WR_Byte(0xa8,OLED_CMD);//Set MUX Ratio
505OLED_WR_Byte(0x83,OLED_CMD);//1/132 duty
506
507OLED_WR_Byte(0xad,OLED_CMD);//Select external or internal IREF
508OLED_WR_Byte(0x10,OLED_CMD);
509OLED_WR_Byte(0xbc,OLED_CMD);//Set Pre-charge voltage
510OLED_WR_Byte(0x1e,OLED_CMD);//
511OLED_WR_Byte(0xbf,OLED_CMD);//Linear LUT
512OLED_WR_Byte1(0xc8,OLED_CMD,1);//Set COM Output Scan Direction LEFT DISPLAY
513OLED_WR_Byte1(0xc0,OLED_CMD,2);//Set COM Output Scan Direction RIGHT DISPLAY
514OLED_WR_Byte(0xd3,OLED_CMD);//Set Display Offset
515OLED_WR_Byte1(0x0e,OLED_CMD,1); //LEFT DISPLAY
516OLED_WR_Byte1(0x92,OLED_CMD,2); // RIGHT DISPLAY
517OLED_WR_Byte(0xd5,OLED_CMD);//Set Display Clock Divide Ratio/Oscillator Frequency
518OLED_WR_Byte(0xc2,OLED_CMD);//85Hz
519OLED_WR_Byte(0xd9,OLED_CMD);//Set Pre-charge Period
520OLED_WR_Byte(0x72,OLED_CMD);//
521OLED_WR_Byte(0xda,OLED_CMD);//Set SEG Pins Hardware Configuration
522OLED_WR_Byte(0x32,OLED_CMD);
523OLED_WR_Byte(0xbd,OLED_CMD);//Set VP
524OLED_WR_Byte(0x03,OLED_CMD);
525OLED_WR_Byte(0xdb,OLED_CMD);//Set VCOMH
526OLED_WR_Byte(0x30,OLED_CMD);
527OLED_WR_Byte(0xaf,OLED_CMD);//Display on
528*/
529static const uint8_t u8x8_d_ssd1320_160x132_init_seq[] = {
530 U8X8_DLY(1),
531 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
532 U8X8_DLY(1),
533
534 U8X8_C(0xae), /* display off */
535 U8X8_CA(0xd5, 0xC2), /* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec) */
536 U8X8_CA(0xa8, 0x83), /* multiplex ratio 1/132 Duty */
537 U8X8_CA(0xa2, 0x00), /* display start line */
538
539 U8X8_C(0xa0), /* Set Segment Re-Map: column address 0 mapped to SEG0 CS1 */
540 // U8X8_C(0xa1), /* Set Segment Re-Map: column address 0 mapped to SEG0 CS2 */
541
542 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode CS1 */
543 // U8X8_C(0xc0), /* Set COM Output Scan Direction: normal mode CS2 */
544
545 U8X8_CA(0xad, 0x10), /* select Iref: 0x00 external (reset default), 0x10 internal */
546 U8X8_CA(0xbc, 0x1e), /* pre-charge voltage level 0x00..0x1f, reset default: 0x1e */
547 U8X8_C(0xbf), /* select linear LUT */
548 U8X8_CA(0xd5, 0xc2), /* Bit 0..3: clock ratio 1, 2, 4, 8, ...256, reset=0x1, Bit 4..7: F_osc 0..15 */
549 U8X8_CA(0xd9, 0x72), /* Set Phase 1&2 Length, Bit 0..3: Phase 1, Bit 4..7: Phase 2, reset default 0x72 */
550 U8X8_CA(0xbd, 0x03), /* from the vendor init sequence */
551 U8X8_CA(0xdb, 0x30), /* VCOMH Deselect Level */
552
553
554 U8X8_CA(0xd3, 0x0e), /* CS1 */
555 // U8X8_CA(0xd3, 0x92), /* CS2 */
556
557 U8X8_CA(0xda, 0x12), /* Set SEG Pins Hardware Configuration: */
558 U8X8_CA(0x81, 0x6b), /* contrast */
559 //U8X8_CA(0xd9, 0x22), /* Set Phase Length */
560 //U8X8_CA(0xdb, 0x30), /* VCOMH Deselect Level */
561 //U8X8_CA(0xad, 0x10), /* Internal IREF Enable */
562 U8X8_CA(0x20, 0x00), /* Memory Addressing Mode: Horizontal */
563 //U8X8_CA(0x8d, 0x01), /* unknown in SSD1320 datasheet, disable internal charge pump 1 */
564 //U8X8_CA(0xac, 0x00), /* unknown in SSD1320 datasheet, disable internal charge pump 2 */
565 U8X8_C(0xa4), /* display RAM on */
566 U8X8_C(0xa6), /* normal display */
567
568 U8X8_DLY(1), /* delay 2ms */
569
570 U8X8_END_TRANSFER(), /* disable chip */
571 U8X8_END() /* end of sequence */
572};
573
574uint8_t u8x8_d_ssd1320_160x132(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
575{
576 switch(msg)
577 {
578 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
579 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_d_ssd1320_cs1_160x132_display_info);
580
581 break;
582
583 case U8X8_MSG_DISPLAY_INIT:
584 u8x8_d_helper_display_init(u8x8);
585 // u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_init_seq);
586 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_160x132_init_seq);
587 break;
588
589 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
590 if ( arg_int == 0 ){
591 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_nhd_flip0_seq);
592 u8x8->x_offset = u8x8->display_info->default_x_offset;
593 }
594 else{
595 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_cs1_160x132_nhd_flip1_seq);
596 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
597 }
598 break;
599
600 default:
601 return u8x8_d_ssd1320_common(u8x8, msg, arg_int, arg_ptr);
602 }
603 return 1;
604}
605
606
607
608
609/*=========================================================*/
610/* https://github.com/olikraus/u8g2/issues/1816 */
611/* 160x80, https://de.aliexpress.com/item/1005003510267760.html */
612
613static const uint8_t u8x8_d_ssd1320_160x80_flip0_seq[] = {
614 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
615 U8X8_C(0x0a0), /* remap */
616 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode CS1 */
617 U8X8_CA(0xd3, 39), /* display offset */
618 U8X8_END_TRANSFER(), /* disable chip */
619 U8X8_END() /* end of sequence */
620};
621
622static const uint8_t u8x8_d_ssd1320_160x80_flip1_seq[] = {
623 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
624 U8X8_C(0x0a1), /* remap */
625 U8X8_C(0xc0), /* Set COM Output Scan Direction: normal mode CS1 */
626 U8X8_CA(0xd3, 120), /* display offset */
627 U8X8_END_TRANSFER(), /* disable chip */
628 U8X8_END() /* end of sequence */
629};
630
631static const u8x8_display_info_t u8x8_d_ssd1320_160x80_display_info =
632{
633 /* chip_enable_level = */ 0,
634 /* chip_disable_level = */ 1,
635
636 /* post_chip_enable_wait_ns = */ 20,
637 /* pre_chip_disable_wait_ns = */ 10,
638 /* reset_pulse_width_ms = */ 100, /* ssd1320: 2 us */
639 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
640 /* sda_setup_time_ns = */ 50, /* ssd1320: 15ns, but cycle time is 100ns, so use 100/2 */
641 /* sck_pulse_width_ns = */ 50, /* ssd1320: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
642 /* 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) */
643 /* spi_mode = */ 0, /* active high, rising edge */
644 /* i2c_bus_clock_100kHz = */ 4,
645 /* data_setup_time_ns = */ 10,
646 /* write_pulse_width_ns = */ 150, /* ssd1320: cycle time is 300ns, so use 300/2 = 150 */
647 /* tile_width = */ 20, /* 160 pixel, so we require 20 bytes for this */
648 /* tile_height = */ 10,
649 /* default_x_offset = */ 0, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
650 /* flipmode_x_offset = */ 0,
651 /* pixel_width = */ 160,
652 /* pixel_height = */ 80
653};
654
655
656
657static const uint8_t u8x8_d_ssd1320_160x80_init_seq[] = {
658 U8X8_DLY(1),
659 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
660 U8X8_DLY(1),
661
662 U8X8_C(0xae), /* display off */
663 U8X8_CA(0xa8, 80), /* multiplex ratio 1/80 Duty */
664 U8X8_CA(0xa2, 0), /* display start line */
665
666 U8X8_C(0xa0), /* Set Segment Re-Map */
667 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode */
668
669 U8X8_CA(0xad, 0x10), /* select Iref: 0x00 external (reset default), 0x10 internal */
670 U8X8_CA(0xbc, 0x1e), /* pre-charge voltage level 0x00..0x1f, reset default: 0x1e */
671 U8X8_C(0xbf), /* select linear LUT */
672 U8X8_CA(0xd5, 0xc2), /* Bit 0..3: clock ratio 1, 2, 4, 8, ...256, reset=0x1, Bit 4..7: F_osc 0..15 */
673 U8X8_CA(0xd9, 0x72), /* Set Phase 1&2 Length, Bit 0..3: Phase 1, Bit 4..7: Phase 2, reset default 0x72 */
674
675 U8X8_CA(0xd3, 39), /* display offset */
676
677 U8X8_CA(0xda, 0x12), /* Set SEG Pins Hardware Configuration: */
678 U8X8_CA(0x81, 0x70), /* contrast */
679 U8X8_CA(0x20, 0x00), /* Memory Addressing Mode: Horizontal */
680
681 U8X8_C(0xa4), /* display RAM on */
682 U8X8_C(0xa6), /* normal display */
683
684 U8X8_DLY(1), /* delay 2ms */
685
686 U8X8_END_TRANSFER(), /* disable chip */
687 U8X8_END() /* end of sequence */
688};
689
690uint8_t u8x8_d_ssd1320_160x80(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
691{
692
693 if ( u8x8_d_ssd1320_common_2(u8x8, msg, arg_int, arg_ptr) != 0 )
694 return 1;
695
696 switch(msg)
697 {
698 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
699 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_d_ssd1320_160x80_display_info);
700 break;
701
702 case U8X8_MSG_DISPLAY_INIT:
703 u8x8_d_helper_display_init(u8x8);
704 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_160x80_init_seq);
705 break;
706
707 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
708 if ( arg_int == 0 ){
709 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_160x80_flip0_seq);
710 u8x8->x_offset = u8x8->display_info->default_x_offset;
711 }
712 else{
713 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_160x80_flip1_seq);
714 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
715 }
716 break;
717
718 default:
719 break;
720 }
721 return 1;
722}
723
724
725/*=========================================================*/
726/* https://github.com/olikraus/u8g2/issues/2565 */
727/* 128x72, https://www.buydisplay.com/128x72-grayscale-oled-spi-white-0-72-inch-arduino-raspberry-pi */
728
729static const uint8_t u8x8_d_ssd1320_128x72_flip0_seq[] = {
730 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
731 U8X8_C(0x0a0), /* remap */
732 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode CS1 */
733 U8X8_CA(0xd3, 0x2c), /* display offset WARNING: ALSO ASSIGN THIS IN THE INIT SEQ */
734 U8X8_END_TRANSFER(), /* disable chip */
735 U8X8_END() /* end of sequence */
736};
737
738static const uint8_t u8x8_d_ssd1320_128x72_flip1_seq[] = {
739 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
740 U8X8_C(0x0a1), /* remap */
741 U8X8_C(0xc0), /* Set COM Output Scan Direction: normal mode CS1 */
742 U8X8_CA(0xd3, 0x74), /* display offset */
743 U8X8_END_TRANSFER(), /* disable chip */
744 U8X8_END() /* end of sequence */
745};
746
747static const u8x8_display_info_t u8x8_d_ssd1320_128x72_display_info =
748{
749 /* chip_enable_level = */ 0,
750 /* chip_disable_level = */ 1,
751
752 /* post_chip_enable_wait_ns = */ 20,
753 /* pre_chip_disable_wait_ns = */ 10,
754 /* reset_pulse_width_ms = */ 100, /* ssd1320: 2 us */
755 /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
756 /* sda_setup_time_ns = */ 50, /* ssd1320: 15ns, but cycle time is 100ns, so use 100/2 */
757 /* sck_pulse_width_ns = */ 50, /* ssd1320: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
758 /* 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) */
759 /* spi_mode = */ 0, /* active high, rising edge */
760 /* i2c_bus_clock_100kHz = */ 4,
761 /* data_setup_time_ns = */ 10,
762 /* write_pulse_width_ns = */ 150, /* ssd1320: cycle time is 300ns, so use 300/2 = 150 */
763 /* tile_width = */ 16, /* 128 */
764 /* tile_height = */ 9, /* 72 */
765 /* default_x_offset = */ 16, /* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
766 /* flipmode_x_offset = */ 0,
767 /* pixel_width = */ 128,
768 /* pixel_height = */ 72
769};
770
771/* from the buydisplay.com example code for the 8051:
772 Contrast_level=0xDF
773
774 OLED_WR_Byte(0xae,OLED_CMD);//Set y Off
775 OLED_WR_Byte(0xD5,OLED_CMD);//Set Display Clock Divide Ratio/Oscillator Frequency
776 OLED_WR_Byte(0x11,OLED_CMD);
777 OLED_WR_Byte(0xA8,OLED_CMD);//Set Multiplex Ratio
778 OLED_WR_Byte(0x47,OLED_CMD);
779 OLED_WR_Byte(0xA2,OLED_CMD);//Set Display Start Line
780 OLED_WR_Byte(0x00,OLED_CMD);
781
782 if(USE_HORIZONTAL==0)
783 {
784 x_offset=0x10;
785 OLED_WR_Byte(0xD3,OLED_CMD);//Set Display Offset
786 OLED_WR_Byte(0x2C,OLED_CMD);
787 OLED_WR_Byte(0xa0,OLED_CMD);//Set COM Output Scan Direction
788 OLED_WR_Byte(0xC8,OLED_CMD);
789 }
790 else
791 {
792 x_offset=0;
793 OLED_WR_Byte(0xD3,OLED_CMD);//Set Display Offset
794 OLED_WR_Byte(0x74,OLED_CMD);
795 OLED_WR_Byte(0xa1,OLED_CMD);//Set COM Output Scan Direction
796 OLED_WR_Byte(0xC0,OLED_CMD);
797 }
798
799
800 OLED_WR_Byte(0xDA,OLED_CMD);//SetSEGPinsHardwareConfiguration
801 OLED_WR_Byte(0x32,OLED_CMD);
802
803
804 OLED_WR_Byte(0x81,OLED_CMD);//Set Contrast Control
805 OLED_WR_Byte(Contrast_level,OLED_CMD);
806
807 OLED_WR_Byte(0xD9,OLED_CMD);//SSet Pre-Charge Priod
808 OLED_WR_Byte(0x72,OLED_CMD);
809 OLED_WR_Byte(0xDB,OLED_CMD);//Set VCOMH Deselect Level
810 OLED_WR_Byte(0x20,OLED_CMD);
811
812
813 OLED_WR_Byte(0xAD,OLED_CMD);//Set Internal IREF Enable
814 OLED_WR_Byte(0x00,OLED_CMD);
815 OLED_WR_Byte(0xBC,OLED_CMD);
816 OLED_WR_Byte(0x1E,OLED_CMD);
817*/
818
819
820static const uint8_t u8x8_d_ssd1320_128x72_init_seq[] = {
821 U8X8_DLY(1),
822 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
823 U8X8_DLY(1),
824
825 U8X8_C(0xae), /* display off */
826 U8X8_CA(0xa8, 0x47), /* multiplex ratio 1/72 Duty (128x72 init code) */
827 U8X8_CA(0xa2, 0), /* display start line (128x72 init code) */
828
829 U8X8_C(0xa0), /* Set Segment Re-Map */
830 U8X8_C(0xc8), /* Set COM Output Scan Direction: normal mode */
831
832 U8X8_CA(0xad, 0x10), /* select Iref: 0x00 external (reset default), 0x10 internal (datasheet: 0x00, but no difference with 0x10) */
833 U8X8_CA(0xbc, 0x1e), /* pre-charge voltage level 0x00..0x1f, reset default: 0x1e (128x72 init code)*/
834 U8X8_C(0xbf), /* select linear LUT */
835 //U8X8_DLY(1),
836
837 U8X8_CA(0xd5, 0x11 ), /* Bit 0..3: clock ratio 1, 2, 4, 8, ...256, reset=0x1, Bit 4..7: F_osc 0..15 (128x72 init code)*/
838
839 U8X8_CA(0xd3, 0x2c), /* display offset */
840
841 U8X8_CA(0xda, 0x12), /* Set SEG Pins Hardware Configuration: (128x72 init code: 0x32, but 0x12 req here) */
842 U8X8_CA(0x81, 0xDF), /* contrast (128x72 init code) */
843 U8X8_CA(0xd9, 0x72), /* Set Phase 1&2 Length, Bit 0..3: Phase 1, Bit 4..7: Phase 2, reset default 0x72 */
844 U8X8_CA(0xdb, 0x20), /* VCOMH Deselect Level (128x72 init code 0x20) */
845 U8X8_CA(0x20, 0x00), /* Memory Addressing Mode: Horizontal */
846
847 U8X8_C(0xa4), /* display RAM on */
848 U8X8_C(0xa6), /* normal display */
849
850 U8X8_DLY(1), /* delay 2ms */
851
852 U8X8_END_TRANSFER(), /* disable chip */
853 U8X8_END() /* end of sequence */
854};
855
856uint8_t u8x8_d_ssd1320_128x72(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
857{
858
859 if ( u8x8_d_ssd1320_common_2(u8x8, msg, arg_int, arg_ptr) != 0 )
860 return 1;
861
862 switch(msg)
863 {
864 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
865 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_d_ssd1320_128x72_display_info);
866 break;
867
868 case U8X8_MSG_DISPLAY_INIT:
869 u8x8_d_helper_display_init(u8x8);
870 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_128x72_init_seq);
871 break;
872
873 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
874 if ( arg_int == 0 ){
875 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_128x72_flip0_seq);
876 u8x8->x_offset = u8x8->display_info->default_x_offset;
877 }
878 else{
879 u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_128x72_flip1_seq);
880 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
881 }
882 break;
883
884 default:
885 break;
886 }
887 return 1;
888}