components/u8g2/csrc/u8x8_d_il3820_296x128.c

changeset 0
88d965579617
equal deleted inserted replaced
-1:000000000000 0:88d965579617
1 /*
2
3 u8x8_d_il3820_296x128.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 il3820: 200x300x1
35
36 command
37 0x22: assign actions
38 0x20: execute actions
39
40 action for command 0x022 are (more or less guessed)
41 bit 7: Enable Clock
42 bit 6: Enable Charge Pump
43 bit 5: Load Temparture Value (???)
44 bit 4: Load LUT (???)
45 bit 3: Initial Display (???)
46 bit 2: Pattern Display --> Requires about 945ms with the LUT from below
47 bit 1: Disable Charge Pump
48 bit 0: Disable Clock
49
50 Disable Charge Pump and Clock require about 10ms
51 Enable Charge Pump and Clock require about 100 to 300ms
52
53 Notes:
54 - Introduced a refresh display message, which copies RAM to display
55 - Charge pump is always enabled. Charge pump can be enabled/disabled via power save message
56 - U8x8 will not really work because of the two buffers in the SSD1606, however U8g2 should be ok.
57
58 LUT for the 296x128 device (IL3820)
59 LUT (cmd: 0x032 has 30 bytes)
60 section 6.8 of the datasheet mentions 256 bits = 32 bytes for the LUT
61 chapter 7 tells 30 bytes
62
63 according to section 6.8:
64 20 bytes waveform
65 10 bytes timing
66 1 byte named as VSH/VSL
67 1 empty byte
68 according to the command table, the lut has 240 bits (=30 bytes * 8 bits)
69
70
71 LUT / Refresh time
72 total_refresh_time = (refresh_lines + dummy_lines*2)*TGate*TS_Sum/f_OSC
73
74 f_OSC=1MHz (according to the datasheets)
75 refreh_lines = 296 (for the waveshare display, 0x045 cmd)
76 dummy_lines = 22 (for the upcoming u8g2 code, 0x03a cmd)
77 TGate = 62 (POR default, 0x03b cmd)
78 TS_Sum: Sum of all TS entries of the second part of the LUT
79 f_OSC: 1MHz according to the datasheet.
80
81 so we have
82
83 total_refresh_time = 21080*TS_Sum/1000000 = 21ms * TS_Sum
84
85
86 This file includes two devices:
87 u8x8_d_il3820_296x128 --> includes LUT which is probably from the WaveShare 2.9 Vendor
88 u8x8_d_il3820_v2_296x128 --> includes LUT which was optimized for faster speed and lesser flicker
89
90 */
91
92 /* Waveform part of the LUT (20 bytes) */
93 /* bit 7/6: 1 - 1 transition */
94 /* bit 5/4: 1 - 0 transition */
95 /* bit 3/2: 0 - 1 transition */
96 /* bit 1/0: 0 - 0 transition */
97 /* 00 – VSS */
98 /* 01 – VSH */
99 /* 10 – VSL */
100 /* 11 – NA */
101
102
103 #include "u8x8.h"
104
105 /*=================================================*/
106 /* common code for all devices */
107
108
109 static const uint8_t u8x8_d_il3820_296x128_powersave0_seq[] = {
110 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
111 U8X8_CA(0x22, 0xc0), /* enable clock and charge pump */
112 U8X8_C(0x20), /* execute sequence */
113 U8X8_DLY(200), /* according to my measures it may take up to 150ms */
114 U8X8_DLY(100), /* but it might take longer */
115 U8X8_END_TRANSFER(), /* disable chip */
116 U8X8_END() /* end of sequence */
117 };
118
119 static const uint8_t u8x8_d_il3820_296x128_powersave1_seq[] = {
120 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
121 /* disable clock and charge pump only, deep sleep is not entered, because we will loose RAM content */
122 U8X8_CA(0x22, 0x02), /* only disable charge pump, HW reset seems to be required if the clock is disabled */
123 U8X8_C(0x20), /* execute sequence */
124 U8X8_DLY(20),
125 U8X8_END_TRANSFER(), /* disable chip */
126 U8X8_END() /* end of sequence */
127 };
128
129 // static const uint8_t u8x8_d_il3820_296x128_flip0_seq[] = {
130 // U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
131 // U8X8_END_TRANSFER(), /* disable chip */
132 // U8X8_END() /* end of sequence */
133 // };
134
135 // static const uint8_t u8x8_d_il3820_296x128_flip1_seq[] = {
136 // U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
137 // U8X8_END_TRANSFER(), /* disable chip */
138 // U8X8_END() /* end of sequence */
139 // };
140
141
142 static const u8x8_display_info_t u8x8_il3820_296x128_display_info =
143 {
144 /* chip_enable_level = */ 0,
145 /* chip_disable_level = */ 1,
146
147 /* post_chip_enable_wait_ns = */ 120,
148 /* pre_chip_disable_wait_ns = */ 60,
149 /* reset_pulse_width_ms = */ 100,
150 /* post_reset_wait_ms = */ 100,
151 /* sda_setup_time_ns = */ 50, /* IL3820 */
152 /* sck_pulse_width_ns = */ 125, /* IL3820: 125ns, clock cycle = 250ns */
153 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
154 /* spi_mode = */ 0, /* active high, rising edge */
155 /* i2c_bus_clock_100kHz = */ 4,
156 /* data_setup_time_ns = */ 40,
157 /* write_pulse_width_ns = */ 150,
158 /* tile_width = */ 37, /* 37*8 = 296 */
159 /* tile_hight = */ 16, /* 16*8 = 128 */
160 /* default_x_offset = */ 0,
161 /* flipmode_x_offset = */ 0,
162 /* pixel_width = */ 296,
163 /* pixel_height = */ 128
164 };
165
166
167 static uint8_t *u8x8_convert_tile_for_il3820(uint8_t *t)
168 {
169 uint8_t i;
170 static uint8_t buf[8];
171 uint8_t *pbuf = buf;
172
173 for( i = 0; i < 8; i++ )
174 {
175 *pbuf++ = ~(*t++);
176 }
177 return buf;
178 }
179
180 static void u8x8_d_il3820_draw_tile(u8x8_t *u8x8, uint8_t arg_int, void *arg_ptr) U8X8_NOINLINE;
181 static void u8x8_d_il3820_draw_tile(u8x8_t *u8x8, uint8_t arg_int, void *arg_ptr)
182 {
183 uint16_t x;
184 uint8_t c, page;
185 uint8_t *ptr;
186 u8x8_cad_StartTransfer(u8x8);
187
188 page = u8x8->display_info->tile_height;
189 page --;
190 page -= (((u8x8_tile_t *)arg_ptr)->y_pos);
191
192 x = ((u8x8_tile_t *)arg_ptr)->x_pos;
193 x *= 8;
194 x += u8x8->x_offset;
195
196 //u8x8_cad_SendCmd(u8x8, 0x011 ); /* cursor increment mode */
197 //u8x8_cad_SendArg(u8x8, 7);
198
199 u8x8_cad_SendCmd(u8x8, 0x04f ); /* set cursor column */
200 u8x8_cad_SendArg(u8x8, x&255);
201 u8x8_cad_SendArg(u8x8, x>>8);
202
203 u8x8_cad_SendCmd(u8x8, 0x04e ); /* set cursor row */
204 u8x8_cad_SendArg(u8x8, page);
205
206 u8x8_cad_SendCmd(u8x8, 0x024 );
207
208 do
209 {
210 c = ((u8x8_tile_t *)arg_ptr)->cnt;
211 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
212 do
213 {
214 u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_il3820(ptr));
215 ptr += 8;
216 x += 8;
217 c--;
218 } while( c > 0 );
219
220 arg_int--;
221 } while( arg_int > 0 );
222
223 u8x8_cad_EndTransfer(u8x8);
224 }
225
226
227
228 static const uint8_t u8x8_d_il3820_exec_1000dly_seq[] = {
229 // assumes, that the start transfer has happend
230 U8X8_CA(0x22, 0x04), /* display update seq. option: pattern display */
231 U8X8_C(0x20), /* execute sequence */
232 U8X8_DLY(250),
233 U8X8_DLY(250),
234 U8X8_DLY(250),
235 U8X8_DLY(250),
236 U8X8_END_TRANSFER(), /* disable chip */
237 U8X8_END() /* end of sequence */
238 };
239
240 static void u8x8_d_il3820_first_init(u8x8_t *u8x8)
241 {
242 u8x8_ClearDisplay(u8x8);
243
244 u8x8_cad_StartTransfer(u8x8);
245 u8x8_cad_SendCmd(u8x8, 0x032); // program update sequence
246 u8x8_cad_SendMultipleArg(u8x8, 8, 0x055); // all black
247 u8x8_cad_SendMultipleArg(u8x8, 12, 0x0aa); // all white
248 u8x8_cad_SendMultipleArg(u8x8, 10, 0x022); // 830ms
249 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_exec_1000dly_seq);
250
251 }
252
253 #ifdef OBSOLETE
254 static void u8x8_d_il3820_second_init(u8x8_t *u8x8)
255 {
256 u8x8_ClearDisplay(u8x8);
257
258 u8x8_cad_StartTransfer(u8x8);
259 u8x8_cad_SendCmd(u8x8, 0x032); // program update sequence
260 u8x8_cad_SendMultipleArg(u8x8, 20, 0x000); // do nothing
261 u8x8_cad_SendMultipleArg(u8x8, 10, 0x011); // 414ms dly
262 /* reuse sequence from above, ok some time is wasted here, */
263 /* delay could be lesser */
264 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_exec_1000dly_seq);
265 }
266 #endif
267
268
269 /*=================================================*/
270 /* first version, LUT from WaveShare */
271
272
273 /* http://www.waveshare.com/wiki/File:2.9inch_e-Paper_Module_code.7z */
274 static const uint8_t u8x8_d_il3820_296x128_init_seq[] = {
275
276 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
277
278 U8X8_CA(0x10, 0x00), /* Deep Sleep mode Control: Disable */
279 U8X8_C(0x01),
280 U8X8_A(295 % 256), U8X8_A(295/256), U8X8_A(0),
281
282
283 U8X8_CA(0x03, 0x00), /* Gate Driving voltage: 15V (lowest value)*/
284 U8X8_CA(0x04, 0x0a), /* Source Driving voltage: 15V (mid value and POR)*/
285
286 //U8X8_CA(0x22, 0xc0), /* display update seq. option: enable clk, enable CP, .... todo: this is never activated */
287
288 //U8X8_CA(0x0b, 7), /* Set Delay of gate and source non overlap period, POR = 7 */
289 U8X8_CA(0x2c, 0xa8), /* write vcom value*/
290 U8X8_CA(0x3a, 0x16), /* dummy lines POR=22 (0x016) */
291 U8X8_CA(0x3b, 0x08), /* gate time POR=0x08*/
292 U8X8_CA(0x3c, 0x33), /* select boarder waveform */
293 //U8X8_CA(0x22, 0xc4), /* display update seq. option: clk -> CP -> LUT -> initial display -> pattern display */
294
295
296 U8X8_CA(0x11, 0x07), /* Define data entry mode, x&y inc, x first*/
297
298 U8X8_CAA(0x44, 0, 29), /* RAM x start & end, issue 920: end should be (128/8)-1=15. */
299 U8X8_CAAAA(0x45, 0, 0, 295&255, 295>>8), /* RAM y start & end */
300
301 //U8X8_CA(0x4e, 0), /* set x pos, 0..29? */
302 //U8X8_CAA(0x4f, 0, 0), /* set y pos, 0...320??? */
303
304
305 U8X8_END_TRANSFER(), /* disable chip */
306 U8X8_END() /* end of sequence */
307 };
308
309
310 static const uint8_t u8x8_d_il3820_to_display_seq[] = {
311 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
312 /*
313 0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
316 measured 1582 ms
317 */
318 U8X8_C(0x32), /* write LUT register*/
319 /* original values */
320 U8X8_A(0x50),
321 U8X8_A(0xaa),
322 U8X8_A(0x55),
323 U8X8_A(0xaa),
324 U8X8_A(0x11),
325
326 U8X8_A(0x11),
327 U8X8_A(0x00),
328 U8X8_A(0x00),
329 U8X8_A(0x00),
330 U8X8_A(0x00),
331
332 U8X8_A(0x00),
333 U8X8_A(0x00),
334 U8X8_A(0x00),
335 U8X8_A(0x00),
336 U8X8_A(0x00),
337
338 U8X8_A(0x00),
339 U8X8_A(0x00),
340 U8X8_A(0x00),
341 U8X8_A(0x00),
342 U8X8_A(0x00),
343
344 /* Timing part of the LUT, 20 Phases with 4 bit each: 10 bytes */
345 U8X8_A(0xff),
346 U8X8_A(0xff),
347 U8X8_A(0x3f),
348 U8X8_A(0x00),
349 U8X8_A(0x00),
350 U8X8_A(0x00),
351 U8X8_A(0x00),
352 U8X8_A(0x00),
353 U8X8_A(0x00),
354 U8X8_A(0x00),
355
356 U8X8_CA(0x22, 0x04), /* display update seq. option: pattern display, assumes clk and charge pump are enabled */
357 U8X8_C(0x20), /* execute sequence */
358
359 U8X8_DLY(250), /* delay for 1620ms. The current sequence takes 1582ms */
360 U8X8_DLY(250),
361 U8X8_DLY(250),
362 U8X8_DLY(250),
363
364 U8X8_DLY(250),
365 U8X8_DLY(250),
366 U8X8_DLY(120),
367
368 U8X8_END_TRANSFER(), /* disable chip */
369 U8X8_END() /* end of sequence */
370 };
371
372
373 uint8_t u8x8_d_il3820_296x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
374 {
375 switch(msg)
376 {
377 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
378 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_il3820_296x128_display_info);
379 break;
380 case U8X8_MSG_DISPLAY_INIT:
381
382 u8x8_d_helper_display_init(u8x8);
383 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_init_seq);
384
385 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_powersave0_seq);
386 u8x8_d_il3820_first_init(u8x8);
387
388 /* usually the DISPLAY_INIT message leaves the display in power save state */
389 /* however this is not done for e-paper devices, see: */
390 /* https://github.com/olikraus/u8g2/wiki/internal#powersave-mode */
391
392 break;
393 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
394 if ( arg_int == 0 )
395 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_powersave0_seq);
396 else
397 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_powersave1_seq);
398 break;
399 case U8X8_MSG_DISPLAY_DRAW_TILE:
400 u8x8_d_il3820_draw_tile(u8x8, arg_int, arg_ptr);
401 break;
402 case U8X8_MSG_DISPLAY_REFRESH:
403 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_to_display_seq);
404 break;
405 default:
406 return 0;
407 }
408 return 1;
409 }
410
411 /*=================================================*/
412 /* second version for the IL3820 display */
413
414
415 /* http://www.waveshare.com/wiki/File:2.9inch_e-Paper_Module_code.7z */
416 static const uint8_t u8x8_d_il3820_v2_296x128_init_seq[] = {
417
418 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
419
420 // U8X8_CA(0x10, 0x00), /* Deep Sleep mode Control: POR: Normal mode */
421 U8X8_C(0x01),
422 U8X8_A(295 % 256), U8X8_A(295/256), U8X8_A(0),
423
424 /* the driving voltagesmust not be that high, in order to aviod level change after */
425 /* some seconds (which happens with 0xea */
426 U8X8_CA(0x03, 0x75), /* Gate Driving voltage: +/-15V =0x00 POR (+22/-20V) = 0x0ea*/
427 U8X8_CA(0x04, 0x0a), /* Source Driving voltage: (POR=0x0a=15V), max=0x0e*/
428
429 U8X8_CA(0x0b, 7), /* Set Delay of gate and source non overlap period, POR = 7 */
430 U8X8_CA(0x2c, 0xa8), /* write vcom value*/
431 U8X8_CA(0x3a, 0x16), /* dummy lines POR=22 (0x016) */
432 U8X8_CA(0x3b, 0x08), /* gate time POR=0x08*/
433 U8X8_CA(0x3c, 0x33), /* select boarder waveform */
434
435 U8X8_CA(0x11, 0x07), /* Define data entry mode, x&y inc, x first*/
436 U8X8_CAA(0x44, 0, 29), /* RAM x start & end, 32*4=128 */
437 U8X8_CAAAA(0x45, 0, 0, 295&255, 295>>8), /* RAM y start & end, 0..295 */
438
439 U8X8_END_TRANSFER(), /* disable chip */
440 U8X8_END() /* end of sequence */
441 };
442
443
444 static const uint8_t u8x8_d_il3820_v2_to_display_seq[] = {
445 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
446
447 /*
448 0xaa, 0x09, 0x09, 0x19, 0x19,
449 0x11, 0x11, 0x11, 0x11, 0x00,
450 0x00, 0x00, 0x00, 0x00, 0x00,
451 0x00, 0x00, 0x00, 0x00, 0x00,
452
453 0x75, 0x77, 0x77, 0x77, 0x07,
454 0x00, 0x00, 0x00, 0x00, 0x00
455 measured 1240 ms
456 */
457 U8X8_C(0x32), /* write LUT register*/
458 /* https://github.com/olikraus/u8g2/issues/347 */
459 U8X8_A(0xaa),
460 U8X8_A(0x09),
461 U8X8_A(0x09),
462 U8X8_A(0x19),
463 U8X8_A(0x19),
464
465 U8X8_A(0x11),
466 U8X8_A(0x11),
467 U8X8_A(0x11),
468 U8X8_A(0x11),
469 U8X8_A(0x00),
470
471 U8X8_A(0x00),
472 U8X8_A(0x00),
473 U8X8_A(0x00),
474 U8X8_A(0x00),
475 U8X8_A(0x00),
476
477 U8X8_A(0x00),
478 U8X8_A(0x00),
479 U8X8_A(0x00),
480 U8X8_A(0x00),
481 U8X8_A(0x00),
482
483 /* Timing part of the LUT, 20 Phases with 4 bit each: 10 bytes */
484 U8X8_A(0x75),
485 U8X8_A(0x77),
486 U8X8_A(0x77),
487 U8X8_A(0x77),
488 U8X8_A(0x07),
489
490 U8X8_A(0x00),
491 U8X8_A(0x00),
492 U8X8_A(0x00),
493 U8X8_A(0x00),
494 U8X8_A(0x00),
495
496 U8X8_CA(0x22, 0x04), /* display update seq. option: pattern display */
497 U8X8_C(0x20), /* execute sequence */
498
499 U8X8_DLY(250), /* delay for 1400ms. The current sequence takes 1240ms, it was reported, that longer delays are better */
500 U8X8_DLY(250),
501 U8X8_DLY(250),
502 U8X8_DLY(250),
503
504 U8X8_DLY(250),
505 U8X8_DLY(150), /* extended, #318 */
506
507 U8X8_END_TRANSFER(), /* disable chip */
508 U8X8_END() /* end of sequence */
509 };
510
511 uint8_t u8x8_d_il3820_v2_296x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
512 {
513 switch(msg)
514 {
515 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
516 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_il3820_296x128_display_info);
517 break;
518 case U8X8_MSG_DISPLAY_INIT:
519
520 u8x8_d_helper_display_init(u8x8);
521
522 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_v2_296x128_init_seq);
523
524 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_powersave0_seq);
525 u8x8_d_il3820_first_init(u8x8);
526 /* u8x8_d_il3820_second_init(u8x8); */ /* not required, u8g2.begin() will also clear the display once more */
527
528 /* usually the DISPLAY_INIT message leaves the display in power save state */
529 /* however this is not done for e-paper devices, see: */
530 /* https://github.com/olikraus/u8g2/wiki/internal#powersave-mode */
531
532 break;
533 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
534 if ( arg_int == 0 )
535 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_powersave0_seq);
536 else
537 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_296x128_powersave1_seq);
538 break;
539 case U8X8_MSG_DISPLAY_DRAW_TILE:
540 u8x8_d_il3820_draw_tile(u8x8, arg_int, arg_ptr);
541 break;
542 case U8X8_MSG_DISPLAY_REFRESH:
543 u8x8_cad_SendSequence(u8x8, u8x8_d_il3820_v2_to_display_seq);
544 break;
545 default:
546 return 0;
547 }
548 return 1;
549 }
550
551
552

mercurial