1 /**************************************************************************//**
2 *
3 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date            Author       Notes
9 * 2020-1-16       Wayne        First version
10 *
11 ******************************************************************************/
12 
13 #include <rtconfig.h>
14 
15 #if defined(NU_PKG_USING_ILI9341)
16 
17 #include <rtdevice.h>
18 #include <lcd_ili9341.h>
19 
20 #if defined(NU_PKG_ILI9341_WITH_OFFSCREEN_FRAMEBUFFER)
21     #if !defined(NU_PKG_ILI9341_LINE_BUFFER_NUMBER)
22         #define NU_PKG_ILI9341_LINE_BUFFER_NUMBER   YSIZE_PHYS
23     #endif
24 #endif
25 
26 #define ili9341_delay_ms(ms)    rt_thread_mdelay(ms)
27 
28 static struct rt_device_graphic_info g_Ili9341Info =
29 {
30     .bits_per_pixel = 16,
31     .pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565,
32     .framebuffer = RT_NULL,
33     .width = XSIZE_PHYS,
34     .pitch = XSIZE_PHYS * 2,
35     .height = YSIZE_PHYS
36 };
37 
ili9341_pin_init(void)38 static rt_err_t ili9341_pin_init(void)
39 {
40     rt_pin_mode(BOARD_USING_ILI9341_PIN_DC, PIN_MODE_OUTPUT);
41     rt_pin_mode(BOARD_USING_ILI9341_PIN_RESET, PIN_MODE_OUTPUT);
42     rt_pin_mode(BOARD_USING_ILI9341_PIN_BACKLIGHT, PIN_MODE_OUTPUT);
43 
44     SET_RS;
45     SET_RST;
46     SET_BACKLIGHT_OFF;
47 
48     return RT_EOK;
49 }
50 
ili9341_lcd_init(rt_device_t dev)51 static rt_err_t ili9341_lcd_init(rt_device_t dev)
52 {
53     /* Hardware reset */
54     SET_RST;
55     ili9341_delay_ms(5);     // Delay 5ms
56 
57     CLR_RST;
58     ili9341_delay_ms(20);    // Delay 20ms
59 
60     SET_RST;
61     ili9341_delay_ms(40);    // Delay 40ms
62 
63     /* Initial control registers */
64     ili9341_send_cmd(0xCB);
65     ili9341_send_cmd_parameter(0x39);
66     ili9341_send_cmd_parameter(0x2C);
67     ili9341_send_cmd_parameter(0x00);
68     ili9341_send_cmd_parameter(0x34);
69     ili9341_send_cmd_parameter(0x02);
70 
71     ili9341_send_cmd(0xCF);
72     ili9341_send_cmd_parameter(0x00);
73     ili9341_send_cmd_parameter(0xC1);
74     ili9341_send_cmd_parameter(0x30);
75 
76     ili9341_send_cmd(0xE8);
77     ili9341_send_cmd_parameter(0x85);
78     ili9341_send_cmd_parameter(0x00);
79     ili9341_send_cmd_parameter(0x78);
80 
81     ili9341_send_cmd(0xEA);
82     ili9341_send_cmd_parameter(0x00);
83     ili9341_send_cmd_parameter(0x00);
84 
85     ili9341_send_cmd(0xED);
86     ili9341_send_cmd_parameter(0x64);
87     ili9341_send_cmd_parameter(0x03);
88     ili9341_send_cmd_parameter(0x12);
89     ili9341_send_cmd_parameter(0x81);
90 
91     ili9341_send_cmd(0xF7);
92     ili9341_send_cmd_parameter(0x20);
93 
94     ili9341_send_cmd(0xC0);
95     ili9341_send_cmd_parameter(0x23);
96 
97     ili9341_send_cmd(0xC1);
98     ili9341_send_cmd_parameter(0x10);
99 
100     ili9341_send_cmd(0xC5);
101     ili9341_send_cmd_parameter(0x3e);
102     ili9341_send_cmd_parameter(0x28);
103 
104     ili9341_send_cmd(0xC7);
105     ili9341_send_cmd_parameter(0x86);
106 
107     ili9341_send_cmd(0x36);
108 
109     if (g_Ili9341Info.width == 240)
110         ili9341_send_cmd_parameter(0x48); // for 240x320
111     else
112         ili9341_send_cmd_parameter(0xE8); // for 320x240
113 
114     ili9341_send_cmd(0x3A);
115     ili9341_send_cmd_parameter(0x55);
116 
117     ili9341_send_cmd(0xB1);
118     ili9341_send_cmd_parameter(0x00);
119     ili9341_send_cmd_parameter(0x18);
120 
121     ili9341_send_cmd(0xB6);
122     ili9341_send_cmd_parameter(0x08);
123     ili9341_send_cmd_parameter(0x82);
124     ili9341_send_cmd_parameter(0x27);
125 
126     ili9341_send_cmd(0xF2);
127     ili9341_send_cmd_parameter(0x00);
128 
129     ili9341_send_cmd(0x26);
130     ili9341_send_cmd_parameter(0x01);
131 
132     ili9341_send_cmd(0xE0);
133     ili9341_send_cmd_parameter(0x0F);
134     ili9341_send_cmd_parameter(0x31);
135     ili9341_send_cmd_parameter(0x2B);
136     ili9341_send_cmd_parameter(0x0C);
137     ili9341_send_cmd_parameter(0x0E);
138     ili9341_send_cmd_parameter(0x08);
139     ili9341_send_cmd_parameter(0x4E);
140     ili9341_send_cmd_parameter(0xF1);
141     ili9341_send_cmd_parameter(0x37);
142     ili9341_send_cmd_parameter(0x07);
143     ili9341_send_cmd_parameter(0x10);
144     ili9341_send_cmd_parameter(0x03);
145     ili9341_send_cmd_parameter(0x0E);
146     ili9341_send_cmd_parameter(0x09);
147     ili9341_send_cmd_parameter(0x00);
148 
149     ili9341_send_cmd(0xE1);
150     ili9341_send_cmd_parameter(0x00);
151     ili9341_send_cmd_parameter(0x0E);
152     ili9341_send_cmd_parameter(0x14);
153     ili9341_send_cmd_parameter(0x03);
154     ili9341_send_cmd_parameter(0x11);
155     ili9341_send_cmd_parameter(0x07);
156     ili9341_send_cmd_parameter(0x31);
157     ili9341_send_cmd_parameter(0xC1);
158     ili9341_send_cmd_parameter(0x48);
159     ili9341_send_cmd_parameter(0x08);
160     ili9341_send_cmd_parameter(0x0F);
161     ili9341_send_cmd_parameter(0x0C);
162     ili9341_send_cmd_parameter(0x31);
163     ili9341_send_cmd_parameter(0x36);
164     ili9341_send_cmd_parameter(0x0F);
165 
166     ili9341_send_cmd(0x11);
167 
168     ili9341_delay_ms(120);   // Delay 120ms
169 
170     ili9341_send_cmd(0x29);  //Display on
171 
172     SET_BACKLIGHT_ON;
173 
174     return RT_EOK;
175 }
176 
177 #if defined(NU_PKG_ILI9341_WITH_OFFSCREEN_FRAMEBUFFER)
ili9341_fillrect(uint16_t * pixels,struct rt_device_rect_info * pRectInfo)178 static void ili9341_fillrect(uint16_t *pixels, struct rt_device_rect_info *pRectInfo)
179 {
180     ili9341_set_column(pRectInfo->x, pRectInfo->x + pRectInfo->width - 1);
181     ili9341_set_page(pRectInfo->y, pRectInfo->y + pRectInfo->height - 1);
182     ili9341_send_cmd(0x2c);
183 
184     ili9341_send_pixels(pixels, pRectInfo->height * pRectInfo->width * 2);
185 }
186 #endif
187 
ili9341_fillscreen(rt_uint16_t color)188 static void ili9341_fillscreen(rt_uint16_t color)
189 {
190 #if defined(NU_PKG_ILI9341_WITH_OFFSCREEN_FRAMEBUFFER)
191     struct rt_device_rect_info rectinfo;
192     int filled_line_num = 0;
193 
194     while (filled_line_num < YSIZE_PHYS)
195     {
196         int pixel_count;
197         rectinfo.x = 0;
198         rectinfo.y = filled_line_num;
199         rectinfo.width = XSIZE_PHYS;
200         rectinfo.height = (NU_PKG_ILI9341_LINE_BUFFER_NUMBER < YSIZE_PHYS) ? NU_PKG_ILI9341_LINE_BUFFER_NUMBER : YSIZE_PHYS;
201 
202         pixel_count = XSIZE_PHYS * NU_PKG_ILI9341_LINE_BUFFER_NUMBER;
203         rt_uint16_t *pu16ShadowBuf = (rt_uint16_t *)g_Ili9341Info.framebuffer;
204 
205         while (pixel_count > 0)
206         {
207             *pu16ShadowBuf++ = color;
208             pixel_count--;
209         }
210         ili9341_fillrect((uint16_t *)g_Ili9341Info.framebuffer, &rectinfo);
211         filled_line_num += NU_PKG_ILI9341_LINE_BUFFER_NUMBER;
212     }
213 #else
214     ili9341_set_column(0, (XSIZE_PHYS - 1));
215     ili9341_set_page(0, (YSIZE_PHYS - 1));
216     ili9341_send_cmd(0x2c);
217 
218     for (int i = 0; i < (XSIZE_PHYS * YSIZE_PHYS); i++)
219         ili9341_send_pixel_data(color);
220 #endif
221 }
222 
ili9341_lcd_set_pixel(const char * color,int x,int y)223 static void ili9341_lcd_set_pixel(const char *color, int x, int y)
224 {
225     ili9341_set_column(x, x);
226     ili9341_set_page(y, y);
227     ili9341_send_cmd(0x2c);
228     ili9341_send_pixel_data(*(uint16_t *)color);
229 }
230 
ili9341_lcd_draw_hline(const char * pixel,int x1,int x2,int y)231 static void ili9341_lcd_draw_hline(const char *pixel, int x1, int x2, int y)
232 {
233     ili9341_set_column(x1, x2);
234     ili9341_set_page(y, y);
235     ili9341_send_cmd(0x2c);
236 
237     for (; x1 < x2; x1++)
238         ili9341_send_pixel_data(*(uint16_t *)pixel);
239 }
240 
ili9341_lcd_draw_vline(const char * pixel,int x,int y1,int y2)241 static void ili9341_lcd_draw_vline(const char *pixel, int x, int y1, int y2)
242 {
243     ili9341_set_column(x, x);
244     ili9341_set_page(y1, y2);
245     ili9341_send_cmd(0x2c);
246 
247     for (; y1 < y2; y1++)
248         ili9341_send_pixel_data(*(uint16_t *)pixel);
249 }
250 
ili9341_lcd_blit_line(const char * pixels,int x,int y,rt_size_t size)251 static void ili9341_lcd_blit_line(const char *pixels, int x, int y, rt_size_t size)
252 {
253     rt_uint16_t *ptr = (rt_uint16_t *)pixels;
254 
255     ili9341_set_column(x, x + size);
256     ili9341_set_page(y, y);
257     ili9341_send_cmd(0x2c);
258 
259     while (size--)
260         ili9341_send_pixel_data(*ptr++);
261 }
262 
ili9341_lcd_open(rt_device_t dev,rt_uint16_t oflag)263 static rt_err_t ili9341_lcd_open(rt_device_t dev, rt_uint16_t oflag)
264 {
265     return RT_EOK;
266 }
267 
ili9341_lcd_close(rt_device_t dev)268 static rt_err_t ili9341_lcd_close(rt_device_t dev)
269 {
270     return RT_EOK;
271 }
272 
ili9341_lcd_control(rt_device_t dev,int cmd,void * args)273 static rt_err_t ili9341_lcd_control(rt_device_t dev, int cmd, void *args)
274 {
275     switch (cmd)
276     {
277     case RTGRAPHIC_CTRL_GET_INFO:
278     {
279         struct rt_device_graphic_info *info;
280 
281         info = (struct rt_device_graphic_info *) args;
282         RT_ASSERT(info != RT_NULL);
283         rt_memcpy(args, (void *)&g_Ili9341Info, sizeof(struct rt_device_graphic_info));
284     }
285     break;
286 
287     case RTGRAPHIC_CTRL_RECT_UPDATE:
288     {
289 #if defined(NU_PKG_ILI9341_WITH_OFFSCREEN_FRAMEBUFFER)
290         struct rt_device_rect_info *psRectInfo = (struct rt_device_rect_info *)args;
291         rt_uint16_t *pixels  = (rt_uint16_t *)g_Ili9341Info.framebuffer;
292         RT_ASSERT(args);
293 
294         ili9341_fillrect(pixels, psRectInfo);
295 #else
296         /* nothong to be done */
297 #endif
298     }
299     break;
300     default:
301         return -RT_ERROR;
302     }
303 
304     return RT_EOK;
305 }
306 
307 static struct rt_device lcd_device;
308 static struct rt_device_graphic_ops ili9341_ops =
309 {
310     ili9341_lcd_set_pixel,
311     ili9341_lcd_get_pixel,
312     ili9341_lcd_draw_hline,
313     ili9341_lcd_draw_vline,
314     ili9341_lcd_blit_line
315 };
316 
rt_hw_lcd_ili9341_init(void)317 int rt_hw_lcd_ili9341_init(void)
318 {
319     ili9341_pin_init();
320 
321     /* register lcd device */
322     lcd_device.type = RT_Device_Class_Graphic;
323     lcd_device.init = ili9341_lcd_init;
324     lcd_device.open = ili9341_lcd_open;
325     lcd_device.close = ili9341_lcd_close;
326     lcd_device.control = ili9341_lcd_control;
327     lcd_device.read = RT_NULL;
328     lcd_device.write = RT_NULL;
329 
330     lcd_device.user_data = &ili9341_ops;
331 
332 #if defined(NU_PKG_ILI9341_WITH_OFFSCREEN_FRAMEBUFFER)
333     g_Ili9341Info.framebuffer = rt_malloc_align((g_Ili9341Info.pitch * NU_PKG_ILI9341_LINE_BUFFER_NUMBER) + 32, 32);
334     RT_ASSERT(g_Ili9341Info.framebuffer != RT_NULL);
335     g_Ili9341Info.smem_len = g_Ili9341Info.pitch * NU_PKG_ILI9341_LINE_BUFFER_NUMBER;
336 #endif
337 
338     /* register graphic device driver */
339     rt_device_register(&lcd_device, "lcd", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
340 
341     return 0;
342 }
343 
344 #ifdef RT_USING_FINSH
345 #define LINE_LEN 32
lcd_test(int argc,char * argv[])346 static void lcd_test(int argc, char *argv[])
347 {
348     uint16_t pixels[LINE_LEN];
349     uint16_t color;
350     int x, y, i;
351     x = y = 100;
352 
353     ili9341_lcd_init(NULL);
354 
355     color = 0x0; //Black, RGB
356     rt_kprintf("Brush 0x%X on screen.\n", color);
357     ili9341_fillscreen(color);
358     ili9341_lcd_get_pixel((char *)&color, x, y);
359     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
360 
361     color = 0xffff; //White, RGB
362     rt_kprintf("Brush 0x%X on screen.\n", color);
363     ili9341_fillscreen(color);
364     ili9341_lcd_get_pixel((char *)&color, x, y);
365     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
366 
367     color = 0x1f; //Blue, RGB
368     rt_kprintf("Brush 0x%X on screen.\n", color);
369     ili9341_fillscreen(color);
370     ili9341_lcd_get_pixel((char *)&color, x, y);
371     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
372 
373     color = 0x07e0; //Green, RGB
374     rt_kprintf("Brush 0x%X on screen.\n", color);
375     ili9341_fillscreen(color);
376     ili9341_lcd_get_pixel((char *)&color, x, y);
377     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
378 
379     color = 0xf800; //Red, RGB
380     rt_kprintf("Brush 0x%X on screen.\n", color);
381     ili9341_fillscreen(color);
382     ili9341_lcd_get_pixel((char *)&color, x, y);
383     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
384 
385     color = 0xffff; //White, RGB
386     rt_kprintf("lcd draw hline, pixel: 0x%X, x1: %d, x2: %d, y: %d\n", color, x, x + 20, y);
387     ili9341_lcd_draw_hline((const char *)&color, x, x + 20, y);
388 
389     color = 0xffff; //White, RGB
390     rt_kprintf("lcd draw vline, pixel: 0x%X, x: %d, y: %d\n", color, y, y + 20);
391     ili9341_lcd_draw_vline((const char *)&color, x, y, y + 20);
392 
393     for (i = 0; i < LINE_LEN; i++)
394         pixels[i] = 20 + i * 5;
395 
396     x = y = 50;
397     rt_kprintf("lcd blit line, start: x: %d, y: %d\n", x, y);
398     ili9341_lcd_blit_line((const char *)&pixels[0], x, y, LINE_LEN);
399 
400     x = y = 200;
401     color = 0x07E0; //Green, RGB
402     rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
403     ili9341_lcd_set_pixel((const char *)&color, x, y);
404     color = 0x0;
405     ili9341_lcd_get_pixel((char *)&color, x, y);
406     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
407 
408     x = y = 200;
409     color = 0x1f; //Blue, RGB
410     rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
411     ili9341_lcd_set_pixel((const char *)&color, x, y);
412     color = 0x0;
413     ili9341_lcd_get_pixel((char *)&color, x, y);
414     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
415 
416     x = y = 200;
417     color = 0xf800; //Red, RGB
418     rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
419     ili9341_lcd_set_pixel((const char *)&color, x, y);
420     color = 0x0;
421     ili9341_lcd_get_pixel((char *)&color, x, y);
422     rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
423 }
424 MSH_CMD_EXPORT(lcd_test, test lcd display);
425 #endif
426 
427 #endif /* if defined(NU_PKG_USING_ILI9341) */
428