Krolyxon
Commit 3120783

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8U8g2srcclibu8x8_d_lc7981.c

542 lines · 18.0 KB · C

1/*
2
3 u8x8_d_lc7981.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
36*/
37#include "u8x8.h"
38
39
40
41
42/* no powersave mode for the LC7981 */
43// static const uint8_t u8x8_d_lc7981_powersave0_seq[] = {
44// U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
45// U8X8_END_TRANSFER(), /* disable chip */
46// U8X8_END() /* end of sequence */
47// };
48
49// static const uint8_t u8x8_d_lc7981_powersave1_seq[] = {
50// U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
51// U8X8_END_TRANSFER(), /* disable chip */
52// U8X8_END() /* end of sequence */
53// };
54
55/* no hardware flip for the LC7981 */
56// static const uint8_t u8x8_d_lc7981_flip0_seq[] = {
57// U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
58// U8X8_END_TRANSFER(), /* disable chip */
59// U8X8_END() /* end of sequence */
60// };
61
62// static const uint8_t u8x8_d_lc7981_flip1_seq[] = {
63// U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
64// U8X8_END_TRANSFER(), /* disable chip */
65// U8X8_END() /* end of sequence */
66// };
67
68
69/* http://graphics.stanford.edu/~seander/bithacks.html */
70static uint8_t reverse_byte(uint8_t v)
71{
72 // if ( v != 0 && v != 255 ) does not help much
73 {
74 // swap odd and even bits
75 v = ((v >> 1) & 0x055) | ((v & 0x055) << 1);
76 // swap consecutive pairs
77 v = ((v >> 2) & 0x033) | ((v & 0x033) << 2);
78 // swap nibbles ...
79 v = ((v >> 4) & 0x00F) | ((v & 0x00F) << 4);
80 }
81 return v;
82}
83
84static uint8_t u8x8_d_lc7981_common(u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uint8_t arg_int, void *arg_ptr)
85{
86 uint8_t c, i, j;
87 uint16_t y;
88 uint8_t *ptr;
89 switch(msg)
90 {
91 case U8X8_MSG_DISPLAY_DRAW_TILE:
92 y = (((u8x8_tile_t *)arg_ptr)->y_pos);
93 y*=8;
94 y*= u8x8->display_info->tile_width;
95 /* x = ((u8x8_tile_t *)arg_ptr)->x_pos; x is ignored... no u8x8 support */
96 u8x8_cad_StartTransfer(u8x8);
97 /*
98 Tile structure is reused here for the t6963, however u8x8 is not supported
99 tile_ptr points to data which has cnt*8 bytes (same as SSD1306 tiles)
100 Buffer is expected to have 8 lines of code fitting to the t6963 internal memory
101 "cnt" includes the number of horizontal bytes. width is equal to cnt*8
102
103 x is assumed to be zero
104
105 TODO: Consider arg_int, however arg_int is not used by u8g2
106 */
107 c = ((u8x8_tile_t *)arg_ptr)->cnt; /* number of tiles */
108 ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr; /* data ptr to the tiles */
109 for( i = 0; i < 8; i++ )
110 {
111 u8x8_cad_SendCmd(u8x8, 0x0a ); /* display ram (cursor) address low byte */
112 u8x8_cad_SendArg(u8x8, y&255);
113 u8x8_cad_SendCmd(u8x8, 0x0b ); /* display ram (cursor) address high byte */
114 u8x8_cad_SendArg(u8x8, y>>8);
115
116 u8x8_cad_SendCmd(u8x8, 0x0c ); /* write start */
117 /*
118 The LC7981 has the MSB at the right position, which is exactly the opposite to the T6963.
119 Instead of writing a third hvline procedure for this device, we just revert the bytes before
120 transmit. This is slow because:
121 - the bit reverse itself
122 - the single byte transfer
123 The one byte is transmitted via SendArg, which is ok, because CAD = 100
124 */
125 for( j = 0; j < c; j++ )
126 u8x8_cad_SendArg(u8x8, reverse_byte(*ptr++));
127
128 //u8x8_cad_SendData(u8x8, c, ptr); /* note: SendData can not handle more than 255 bytes, send one line of data */
129 //ptr += u8x8->display_info->tile_width;
130
131 y += u8x8->display_info->tile_width;
132 }
133
134 u8x8_cad_EndTransfer(u8x8);
135 break;
136 /* handled in the calling procedure
137 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
138 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_lc7981_128x64_display_info);
139 break;
140 case U8X8_MSG_DISPLAY_INIT:
141 u8x8_d_helper_display_init(u8x8);
142 u8x8_cad_SendSequence(u8x8, u8x8_d_uc1701_dogs102_init_seq);
143 break;
144 */
145 /* power save is not there...
146 case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
147 if ( arg_int == 0 )
148 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_powersave0_seq);
149 else
150 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_powersave1_seq);
151 break;
152 */
153 /* hardware flip not is not available
154 case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
155 if ( arg_int == 0 )
156 {
157 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_flip0_seq);
158 u8x8->x_offset = u8x8->display_info->default_x_offset;
159 }
160 else
161 {
162 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_flip1_seq);
163 u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
164 }
165 break;
166 */
167#ifdef U8X8_WITH_SET_CONTRAST
168 /* no contrast setting :-(
169 case U8X8_MSG_DISPLAY_SET_CONTRAST:
170 u8x8_cad_StartTransfer(u8x8);
171 u8x8_cad_SendCmd(u8x8, 0x081 );
172 u8x8_cad_SendArg(u8x8, arg_int );
173 u8x8_cad_EndTransfer(u8x8);
174 break;
175 */
176#endif
177 default:
178 return 0;
179 }
180 return 1;
181}
182
183/*================================================*/
184/* LC7981 160x80 LCD*/
185
186static const u8x8_display_info_t u8x8_lc7981_160x80_display_info =
187{
188 /* chip_enable_level = */ 0, /* LC7981 has a low active CS*/
189 /* chip_disable_level = */ 1,
190
191 /* from here... */
192 /* post_chip_enable_wait_ns = */ 20,
193 /* pre_chip_disable_wait_ns = */ 20,
194 /* reset_pulse_width_ms = */ 1,
195 /* post_reset_wait_ms = */ 10,
196 /* sda_setup_time_ns = */ 30,
197 /* sck_pulse_width_ns = */ 65, /* half of cycle time */
198 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
199 /* spi_mode = */ 0, /* active high, rising edge */
200 /* i2c_bus_clock_100kHz = */ 4,
201 /* ... to here, values are ignored, because this is a parallel interface only */
202
203 /* data_setup_time_ns = */ 220,
204 /* write_pulse_width_ns = */ 20,
205 /* tile_width = */ 20, /* width of 20*8=160 pixel */
206 /* tile_height = */ 10,
207 /* default_x_offset = */ 0,
208 /* flipmode_x_offset = */ 0,
209 /* pixel_width = */ 160,
210 /* pixel_height = */ 80
211};
212
213static const uint8_t u8x8_d_lc7981_160x80_init_seq[] = {
214
215 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
216
217 U8X8_DLY(50),
218
219 U8X8_CA(0x00, 0x32), /* display on (bit 5), master mode on (bit 4), graphics mode on (bit 1) */
220 U8X8_CA(0x01, 0x07), /* character/bits per pixel pitch */
221 U8X8_CA(0x02, 160/8-1), /* number of chars/byte width of the screen */
222 U8X8_CA(0x03, 0x50), /* time division: 50 (1/80 duty cycle) */
223 U8X8_CA(0x08, 0x00), /* display start low */
224 U8X8_CA(0x09, 0x00), /* display start high */
225
226 U8X8_DLY(10),
227
228 U8X8_END_TRANSFER(), /* disable chip */
229 U8X8_END() /* end of sequence */
230};
231
232uint8_t u8x8_d_lc7981_160x80(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
233{
234 /* call common procedure first and handle messages there */
235 if ( u8x8_d_lc7981_common(u8x8, msg, arg_int, arg_ptr) == 0 )
236 {
237 /* msg not handled, then try here */
238 switch(msg)
239 {
240 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
241 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_lc7981_160x80_display_info);
242 break;
243 case U8X8_MSG_DISPLAY_INIT:
244 u8x8_d_helper_display_init(u8x8);
245 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_160x80_init_seq);
246 break;
247 default:
248 return 0; /* msg unknown */
249 }
250 }
251 return 1;
252}
253
254
255/*================================================*/
256/* LC7981 160x160 LCD*/
257
258static const u8x8_display_info_t u8x8_lc7981_160x160_display_info =
259{
260 /* chip_enable_level = */ 0, /* LC7981 has a low active CS*/
261 /* chip_disable_level = */ 1,
262
263 /* from here... */
264 /* post_chip_enable_wait_ns = */ 20,
265 /* pre_chip_disable_wait_ns = */ 20,
266 /* reset_pulse_width_ms = */ 1,
267 /* post_reset_wait_ms = */ 10,
268 /* sda_setup_time_ns = */ 30,
269 /* sck_pulse_width_ns = */ 65, /* half of cycle time */
270 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
271 /* spi_mode = */ 0, /* active high, rising edge */
272 /* i2c_bus_clock_100kHz = */ 4,
273 /* ... to here, values are ignored, because this is a parallel interface only */
274
275 /* data_setup_time_ns = */ 220,
276 /* write_pulse_width_ns = */ 20,
277 /* tile_width = */ 20, /* width of 20*8=160 pixel */
278 /* tile_height = */ 20,
279 /* default_x_offset = */ 0,
280 /* flipmode_x_offset = */ 0,
281 /* pixel_width = */ 160,
282 /* pixel_height = */ 160
283};
284
285static const uint8_t u8x8_d_lc7981_160x160_init_seq[] = {
286
287 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
288
289 U8X8_DLY(50),
290
291 U8X8_CA(0x00, 0x32), /* display on (bit 5), master mode on (bit 4), graphics mode on (bit 1) */
292 U8X8_CA(0x01, 0x07), /* character/bits per pixel pitch */
293 U8X8_CA(0x02, 160/8-1), /* number of chars/byte width of the screen */
294 U8X8_CA(0x03, 159), /* time division */
295 U8X8_CA(0x08, 0x00), /* display start low */
296 U8X8_CA(0x09, 0x00), /* display start high */
297
298 U8X8_DLY(10),
299
300 U8X8_END_TRANSFER(), /* disable chip */
301 U8X8_END() /* end of sequence */
302};
303
304uint8_t u8x8_d_lc7981_160x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
305{
306 /* call common procedure first and handle messages there */
307 if ( u8x8_d_lc7981_common(u8x8, msg, arg_int, arg_ptr) == 0 )
308 {
309 /* msg not handled, then try here */
310 switch(msg)
311 {
312 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
313 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_lc7981_160x160_display_info);
314 break;
315 case U8X8_MSG_DISPLAY_INIT:
316 u8x8_d_helper_display_init(u8x8);
317 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_160x160_init_seq);
318 break;
319 default:
320 return 0; /* msg unknown */
321 }
322 }
323 return 1;
324}
325
326
327/*================================================*/
328/* LC7981 240x128 LCD*/
329
330static const u8x8_display_info_t u8x8_lc7981_240x128_display_info =
331{
332 /* chip_enable_level = */ 0, /* LC7981 has a low active CS*/
333 /* chip_disable_level = */ 1,
334
335 /* from here... */
336 /* post_chip_enable_wait_ns = */ 20,
337 /* pre_chip_disable_wait_ns = */ 20,
338 /* reset_pulse_width_ms = */ 1,
339 /* post_reset_wait_ms = */ 10,
340 /* sda_setup_time_ns = */ 30,
341 /* sck_pulse_width_ns = */ 65, /* half of cycle time */
342 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
343 /* spi_mode = */ 0, /* active high, rising edge */
344 /* i2c_bus_clock_100kHz = */ 4,
345 /* ... to here, values are ignored, because this is a parallel interface only */
346
347 /* data_setup_time_ns = */ 220,
348 /* write_pulse_width_ns = */ 20,
349 /* tile_width = */ 30, /* width of 30*8=240 pixel */
350 /* tile_height = */ 16,
351 /* default_x_offset = */ 0,
352 /* flipmode_x_offset = */ 0,
353 /* pixel_width = */ 240,
354 /* pixel_height = */ 128
355};
356
357static const uint8_t u8x8_d_lc7981_240x128_init_seq[] = {
358
359 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
360
361 U8X8_DLY(50),
362
363 U8X8_CA(0x00, 0x32), /* display on (bit 5), master mode on (bit 4), graphics mode on (bit 1) */
364 U8X8_CA(0x01, 0x07), /* character/bits per pixel pitch */
365 U8X8_CA(0x02, 240/8-1), /* number of chars/byte width of the screen */
366 U8X8_CA(0x03, 16*8-1), /* time division */
367 U8X8_CA(0x08, 0x00), /* display start low */
368 U8X8_CA(0x09, 0x00), /* display start high */
369
370 U8X8_DLY(10),
371
372 U8X8_END_TRANSFER(), /* disable chip */
373 U8X8_END() /* end of sequence */
374};
375
376uint8_t u8x8_d_lc7981_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
377{
378 /* call common procedure first and handle messages there */
379 if ( u8x8_d_lc7981_common(u8x8, msg, arg_int, arg_ptr) == 0 )
380 {
381 /* msg not handled, then try here */
382 switch(msg)
383 {
384 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
385 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_lc7981_240x128_display_info);
386 break;
387 case U8X8_MSG_DISPLAY_INIT:
388 u8x8_d_helper_display_init(u8x8);
389 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_240x128_init_seq);
390 break;
391 default:
392 return 0; /* msg unknown */
393 }
394 }
395 return 1;
396}
397
398
399/*================================================*/
400/* LC7981 240x64 LCD*/
401/* https://github.com/olikraus/u8g2/issues/642 */
402
403static const u8x8_display_info_t u8x8_lc7981_240x64_display_info =
404{
405 /* chip_enable_level = */ 0, /* LC7981 has a low active CS*/
406 /* chip_disable_level = */ 1,
407
408 /* from here... */
409 /* post_chip_enable_wait_ns = */ 20,
410 /* pre_chip_disable_wait_ns = */ 20,
411 /* reset_pulse_width_ms = */ 1,
412 /* post_reset_wait_ms = */ 10,
413 /* sda_setup_time_ns = */ 30,
414 /* sck_pulse_width_ns = */ 65, /* half of cycle time */
415 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
416 /* spi_mode = */ 0, /* active high, rising edge */
417 /* i2c_bus_clock_100kHz = */ 4,
418 /* ... to here, values are ignored, because this is a parallel interface only */
419
420 /* data_setup_time_ns = */ 220,
421 /* write_pulse_width_ns = */ 20,
422 /* tile_width = */ 30, /* width of 30*8=240 pixel */
423 /* tile_height = */ 8,
424 /* default_x_offset = */ 0,
425 /* flipmode_x_offset = */ 0,
426 /* pixel_width = */ 240,
427 /* pixel_height = */ 64
428};
429
430static const uint8_t u8x8_d_lc7981_240x64_init_seq[] = {
431
432 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
433
434 U8X8_DLY(50),
435
436 U8X8_CA(0x00, 0x32), /* display on (bit 5), master mode on (bit 4), graphics mode on (bit 1) */
437 U8X8_CA(0x01, 0x07), /* character/bits per pixel pitch */
438 U8X8_CA(0x02, 240/8-1), /* number of chars/byte width of the screen */
439 U8X8_CA(0x03, 0x7f), /* time division */
440 U8X8_CA(0x08, 0x00), /* display start low */
441 U8X8_CA(0x09, 0x00), /* display start high */
442
443 U8X8_DLY(10),
444
445 U8X8_END_TRANSFER(), /* disable chip */
446 U8X8_END() /* end of sequence */
447};
448
449uint8_t u8x8_d_lc7981_240x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
450{
451 /* call common procedure first and handle messages there */
452 if ( u8x8_d_lc7981_common(u8x8, msg, arg_int, arg_ptr) == 0 )
453 {
454 /* msg not handled, then try here */
455 switch(msg)
456 {
457 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
458 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_lc7981_240x64_display_info);
459 break;
460 case U8X8_MSG_DISPLAY_INIT:
461 u8x8_d_helper_display_init(u8x8);
462 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_240x64_init_seq);
463 break;
464 default:
465 return 0; /* msg unknown */
466 }
467 }
468 return 1;
469}
470
471
472/*================================================*/
473/* LC7981 128x128 LCD, https://github.com/olikraus/u8g2/issues/1913*/
474
475static const u8x8_display_info_t u8x8_lc7981_128x128_display_info =
476{
477 /* chip_enable_level = */ 0, /* LC7981 has a low active CS*/
478 /* chip_disable_level = */ 1,
479
480 /* from here... */
481 /* post_chip_enable_wait_ns = */ 20,
482 /* pre_chip_disable_wait_ns = */ 20,
483 /* reset_pulse_width_ms = */ 1,
484 /* post_reset_wait_ms = */ 10,
485 /* sda_setup_time_ns = */ 30,
486 /* sck_pulse_width_ns = */ 65, /* half of cycle time */
487 /* sck_clock_hz = */ 4000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
488 /* spi_mode = */ 0, /* active high, rising edge */
489 /* i2c_bus_clock_100kHz = */ 4,
490 /* ... to here, values are ignored, because this is a parallel interface only */
491
492 /* data_setup_time_ns = */ 220,
493 /* write_pulse_width_ns = */ 20,
494 /* tile_width = */ 16, /* width of 16*8=128 pixel */
495 /* tile_height = */ 16,
496 /* default_x_offset = */ 0,
497 /* flipmode_x_offset = */ 0,
498 /* pixel_width = */ 128,
499 /* pixel_height = */ 128
500};
501
502static const uint8_t u8x8_d_lc7981_128x128_init_seq[] = {
503
504 U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
505
506 U8X8_DLY(50),
507
508 U8X8_CA(0x00, 0x32), /* display on (bit 5), master mode on (bit 4), graphics mode on (bit 1) */
509 U8X8_CA(0x01, 0x07), /* character/bits per pixel pitch */
510 U8X8_CA(0x02, 128/8-1), /* number of chars/byte width of the screen */
511 U8X8_CA(0x03, 128), /* time division, issue https://github.com/olikraus/u8g2/issues/1581 */
512 U8X8_CA(0x08, 0x00), /* display start low */
513 U8X8_CA(0x09, 0x00), /* display start high */
514
515 U8X8_DLY(10),
516
517 U8X8_END_TRANSFER(), /* disable chip */
518 U8X8_END() /* end of sequence */
519};
520
521uint8_t u8x8_d_lc7981_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
522{
523 /* call common procedure first and handle messages there */
524 if ( u8x8_d_lc7981_common(u8x8, msg, arg_int, arg_ptr) == 0 )
525 {
526 /* msg not handled, then try here */
527 switch(msg)
528 {
529 case U8X8_MSG_DISPLAY_SETUP_MEMORY:
530 u8x8_d_helper_display_setup_memory(u8x8, &u8x8_lc7981_128x128_display_info);
531 break;
532 case U8X8_MSG_DISPLAY_INIT:
533 u8x8_d_helper_display_init(u8x8);
534 u8x8_cad_SendSequence(u8x8, u8x8_d_lc7981_128x128_init_seq);
535 break;
536 default:
537 return 0; /* msg unknown */
538 }
539 }
540 return 1;
541}
542