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