1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2020-08-10     zylx              first version
9  * 2022-02-01     Rudy Lo           add lcd_fill_array function
10  */
11 
12 #include <board.h>
13 
14 #ifdef BSP_USING_SPI_LCD_ILI9488
15 #include <rtdevice.h>
16 #include "drv_spi.h"
17 #include "drv_spi_ili9488.h"
18 #include <lcd_spi_port.h>
19 #include "drv_lcd_font.h"
20 #include <rttlogo.h>
21 #include <string.h>
22 
23 #if defined(PKG_USING_GUIENGINE)
24 #include <rtgui/driver.h>
25 #endif
26 
27 #define DRV_DEBUG
28 #define LOG_TAG             "drv.spi_lcd"
29 #include <drv_log.h>
30 
31 #define LCD_DC_PIN            GET_PIN(C, 7)
32 
33 #define LCD_DEVICE(dev)     (struct drv_lcd_device*)(dev)
34 
35 #define LCD_CLEAR_SEND_NUMBER (LCD_H * LCD_W *3)
36 
37 static rt_uint32_t BACK_COLOR = WHITE, FORE_COLOR = BLACK;
38 static struct rt_spi_device *spi_dev_lcd;
39 
rt_hw_lcd_config(void)40 static int rt_hw_lcd_config(void)
41 {
42     spi_dev_lcd = (struct rt_spi_device *)rt_device_find("spi20");
43 
44     /* config spi */
45     {
46         struct rt_spi_configuration cfg;
47         cfg.data_width = 8;
48         cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
49         cfg.max_hz = 50 * 1000 * 1000;
50 
51         rt_spi_configure(spi_dev_lcd, &cfg);
52     }
53 
54     return RT_EOK;
55 }
56 
lcd_write_cmd(const rt_uint8_t cmd)57 static rt_err_t lcd_write_cmd(const rt_uint8_t cmd)
58 {
59     rt_size_t len;
60 
61     rt_pin_write(LCD_DC_PIN, PIN_LOW);
62 
63     len = rt_spi_send(spi_dev_lcd, &cmd, 1);
64 
65     if (len != 1)
66     {
67         LOG_I("lcd_write_cmd error. %d", len);
68         return -RT_ERROR;
69     }
70     else
71     {
72         return RT_EOK;
73     }
74 }
75 
lcd_write_data(const rt_uint8_t data)76 static rt_err_t lcd_write_data(const rt_uint8_t data)
77 {
78     rt_size_t len;
79 
80     rt_pin_write(LCD_DC_PIN, PIN_HIGH);
81 
82     len = rt_spi_send(spi_dev_lcd, &data, 1);
83 
84     if (len != 1)
85     {
86         LOG_I("lcd_write_data error. %d", len);
87         return -RT_ERROR;
88     }
89     else
90     {
91         return RT_EOK;
92     }
93 }
94 
lcd_write_half_word(const rt_uint16_t da)95 static rt_err_t lcd_write_half_word(const rt_uint16_t da)
96 {
97     rt_size_t len;
98     char data[2] = {0};
99 
100     data[0] = da >> 8;
101     data[1] = da;
102 
103     rt_pin_write(LCD_DC_PIN, PIN_HIGH);
104     len = rt_spi_send(spi_dev_lcd, data, 2);
105     if (len != 2)
106     {
107         LOG_I("lcd_write_half_word error. %d", len);
108         return -RT_ERROR;
109     }
110     else
111     {
112         return RT_EOK;
113     }
114 }
115 
lcd_write_three_bytes(const rt_uint32_t da)116 static rt_err_t lcd_write_three_bytes(const rt_uint32_t da)
117 {
118     rt_size_t len;
119     char data[3] = {0};
120 
121     data[0] = da >> 16;
122     data[1] = da >> 8;
123     data[2] = da;
124 
125     rt_pin_write(LCD_DC_PIN, PIN_HIGH);
126     len = rt_spi_send(spi_dev_lcd, data, 3);
127     if (len != 3)
128     {
129         LOG_I("lcd_write_half_word error. %d", len);
130         return -RT_ERROR;
131     }
132     else
133     {
134         return RT_EOK;
135     }
136 }
137 
lcd_gpio_init(void)138 static void lcd_gpio_init(void)
139 {
140     rt_hw_lcd_config();
141 
142     __HAL_RCC_GPIOC_CLK_ENABLE();
143     rt_pin_mode(LCD_DC_PIN, PIN_MODE_OUTPUT);
144     rt_pin_mode(LCD_BL_PIN, PIN_MODE_OUTPUT);
145     rt_pin_mode(LCD_RES_PIN, PIN_MODE_OUTPUT);
146     rt_pin_write(LCD_BL_PIN, PIN_LOW);
147 }
148 
rt_hw_spi_lcd_init(void)149 int rt_hw_spi_lcd_init(void)
150 {
151     __HAL_RCC_GPIOI_CLK_ENABLE();
152     rt_hw_spi_device_attach("spi2", "spi20", GET_PIN(I, 0));
153     lcd_gpio_init();
154 
155     rt_pin_write(LCD_RES_PIN, PIN_HIGH);
156     rt_thread_mdelay(10);
157     rt_pin_write(LCD_RES_PIN, PIN_LOW);
158     rt_thread_mdelay(50);
159     rt_pin_write(LCD_RES_PIN, PIN_HIGH);
160     rt_thread_mdelay(200);
161 
162     //************* Start Initial Sequence **********//
163     lcd_write_cmd(0xE0);
164     lcd_write_data(0x00);
165     lcd_write_data(0x07);
166     lcd_write_data(0x0f);
167     lcd_write_data(0x0D);
168     lcd_write_data(0x1B);
169     lcd_write_data(0x0A);
170     lcd_write_data(0x3c);
171     lcd_write_data(0x78);
172     lcd_write_data(0x4A);
173     lcd_write_data(0x07);
174     lcd_write_data(0x0E);
175     lcd_write_data(0x09);
176     lcd_write_data(0x1B);
177     lcd_write_data(0x1e);
178     lcd_write_data(0x0f);
179 
180     lcd_write_cmd(0xE1);
181     lcd_write_data(0x00);
182     lcd_write_data(0x22);
183     lcd_write_data(0x24);
184     lcd_write_data(0x06);
185     lcd_write_data(0x12);
186     lcd_write_data(0x07);
187     lcd_write_data(0x36);
188     lcd_write_data(0x47);
189     lcd_write_data(0x47);
190     lcd_write_data(0x06);
191     lcd_write_data(0x0a);
192     lcd_write_data(0x07);
193     lcd_write_data(0x30);
194     lcd_write_data(0x37);
195     lcd_write_data(0x0f);
196 
197     lcd_write_cmd(0xC0);
198     lcd_write_data(0x10);
199     lcd_write_data(0x10);
200 
201     lcd_write_cmd(0xC1);
202     lcd_write_data(0x41);
203 
204     lcd_write_cmd(0xC5);
205     lcd_write_data(0x00);
206     lcd_write_data(0x22);
207     lcd_write_data(0x80);
208 
209     lcd_write_cmd(0x36);
210 #ifndef LCD_HOR_SCREEN
211     lcd_write_data(0x48);
212 #else
213     lcd_write_data(0x28);
214 #endif
215 
216     lcd_write_cmd(0x3A);   //Interface Mode Control
217     lcd_write_data(0x66);
218 
219     lcd_write_cmd(0XB0);   //Interface Mode Control
220     lcd_write_data(0x00);
221     lcd_write_cmd(0xB1);   //Frame rate 70HZ
222     lcd_write_data(0xB0);
223     lcd_write_data(0x11);
224     lcd_write_cmd(0xB4);
225     lcd_write_data(0x02);
226     lcd_write_cmd(0xB6);   //RGB/MCU Interface Control
227     lcd_write_data(0x02);
228     lcd_write_data(0x02);
229 
230     lcd_write_cmd(0xB7);
231     lcd_write_data(0xC6);
232 
233     lcd_write_cmd(0xE9);
234     lcd_write_data(0x00);
235 
236     lcd_write_cmd(0XF7);
237     lcd_write_data(0xA9);
238     lcd_write_data(0x51);
239     lcd_write_data(0x2C);
240     lcd_write_data(0x82);
241 
242     lcd_fill(0, 0, LCD_WIDTH, LCD_HEIGHT, LCD_FULL_COLOR);
243 
244     lcd_write_cmd(0x11);
245     rt_thread_mdelay(120);
246     lcd_write_cmd(0x29);
247 
248     rt_thread_mdelay(50);   //delay screen update to prevent screen appears white when the default color is black
249 
250     return RT_EOK;
251 }
252 
253 /**
254  * Set background color and foreground color
255  *
256  * @param   back    background color
257  * @param   fore    fore color
258  *
259  * @return  void
260  */
lcd_set_color(rt_uint32_t back,rt_uint32_t fore)261 void lcd_set_color(rt_uint32_t back, rt_uint32_t fore)
262 {
263     BACK_COLOR = back;
264     FORE_COLOR = fore;
265 }
266 
lcd_display_on(void)267 void lcd_display_on(void)
268 {
269     rt_pin_write(LCD_BL_PIN, PIN_HIGH);
270 }
271 
lcd_display_off(void)272 void lcd_display_off(void)
273 {
274     rt_pin_write(LCD_BL_PIN, PIN_LOW);
275 }
276 
277 /* lcd enter the minimum power consumption mode and backlight off. */
lcd_enter_sleep(void)278 void lcd_enter_sleep(void)
279 {
280     lcd_display_off();
281     rt_thread_mdelay(5);
282     lcd_write_cmd(0x28);
283     rt_thread_mdelay(10);
284     lcd_write_cmd(0x10);
285     rt_thread_mdelay(120);
286 }
287 /* lcd turn off sleep mode and backlight on. */
lcd_exit_sleep(void)288 void lcd_exit_sleep(void)
289 {
290     lcd_display_on();
291     rt_thread_mdelay(5);
292     lcd_write_cmd(0x11);
293     rt_thread_mdelay(120);
294     lcd_write_cmd(0x29);
295 }
296 
297 /**
298  * Set drawing area
299  *
300  * @param   x1      start of x position
301  * @param   y1      start of y position
302  * @param   x2      end of x position
303  * @param   y2      end of y position
304  *
305  * @return  void
306  */
lcd_address_set(rt_uint16_t x1,rt_uint16_t y1,rt_uint16_t x2,rt_uint16_t y2)307 void lcd_address_set(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2)
308 {
309     lcd_write_cmd(0x2a);
310     lcd_write_data(x1 >> 8);
311     lcd_write_data(x1);
312     lcd_write_data(x2 >> 8);
313     lcd_write_data(x2);
314 
315     lcd_write_cmd(0x2b);
316     lcd_write_data(y1 >> 8);
317     lcd_write_data(y1);
318     lcd_write_data(y2 >> 8);
319     lcd_write_data(y2);
320 
321     lcd_write_cmd(0x2C);
322 }
323 
324 /**
325  * clear the lcd.
326  *
327  * @param   color       Fill color
328  *
329  * @return  void
330  */
lcd_clear(rt_uint32_t color)331 void lcd_clear(rt_uint32_t color)
332 {
333     rt_uint32_t i, j;
334     rt_uint8_t data[3] = {0};
335     rt_uint8_t *buf = RT_NULL;
336 
337     data[0] = color >> 16;
338     data[1] = color >> 8;
339     data[2] = color;
340     lcd_address_set(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
341 
342     buf = rt_malloc(LCD_BUF_SIZE);
343     if (buf)
344     {
345         /* color is 16 bit */
346         for (j = 0; j < LCD_BUF_SIZE / 3; j++)
347         {
348             buf[j * 3] =  data[0];
349             buf[j * 3 + 1] =  data[1];
350             buf[j * 3 + 2] =  data[2];
351         }
352 
353         rt_pin_write(LCD_DC_PIN, PIN_HIGH);
354         rt_spi_send(spi_dev_lcd, buf, LCD_BUF_SIZE);
355         rt_free(buf);
356     }
357     else
358     {
359         rt_pin_write(LCD_DC_PIN, PIN_HIGH);
360         for (i = 0; i < LCD_WIDTH; i++)
361         {
362             for (j = 0; j < LCD_HEIGHT; j++)
363             {
364                 rt_spi_send(spi_dev_lcd, data, 3);
365             }
366         }
367     }
368 }
369 
370 /**
371  * display a point on the lcd using the given colour.
372  *
373  * @param   x       x position
374  * @param   y       y position
375  * @param   color   color of point
376  *
377  * @return  void
378  */
lcd_draw_point_color(rt_uint16_t x,rt_uint16_t y,rt_uint32_t color)379 void lcd_draw_point_color(rt_uint16_t x, rt_uint16_t y, rt_uint32_t color)
380 {
381     lcd_address_set(x, y, x, y);
382     lcd_write_three_bytes(color);
383 }
384 
385 /**
386  * display a point on the lcd.
387  *
388  * @param   x   x position
389  * @param   y   y position
390  *
391  * @return  void
392  */
lcd_draw_point(rt_uint16_t x,rt_uint16_t y)393 void lcd_draw_point(rt_uint16_t x, rt_uint16_t y)
394 {
395     lcd_draw_point_color(x, y, FORE_COLOR);
396 }
397 
398 /**
399  * full color on the lcd.
400  *
401  * @param   x_start     start of x position
402  * @param   y_start     start of y position
403  * @param   x_end       end of x position
404  * @param   y_end       end of y position
405  * @param   color       Fill color
406  *
407  * @return  void
408  */
lcd_fill(rt_uint16_t x_start,rt_uint16_t y_start,rt_uint16_t x_end,rt_uint16_t y_end,rt_uint32_t color)409 void lcd_fill(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end, rt_uint16_t y_end, rt_uint32_t color)
410 {
411     rt_uint32_t i = 0, j = 0;
412     rt_uint32_t size = 0, size_remain = 0;
413     rt_uint8_t *fill_buf = RT_NULL;
414 
415     size = (x_end - x_start) * (y_end - y_start) * 3;
416 
417     if (size > LCD_CLEAR_SEND_NUMBER)
418     {
419         /* the number of remaining to be filled */
420         size_remain = size - LCD_CLEAR_SEND_NUMBER;
421         size = LCD_CLEAR_SEND_NUMBER;
422     }
423 
424     lcd_address_set(x_start, y_start, x_end, y_end);
425 
426     fill_buf = (rt_uint8_t *)rt_malloc(LCD_CLEAR_SEND_NUMBER);
427     if (fill_buf)
428     {
429         /* fast fill */
430         while (1)
431         {
432             for (i = 0; i < size / 3; i++)
433             {
434                 fill_buf[3 * i] = color >> 16;
435                 fill_buf[3 * i + 1] = color >> 8;
436                 fill_buf[3 * i + 2] = color;
437             }
438             rt_pin_write(LCD_DC_PIN, PIN_HIGH);
439             rt_spi_send(spi_dev_lcd, fill_buf, size);
440 
441             /* Fill completed */
442             if (size_remain == 0)
443                 break;
444 
445             /* calculate the number of fill next time */
446             if (size_remain > LCD_CLEAR_SEND_NUMBER)
447             {
448                 size_remain = size_remain - LCD_CLEAR_SEND_NUMBER;
449             }
450             else
451             {
452                 size = size_remain;
453                 size_remain = 0;
454             }
455 
456         }
457         rt_free(fill_buf);
458     }
459     else
460     {
461         for (i = y_start; i <= y_end; i++)
462         {
463             for (j = x_start; j <= x_end; j++)lcd_write_three_bytes(color);
464         }
465     }
466 }
467 
468 /**
469  * full color array on the lcd.
470  *
471  * @param   x_start     start of x position
472  * @param   y_start     start of y position
473  * @param   x_end       end of x position
474  * @param   y_end       end of y position
475  * @param   pcolor      Fill color array's pointer
476  *
477  * @return  void
478  */
lcd_fill_array(rt_uint16_t x_start,rt_uint16_t y_start,rt_uint16_t x_end,rt_uint16_t y_end,void * pcolor)479 void lcd_fill_array(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end, rt_uint16_t y_end, void *pcolor)
480 {
481     rt_uint32_t size = 0;
482     rt_uint8_t *array = RT_NULL;
483 
484     size = (x_end - x_start + 1) * (y_end - y_start + 1) * 3 /* 24bit */;
485     array = (rt_uint8_t *)rt_malloc(size);
486 
487     if (!array) {
488         LOG_E("not enough memory");
489         return ;
490     }
491 
492     rt_uint32_t *color_p = (rt_uint32_t *)pcolor;
493 
494     for (rt_uint16_t i = 0; i < size / 3; i++)
495     {
496         array[3 * i] = *color_p >> 16;
497         array[3 * i + 1] = *color_p >> 8;
498         array[3 * i + 2] = *color_p;
499         color_p++;
500     }
501 
502     lcd_address_set(x_start, y_start, x_end, y_end);
503     rt_pin_write(LCD_DC_PIN, PIN_HIGH);
504     rt_spi_send(spi_dev_lcd, array, size);
505 
506     rt_free(array);
507 }
508 
509 /**
510  * display a line on the lcd.
511  *
512  * @param   x1      x1 position
513  * @param   y1      y1 position
514  * @param   x2      x2 position
515  * @param   y2      y2 position
516  *
517  * @return  void
518  */
lcd_draw_line(rt_uint16_t x1,rt_uint16_t y1,rt_uint16_t x2,rt_uint16_t y2)519 void lcd_draw_line(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2)
520 {
521     rt_uint16_t t;
522     rt_uint32_t i = 0;
523     int xerr = 0, yerr = 0, delta_x, delta_y, distance;
524     int incx, incy, row, col;
525 
526     if (y1 == y2)
527     {
528         /* fast draw transverse line */
529         lcd_address_set(x1, y1, x2, y2);
530 
531         rt_uint8_t line_buf[960] = {0};
532 
533         for (i = 0; i < x2 - x1; i++)
534         {
535             line_buf[3 * i] = FORE_COLOR >> 16;
536             line_buf[3 * i + 1] = FORE_COLOR >> 8;
537             line_buf[3 * i + 2] = FORE_COLOR;
538         }
539 
540         rt_pin_write(LCD_DC_PIN, PIN_HIGH);
541         rt_spi_send(spi_dev_lcd, line_buf, (x2 - x1) * 3);
542 
543         return ;
544     }
545 
546     delta_x = x2 - x1;
547     delta_y = y2 - y1;
548     row = x1;
549     col = y1;
550     if (delta_x > 0)incx = 1;
551     else if (delta_x == 0)incx = 0;
552     else
553     {
554         incx = -1;
555         delta_x = -delta_x;
556     }
557     if (delta_y > 0)incy = 1;
558     else if (delta_y == 0)incy = 0;
559     else
560     {
561         incy = -1;
562         delta_y = -delta_y;
563     }
564     if (delta_x > delta_y)distance = delta_x;
565     else distance = delta_y;
566     for (t = 0; t <= distance + 1; t++)
567     {
568         lcd_draw_point(row, col);
569         xerr += delta_x ;
570         yerr += delta_y ;
571         if (xerr > distance)
572         {
573             xerr -= distance;
574             row += incx;
575         }
576         if (yerr > distance)
577         {
578             yerr -= distance;
579             col += incy;
580         }
581     }
582 }
583 
584 /**
585  * display a rectangle on the lcd.
586  *
587  * @param   x1      x1 position
588  * @param   y1      y1 position
589  * @param   x2      x2 position
590  * @param   y2      y2 position
591  *
592  * @return  void
593  */
lcd_draw_rectangle(rt_uint16_t x1,rt_uint16_t y1,rt_uint16_t x2,rt_uint16_t y2)594 void lcd_draw_rectangle(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2)
595 {
596     lcd_draw_line(x1, y1, x2, y1);
597     lcd_draw_line(x1, y1, x1, y2);
598     lcd_draw_line(x1, y2, x2, y2);
599     lcd_draw_line(x2, y1, x2, y2);
600 }
601 
602 /**
603  * display a circle on the lcd.
604  *
605  * @param   x       x position of Center
606  * @param   y       y position of Center
607  * @param   r       radius
608  *
609  * @return  void
610  */
lcd_draw_circle(rt_uint16_t x0,rt_uint16_t y0,rt_uint8_t r)611 void lcd_draw_circle(rt_uint16_t x0, rt_uint16_t y0, rt_uint8_t r)
612 {
613     int a, b;
614     int di;
615     a = 0;
616     b = r;
617     di = 3 - (r << 1);
618     while (a <= b)
619     {
620         lcd_draw_point(x0 - b, y0 - a);
621         lcd_draw_point(x0 + b, y0 - a);
622         lcd_draw_point(x0 - a, y0 + b);
623         lcd_draw_point(x0 - b, y0 - a);
624         lcd_draw_point(x0 - a, y0 - b);
625         lcd_draw_point(x0 + b, y0 + a);
626         lcd_draw_point(x0 + a, y0 - b);
627         lcd_draw_point(x0 + a, y0 + b);
628         lcd_draw_point(x0 - b, y0 + a);
629         a++;
630         //Bresenham
631         if (di < 0)di += 4 * a + 6;
632         else
633         {
634             di += 10 + 4 * (a - b);
635             b--;
636         }
637         lcd_draw_point(x0 + a, y0 + b);
638     }
639 }
640 
lcd_show_char(rt_uint16_t x,rt_uint16_t y,rt_uint8_t data,rt_uint32_t size)641 static void lcd_show_char(rt_uint16_t x, rt_uint16_t y, rt_uint8_t data, rt_uint32_t size)
642 {
643     rt_uint8_t temp;
644     rt_uint8_t num = 0;;
645     rt_uint8_t pos, t;
646     rt_uint32_t colortemp = FORE_COLOR;
647     rt_uint8_t *font_buf = RT_NULL;
648 
649     if (x > LCD_WIDTH - size / 2 || y > LCD_HEIGHT - size)return;
650 
651     data = data - ' ';
652 #ifdef ASC2_1608
653     if (size == 16)
654     {
655         lcd_address_set(x, y, x + size / 2 - 1, y + size - 1);//(x,y,x+8-1,y+16-1)
656 
657         font_buf = (rt_uint8_t *)rt_malloc(size * size / 2 * 3);
658         if (!font_buf)
659         {
660             /* fast show char */
661             for (pos = 0; pos < size * (size / 2) / 8; pos++)
662             {
663                 temp = asc2_1608[(rt_uint16_t)data * size * (size / 2) / 8 + pos];
664                 for (t = 0; t < 8; t++)
665                 {
666                     if (temp & 0x80)colortemp = FORE_COLOR;
667                     else colortemp = BACK_COLOR;
668                     lcd_write_three_bytes(colortemp);
669                     temp <<= 1;
670                 }
671             }
672         }
673         else
674         {
675             for (pos = 0; pos < size * (size / 2) / 8; pos++)
676             {
677                 temp = asc2_1608[(rt_uint16_t)data * size * (size / 2) / 8 + pos];
678                 for (t = 0; t < 8; t++)
679                 {
680                     if (temp & 0x80)colortemp = FORE_COLOR;
681                     else colortemp = BACK_COLOR;
682                     font_buf[3 * (8 * pos + t)] = colortemp >> 16;
683                     font_buf[3 * (8 * pos + t) + 1] = colortemp >> 8;
684                     font_buf[3 * (8 * pos + t) + 2] = colortemp;
685                     temp <<= 1;
686                 }
687             }
688             rt_pin_write(LCD_DC_PIN, PIN_HIGH);
689             rt_spi_send(spi_dev_lcd, font_buf, size * size / 2 * 3);
690             rt_free(font_buf);
691         }
692     }
693     else
694 #endif
695 
696 #ifdef ASC2_2412
697         if (size == 24)
698         {
699             lcd_address_set(x, y, x + size / 2 - 1, y + size - 1);
700 
701             font_buf = (rt_uint8_t *)rt_malloc(size * size / 2 * 3);
702             if (!font_buf)
703             {
704                 /* fast show char */
705                 for (pos = 0; pos < (size * 16) / 8; pos++)
706                 {
707                     temp = asc2_2412[(rt_uint16_t)data * (size * 16) / 8 + pos];
708                     if (pos % 2 == 0)
709                     {
710                         num = 8;
711                     }
712                     else
713                     {
714                         num = 4;
715                     }
716 
717                     for (t = 0; t < num; t++)
718                     {
719                         if (temp & 0x80)colortemp = FORE_COLOR;
720                         else colortemp = BACK_COLOR;
721                         lcd_write_three_bytes(colortemp);
722                         temp <<= 1;
723                     }
724                 }
725             }
726             else
727             {
728                 for (pos = 0; pos < (size * 16) / 8; pos++)
729                 {
730                     temp = asc2_2412[(rt_uint16_t)data * (size * 16) / 8 + pos];
731                     if (pos % 2 == 0)
732                     {
733                         num = 8;
734                     }
735                     else
736                     {
737                         num = 4;
738                     }
739 
740                     for (t = 0; t < num; t++)
741                     {
742                         if (temp & 0x80)colortemp = FORE_COLOR;
743                         else colortemp = BACK_COLOR;
744                         if (num == 8)
745                         {
746                             font_buf[3 * (12 * (pos / 2) + t)] = colortemp >> 16;
747                             font_buf[3 * (12 * (pos / 2) + t) + 1] = colortemp >> 8;
748                             font_buf[3 * (12 * (pos / 2) + t) + 2] = colortemp;
749                         }
750                         else
751                         {
752                             font_buf[3 * (8 + 12 * (pos / 2) + t)] = colortemp >> 16;
753                             font_buf[3 * (8 + 12 * (pos / 2) + t) + 1] = colortemp >> 8;
754                             font_buf[3 * (8 + 12 * (pos / 2) + t) + 2] = colortemp;
755                         }
756                         temp <<= 1;
757                     }
758                 }
759                 rt_pin_write(LCD_DC_PIN, PIN_HIGH);
760                 rt_spi_send(spi_dev_lcd, font_buf, size * size / 2 * 3);
761                 rt_free(font_buf);
762             }
763         }
764         else
765 #endif
766 
767 #ifdef ASC2_3216
768             if (size == 32)
769             {
770                 lcd_address_set(x, y, x + size / 2 - 1, y + size - 1);
771 
772                 font_buf = (rt_uint8_t *)rt_malloc(size * size / 2 * 3);
773                 if (!font_buf)
774                 {
775                     /* fast show char */
776                     for (pos = 0; pos < size * (size / 2) / 8; pos++)
777                     {
778                         temp = asc2_3216[(rt_uint16_t)data * size * (size / 2) / 8 + pos];
779                         for (t = 0; t < 8; t++)
780                         {
781                             if (temp & 0x80)colortemp = FORE_COLOR;
782                             else colortemp = BACK_COLOR;
783                             lcd_write_three_bytes(colortemp);
784                             temp <<= 1;
785                         }
786                     }
787                 }
788                 else
789                 {
790                     for (pos = 0; pos < size * (size / 2) / 8; pos++)
791                     {
792                         temp = asc2_3216[(rt_uint16_t)data * size * (size / 2) / 8 + pos];
793                         for (t = 0; t < 8; t++)
794                         {
795                             if (temp & 0x80)colortemp = FORE_COLOR;
796                             else colortemp = BACK_COLOR;
797                             font_buf[3 * (8 * pos + t)] = colortemp >> 16;
798                             font_buf[3 * (8 * pos + t) + 1] = colortemp >> 8;
799                             font_buf[3 * (8 * pos + t) + 2] = colortemp;
800                             temp <<= 1;
801                         }
802                     }
803                     rt_pin_write(LCD_DC_PIN, PIN_HIGH);
804                     rt_spi_send(spi_dev_lcd, font_buf, size * size / 2 * 3);
805                     rt_free(font_buf);
806                 }
807             }
808             else
809 #endif
810             {
811                 LOG_E("There is no any define ASC2_1208 && ASC2_2412 && ASC2_2416 && ASC2_3216 !");
812             }
813 }
814 
815 /**
816  * display the number on the lcd.
817  *
818  * @param   x       x position
819  * @param   y       y position
820  * @param   num     number
821  * @param   len     length of number
822  * @param   size    size of font
823  *
824  * @return  void
825  */
lcd_show_num(rt_uint16_t x,rt_uint16_t y,rt_uint32_t num,rt_uint8_t len,rt_uint32_t size)826 void lcd_show_num(rt_uint16_t x, rt_uint16_t y, rt_uint32_t num, rt_uint8_t len, rt_uint32_t size)
827 {
828     lcd_show_string(x, y, size, "%d", num);
829 }
830 
831 /**
832  * display the string on the lcd.
833  *
834  * @param   x       x position
835  * @param   y       y position
836  * @param   size    size of font
837  * @param   p       the string to be display
838  *
839  * @return   0: display success
840  *          -1: size of font is not support
841  */
lcd_show_string(rt_uint16_t x,rt_uint16_t y,rt_uint32_t size,const char * fmt,...)842 rt_err_t lcd_show_string(rt_uint16_t x, rt_uint16_t y, rt_uint32_t size, const char *fmt, ...)
843 {
844 #define LCD_STRING_BUF_LEN 128
845 
846     va_list args;
847     rt_uint8_t buf[LCD_STRING_BUF_LEN] = {0};
848     rt_uint8_t *p = RT_NULL;
849 
850     if (size != 16 && size != 24 && size != 32)
851     {
852         LOG_E("font size(%d) is not support!", size);
853         return -RT_ERROR;
854     }
855 
856     va_start(args, fmt);
857     rt_vsnprintf((char *)buf, 100, (const char *)fmt, args);
858     va_end(args);
859 
860     p = buf;
861     while (*p != '\0')
862     {
863         if (x > LCD_WIDTH - size / 2)
864         {
865             x = 0;
866             y += size;
867         }
868         if (y > LCD_HEIGHT - size)
869         {
870             y = x = 0;
871             lcd_clear(RED);
872         }
873         lcd_show_char(x, y, *p, size);
874         x += size / 2;
875         p++;
876     }
877 
878     return RT_EOK;
879 }
880 
881 /**
882  * display the image on the lcd.
883  *
884  * @param   x       x position
885  * @param   y       y position
886  * @param   length  length of image
887  * @param   wide    wide of image
888  * @param   p       image
889  *
890  * @return   0: display success
891  *          -1: the image is too large
892  */
lcd_show_image(rt_uint16_t x,rt_uint16_t y,rt_uint16_t length,rt_uint16_t wide,const rt_uint8_t * p)893 rt_err_t lcd_show_image(rt_uint16_t x, rt_uint16_t y, rt_uint16_t length, rt_uint16_t wide, const rt_uint8_t *p)
894 {
895     RT_ASSERT(p);
896 
897     if (x + length > LCD_WIDTH || y + wide > LCD_HEIGHT)
898     {
899         return -RT_ERROR;
900     }
901 
902     lcd_address_set(x, y, x + length - 1, y + wide - 1);
903 
904     rt_pin_write(LCD_DC_PIN, PIN_HIGH);
905     rt_spi_send(spi_dev_lcd, p, length * wide * 3);
906 
907     return RT_EOK;
908 }
909 
910 struct drv_lcd_device
911 {
912     struct rt_device parent;
913 
914     struct rt_device_graphic_info lcd_info;
915 
916     struct rt_semaphore lcd_lock;
917 
918     /* 0:front_buf is being used 1: back_buf is being used*/
919     rt_uint8_t cur_buf;
920     rt_uint8_t *front_buf;
921     rt_uint8_t *back_buf;
922 };
923 
924 struct drv_lcd_device _lcd;
925 
drv_lcd_init(struct rt_device * device)926 static rt_err_t drv_lcd_init(struct rt_device *device)
927 {
928     struct drv_lcd_device *lcd = LCD_DEVICE(device);
929     /* nothing, right now */
930     lcd = lcd;
931     return RT_EOK;
932 }
933 
drv_lcd_control(struct rt_device * device,int cmd,void * args)934 static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
935 {
936     struct drv_lcd_device *lcd = LCD_DEVICE(device);
937     struct rt_device_rect_info *rect_info = RT_NULL;
938     uint32_t data_start_addr = 0;
939     uint32_t i = 0;
940 
941     switch (cmd)
942     {
943     case RTGRAPHIC_CTRL_RECT_UPDATE:
944     {
945         /* update */
946         rect_info = (struct rt_device_rect_info *)args;
947         if(rect_info != NULL)
948         {
949             data_start_addr = rect_info->y * LCD_BYTES_PER_PIXEL * LCD_WIDTH + rect_info->x * LCD_BYTES_PER_PIXEL;
950             for(i = 0; i < rect_info->height; i++)
951             {
952                 memcpy(&_lcd.front_buf[i * LCD_BYTES_PER_PIXEL * rect_info->width], &_lcd.lcd_info.framebuffer[data_start_addr + i * LCD_BYTES_PER_PIXEL * LCD_WIDTH], rect_info->width * LCD_BYTES_PER_PIXEL);
953             }
954             lcd_show_image(rect_info->x, rect_info->y, rect_info->width, rect_info->height, _lcd.front_buf);
955         }
956         else
957         {
958             memcpy(_lcd.front_buf, _lcd.lcd_info.framebuffer, LCD_BUF_SIZE);
959             lcd_show_image(0, 0, LCD_WIDTH, LCD_HEIGHT, _lcd.front_buf);
960         }
961     }
962     break;
963 
964     case RTGRAPHIC_CTRL_GET_INFO:
965     {
966         struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
967 
968         RT_ASSERT(info != RT_NULL);
969         info->pixel_format   = lcd->lcd_info.pixel_format;
970         info->bits_per_pixel = lcd->lcd_info.bits_per_pixel;
971         info->width          = lcd->lcd_info.width;
972         info->height         = lcd->lcd_info.height;
973         info->framebuffer    = lcd->lcd_info.framebuffer;
974     }
975     break;
976     }
977 
978     return RT_EOK;
979 }
980 
981 #if defined(LCD_BACKLIGHT_USING_GPIO)
turn_on_lcd_backlight(void)982 void turn_on_lcd_backlight(void)
983 {
984     rt_pin_mode(LCD_BL_PIN, PIN_MODE_OUTPUT);
985     rt_pin_write(LCD_BL_PIN, PIN_HIGH);
986 }
987 #else
turn_on_lcd_backlight(void)988 void turn_on_lcd_backlight(void)
989 {
990 
991 }
992 #endif
993 
994 #ifdef RT_USING_DEVICE_OPS
995 const static struct rt_device_ops lcd_ops =
996 {
997     drv_lcd_init,
998     RT_NULL,
999     RT_NULL,
1000     RT_NULL,
1001     RT_NULL,
1002     drv_lcd_control
1003 };
1004 #endif
1005 
drv_lcd_ili9488_hw_init(void)1006 int drv_lcd_ili9488_hw_init(void)
1007 {
1008     rt_err_t result = RT_EOK;
1009     struct rt_device *device = &_lcd.parent;
1010 
1011     /* memset _lcd to zero */
1012     memset(&_lcd, 0x00, sizeof(_lcd));
1013 
1014     /* init lcd_lock semaphore */
1015     result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
1016     if (result != RT_EOK)
1017     {
1018         LOG_E("init semaphore failed!\n");
1019         result = -RT_ENOMEM;
1020         goto __exit;
1021     }
1022 
1023     /* config LCD dev info */
1024     _lcd.lcd_info.height = LCD_HEIGHT;
1025     _lcd.lcd_info.width = LCD_WIDTH;
1026     _lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
1027     _lcd.lcd_info.pixel_format = LCD_PIXEL_FORMAT;
1028 
1029     /* malloc memory for double Buffering */
1030     _lcd.lcd_info.framebuffer = rt_malloc(LCD_BUF_SIZE);
1031     _lcd.front_buf = rt_malloc(LCD_BUF_SIZE);
1032     if (_lcd.lcd_info.framebuffer == RT_NULL || _lcd.front_buf == RT_NULL)
1033     {
1034         LOG_E("init frame buffer failed!\n");
1035         result = -RT_ENOMEM;
1036         goto __exit;
1037     }
1038 
1039     /* memset buff to 0xFF */
1040     memset(_lcd.lcd_info.framebuffer, 0xFF, LCD_BUF_SIZE);
1041     memset(_lcd.front_buf, 0xFF, LCD_BUF_SIZE);
1042 
1043     device->type    = RT_Device_Class_Graphic;
1044 #ifdef RT_USING_DEVICE_OPS
1045     device->ops     = &lcd_ops;
1046 #else
1047     device->init    = drv_lcd_init;
1048     device->control = drv_lcd_control;
1049 #endif
1050 
1051     /* register lcd device */
1052     rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
1053 
1054     /* init spi lcd */
1055     if (rt_hw_spi_lcd_init() != RT_EOK)
1056     {
1057         result = -RT_ERROR;
1058         goto __exit;
1059     }
1060     else
1061     {
1062         turn_on_lcd_backlight();
1063     }
1064 
1065 #if defined(PKG_USING_GUIENGINE)
1066     rtgui_graphic_set_device(device);
1067 #endif
1068 
1069 __exit:
1070     if (result != RT_EOK)
1071     {
1072         rt_sem_detach(&_lcd.lcd_lock);
1073 
1074         if (_lcd.lcd_info.framebuffer)
1075         {
1076             rt_free(_lcd.lcd_info.framebuffer);
1077         }
1078 
1079         if (_lcd.back_buf)
1080         {
1081             rt_free(_lcd.back_buf);
1082         }
1083 
1084         if (_lcd.front_buf)
1085         {
1086             rt_free(_lcd.front_buf);
1087         }
1088     }
1089     return result;
1090 }
1091 INIT_COMPONENT_EXPORT(drv_lcd_ili9488_hw_init);
1092 
1093 #ifdef DRV_DEBUG
1094 #ifdef FINSH_USING_MSH
ili9488_test()1095 int ili9488_test()
1096 {
1097     struct drv_lcd_device *lcd;
1098     lcd = (struct drv_lcd_device *)rt_device_find("lcd");
1099     struct rt_device_rect_info rect_info = {0, 0, LCD_WIDTH, LCD_HEIGHT};
1100     uint32_t i = 0;
1101 
1102     lcd_clear(WHITE);
1103 
1104     lcd_show_image(0, 0, 240, 69, image_rttlogo);
1105 
1106     lcd_set_color(WHITE, BLACK);
1107 
1108     lcd_show_string(10, 69, 16, "Hello, RT-Thread!");
1109     lcd_show_string(10, 69+16, 24, "RT-Thread");
1110     lcd_show_string(10, 69+16+24, 32, "RT-Thread");
1111 
1112     lcd_draw_line(0, 69+16+24+32, LCD_H, 69+16+24+32);
1113 
1114     lcd_draw_point(160, 310);
1115     for (int i = 0; i < 150; i += 4)
1116     {
1117         lcd_draw_circle(160, 310, i);
1118     }
1119 
1120     rt_thread_mdelay(2000);
1121 
1122     while (1)
1123     {
1124         i += 10;
1125         if(i >= 120)
1126         {
1127             i = 0;
1128         }
1129 
1130         rect_info.x = i;
1131         rect_info.y = i;
1132         rect_info.width =LCD_WIDTH - 2 * i;
1133         rect_info.height =LCD_HEIGHT - 2 * i;
1134 
1135         /* red */
1136         for (int i = 0; i < LCD_BUF_SIZE / 3; i++)
1137         {
1138             lcd->lcd_info.framebuffer[3 * i] = 0xFF;
1139             lcd->lcd_info.framebuffer[3 * i + 1] = 0x00;
1140             lcd->lcd_info.framebuffer[3 * i + 2] = 0x00;
1141         }
1142         lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info);
1143         rt_thread_mdelay(1000);
1144         /* green */
1145         for (int i = 0; i < LCD_BUF_SIZE / 3; i++)
1146         {
1147             lcd->lcd_info.framebuffer[3 * i] = 0x00;
1148             lcd->lcd_info.framebuffer[3 * i + 1] = 0xFF;
1149             lcd->lcd_info.framebuffer[3 * i + 2] = 0x00;
1150         }
1151         lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info);
1152         rt_thread_mdelay(1000);
1153         /* blue */
1154         for (int i = 0; i < LCD_BUF_SIZE / 3; i++)
1155         {
1156             lcd->lcd_info.framebuffer[3 * i] = 0x00;
1157             lcd->lcd_info.framebuffer[3 * i + 1] = 0x00;
1158             lcd->lcd_info.framebuffer[3 * i + 2] = 0xFF;
1159         }
1160         lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, &rect_info);
1161         rt_thread_mdelay(1000);
1162     }
1163 }
1164 MSH_CMD_EXPORT(ili9488_test, test ili9488 driver);
1165 #endif /* FINSH_USING_MSH */
1166 #endif /* DRV_DEBUG */
1167 #endif /* BSP_USING_SPI_LCD_ILI9488 */
1168