lcd_fsa506.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. * 2022-2-23 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(NU_PKG_USING_FSA506)
  14. #include <rtdevice.h>
  15. #include <lcd_fsa506.h>
  16. #if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
  17. #if !defined(NU_PKG_FSA506_LINE_BUFFER_NUMBER)
  18. #define NU_PKG_FSA506_LINE_BUFFER_NUMBER YSIZE_PHYS
  19. #endif
  20. #endif
  21. #define fsa506_delay_ms(ms) rt_thread_mdelay(ms)
  22. static void fsa506_fillscreen(rt_uint16_t color);
  23. static struct rt_device_graphic_info g_FSA506Info =
  24. {
  25. .bits_per_pixel = 16,
  26. .pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565,
  27. .framebuffer = RT_NULL,
  28. .width = XSIZE_PHYS,
  29. .pitch = XSIZE_PHYS * 2,
  30. .height = YSIZE_PHYS
  31. };
  32. static rt_err_t fsa506_pin_init(void)
  33. {
  34. SET_BACKLIGHT_OFF;
  35. rt_pin_mode(BOARD_USING_FSA506_PIN_BACKLIGHT, PIN_MODE_OUTPUT);
  36. CLR_RS;
  37. CLR_RST;
  38. rt_pin_mode(BOARD_USING_FSA506_PIN_DC, PIN_MODE_OUTPUT);
  39. rt_pin_mode(BOARD_USING_FSA506_PIN_RESET, PIN_MODE_OUTPUT);
  40. return RT_EOK;
  41. }
  42. static rt_err_t fsa506_lcd_init(rt_device_t dev)
  43. {
  44. SET_BACKLIGHT_OFF;
  45. /* Hardware reset */
  46. CLR_RST;
  47. fsa506_delay_ms(100); // Delay 100ms
  48. SET_RST;
  49. fsa506_delay_ms(500); // Delay 500ms
  50. fsa506_write_reg(0x40, 0x12); // [5]:PLL control 20~100MHz [2:1]:Output Driving 8mA, [0]:Output slew Fast
  51. fsa506_write_reg(0x41, 0x05); // PLL Programmable pre-divider: 5
  52. fsa506_write_reg(0x42, 0x06); // PLL Programmable loop divider: 6
  53. /* Set the panel X size */
  54. fsa506_write_reg(0x08, (XSIZE_PHYS >> 8)); //Set the panel X size H[1.0]
  55. fsa506_write_reg(0x09, (XSIZE_PHYS)); //Set the panel X size L[7:0]
  56. /* Memory write start address */
  57. fsa506_write_reg(0x0a, 0x00); //[17:16] bits of memory write start address
  58. fsa506_write_reg(0x0b, 0x00); //[15:8] bits of memory write start address
  59. fsa506_write_reg(0x0c, 0x00); //[7:0] bits of memory write start address
  60. /* Clock & format */
  61. fsa506_write_reg(0x10, 0x0D); //[0-1] : 20MHz, [2]: Parallel panel, [3]: Normal operation
  62. fsa506_write_reg(0x11, 0x05); //[3-5]: RGB, [0-2]BGR
  63. /* For TFT output timing adjust */
  64. fsa506_write_reg(0x12, 0x00); //Hsync start position H-Byte
  65. fsa506_write_reg(0x13, 0x00); //Hsync start position L-Byte
  66. fsa506_write_reg(0x14, (41 >> 8)); //Hsync pulse width H-Byte
  67. fsa506_write_reg(0x15, (41)); //Hsync pulse width L-Byte
  68. fsa506_write_reg(0x16, (43 >> 8)); //DE pulse start position H-Byte
  69. fsa506_write_reg(0x17, (43)); //DE pulse start position L-Byte
  70. fsa506_write_reg(0x18, (XSIZE_PHYS >> 8)); //DE pulse width H-Byte
  71. fsa506_write_reg(0x19, (XSIZE_PHYS)); //DE pulse width L-Byte
  72. fsa506_write_reg(0x1a, (525 >> 8)); //Hsync total clocks H-Byte
  73. fsa506_write_reg(0x1b, (525)); //Hsync total clocks H-Byte
  74. fsa506_write_reg(0x1c, 0x00); //Vsync start position H-Byte
  75. fsa506_write_reg(0x1d, 0x00); //Vsync start position L-Byte
  76. fsa506_write_reg(0x1e, (10 >> 8)); //Vsync pulse width H-Byte
  77. fsa506_write_reg(0x1f, (10)); //Vsync pulse width L-Byte
  78. fsa506_write_reg(0x20, (12 >> 8)); //Vertical DE pulse start position H-Byte
  79. fsa506_write_reg(0x21, (12)); //Vertical DE pulse start position L-Byte
  80. fsa506_write_reg(0x22, (YSIZE_PHYS >> 8)); //Vertical Active width H-Byte
  81. fsa506_write_reg(0x23, (YSIZE_PHYS)); //Vertical Active width H-Byte
  82. fsa506_write_reg(0x24, (286 >> 8)); //Vertical total width H-Byte
  83. fsa506_write_reg(0x25, (286)); //Vertical total width L-Byte
  84. fsa506_write_reg(0x26, 0x00); //Memory read start address
  85. fsa506_write_reg(0x27, 0x00); //Memory read start address
  86. fsa506_write_reg(0x28, 0x00); //Memory read start address
  87. fsa506_write_reg(0x29, 0x01); //[0] Load output timing related setting (H sync., V sync. and DE) to take effect
  88. //[7:4] Reserved
  89. //[3] Output pin X_DCON level control
  90. //[2] Output clock inversion 0: Normal 1: Inverse
  91. //[1:0] Image rotate
  92. // 00: 0? 01: 90? 10: 270?11: 180?
  93. fsa506_write_reg(0x2d, (1 << 2) | 0x08);
  94. /* Set the Horizontal offset */
  95. fsa506_write_reg(0x30, 0x00); //_H byte H-Offset[3:0]
  96. fsa506_write_reg(0x31, 0x00); //_L byte H-Offset[7:0]
  97. fsa506_write_reg(0x32, 0x00); //_H byte V-Offset[3:0]
  98. fsa506_write_reg(0x33, 0x00); //_L byte V-Offset[7:0]
  99. fsa506_write_reg(0x34, (XSIZE_PHYS >> 8)); //H byte H-def[3:0]
  100. fsa506_write_reg(0x35, (XSIZE_PHYS)); //_L byte H-def[7:0]
  101. fsa506_write_reg(0x36, ((2 * YSIZE_PHYS) >> 8)); //[3:0] MSB of image vertical physical resolution in memory
  102. fsa506_write_reg(0x37, (2 * YSIZE_PHYS)); //[7:0] LSB of image vertical physical resolution in memory
  103. fsa506_fillscreen(0);
  104. SET_BACKLIGHT_ON;
  105. return RT_EOK;
  106. }
  107. #if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
  108. static void fsa506_fillrect(uint16_t *pixels, struct rt_device_rect_info *pRectInfo)
  109. {
  110. fsa506_set_column(pRectInfo->x, pRectInfo->x + pRectInfo->width - 1);
  111. fsa506_set_page(pRectInfo->y, pRectInfo->y + pRectInfo->height - 1);
  112. fsa506_send_cmd(0xC1);
  113. fsa506_send_pixels(pixels, pRectInfo->height * pRectInfo->width * 2);
  114. fsa506_send_cmd_done();
  115. }
  116. #endif
  117. static void fsa506_fillscreen(rt_uint16_t color)
  118. {
  119. #if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
  120. struct rt_device_rect_info rectinfo;
  121. int filled_line_num = 0;
  122. while (filled_line_num < YSIZE_PHYS)
  123. {
  124. int pixel_count;
  125. rectinfo.x = 0;
  126. rectinfo.y = filled_line_num;
  127. rectinfo.width = XSIZE_PHYS;
  128. rectinfo.height = (NU_PKG_FSA506_LINE_BUFFER_NUMBER < YSIZE_PHYS) ? NU_PKG_FSA506_LINE_BUFFER_NUMBER : YSIZE_PHYS;
  129. pixel_count = XSIZE_PHYS * NU_PKG_FSA506_LINE_BUFFER_NUMBER;
  130. rt_uint16_t *pu16ShadowBuf = (rt_uint16_t *)g_FSA506Info.framebuffer;
  131. while (pixel_count > 0)
  132. {
  133. *pu16ShadowBuf++ = color;
  134. pixel_count--;
  135. }
  136. fsa506_fillrect((uint16_t *)g_FSA506Info.framebuffer, &rectinfo);
  137. filled_line_num += NU_PKG_FSA506_LINE_BUFFER_NUMBER;
  138. }
  139. #else
  140. fsa506_set_column(0, (XSIZE_PHYS - 1));
  141. fsa506_set_page(0, (YSIZE_PHYS - 1));
  142. fsa506_send_cmd(0xC1);
  143. for (int i = 0; i < (XSIZE_PHYS * YSIZE_PHYS); i++)
  144. fsa506_send_pixel_data(color);
  145. fsa506_send_cmd_done();
  146. #endif
  147. }
  148. static void fsa506_lcd_set_pixel(const char *color, int x, int y)
  149. {
  150. fsa506_set_column(x, x);
  151. fsa506_set_page(y, y);
  152. fsa506_send_cmd(0xC1);
  153. fsa506_send_pixel_data(*(uint16_t *)color);
  154. fsa506_send_cmd_done();
  155. }
  156. static void fsa506_lcd_draw_hline(const char *pixel, int x1, int x2, int y)
  157. {
  158. fsa506_set_column(x1, x2);
  159. fsa506_set_page(y, y);
  160. fsa506_send_cmd(0xC1);
  161. for (; x1 < x2; x1++)
  162. fsa506_send_pixel_data(*(uint16_t *)pixel);
  163. fsa506_send_cmd_done();
  164. }
  165. static void fsa506_lcd_draw_vline(const char *pixel, int x, int y1, int y2)
  166. {
  167. fsa506_set_column(x, x);
  168. fsa506_set_page(y1, y2);
  169. fsa506_send_cmd(0xC1);
  170. for (; y1 < y2; y1++)
  171. fsa506_send_pixel_data(*(uint16_t *)pixel);
  172. fsa506_send_cmd_done();
  173. }
  174. static void fsa506_lcd_blit_line(const char *pixels, int x, int y, rt_size_t size)
  175. {
  176. rt_uint16_t *ptr = (rt_uint16_t *)pixels;
  177. fsa506_set_column(x, x + size);
  178. fsa506_set_page(y, y);
  179. fsa506_send_cmd(0xC1);
  180. while (size--)
  181. fsa506_send_pixel_data(*ptr++);
  182. fsa506_send_cmd_done();
  183. }
  184. static rt_err_t fsa506_lcd_open(rt_device_t dev, rt_uint16_t oflag)
  185. {
  186. return RT_EOK;
  187. }
  188. static rt_err_t fsa506_lcd_close(rt_device_t dev)
  189. {
  190. return RT_EOK;
  191. }
  192. static rt_err_t fsa506_lcd_control(rt_device_t dev, int cmd, void *args)
  193. {
  194. switch (cmd)
  195. {
  196. case RTGRAPHIC_CTRL_GET_INFO:
  197. {
  198. struct rt_device_graphic_info *info;
  199. info = (struct rt_device_graphic_info *) args;
  200. RT_ASSERT(info != RT_NULL);
  201. rt_memcpy(args, (void *)&g_FSA506Info, sizeof(struct rt_device_graphic_info));
  202. }
  203. break;
  204. case RTGRAPHIC_CTRL_RECT_UPDATE:
  205. {
  206. #if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
  207. struct rt_device_rect_info *psRectInfo = (struct rt_device_rect_info *)args;
  208. rt_uint16_t *pixels = (rt_uint16_t *)g_FSA506Info.framebuffer;
  209. RT_ASSERT(args);
  210. fsa506_fillrect(pixels, psRectInfo);
  211. #else
  212. /* nothong to be done */
  213. #endif
  214. }
  215. break;
  216. default:
  217. return -RT_ERROR;
  218. }
  219. return RT_EOK;
  220. }
  221. static struct rt_device lcd_device;
  222. static struct rt_device_graphic_ops fsa506_ops =
  223. {
  224. fsa506_lcd_set_pixel,
  225. fsa506_lcd_get_pixel,
  226. fsa506_lcd_draw_hline,
  227. fsa506_lcd_draw_vline,
  228. fsa506_lcd_blit_line
  229. };
  230. int rt_hw_lcd_fsa506_init(void)
  231. {
  232. fsa506_pin_init();
  233. /* register lcd device */
  234. lcd_device.type = RT_Device_Class_Graphic;
  235. lcd_device.init = fsa506_lcd_init;
  236. lcd_device.open = fsa506_lcd_open;
  237. lcd_device.close = fsa506_lcd_close;
  238. lcd_device.control = fsa506_lcd_control;
  239. lcd_device.read = RT_NULL;
  240. lcd_device.write = RT_NULL;
  241. lcd_device.user_data = &fsa506_ops;
  242. #if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
  243. g_FSA506Info.framebuffer = rt_malloc_align((g_FSA506Info.pitch * NU_PKG_FSA506_LINE_BUFFER_NUMBER) + 32, 32);
  244. RT_ASSERT(g_FSA506Info.framebuffer != RT_NULL);
  245. g_FSA506Info.smem_len = g_FSA506Info.pitch * NU_PKG_FSA506_LINE_BUFFER_NUMBER;
  246. #endif
  247. /* register graphic device driver */
  248. rt_device_register(&lcd_device, "lcd", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
  249. return 0;
  250. }
  251. #ifdef RT_USING_FINSH
  252. #define LINE_LEN 32
  253. static void lcd_test(int argc, char *argv[])
  254. {
  255. uint16_t pixels[LINE_LEN];
  256. uint16_t color;
  257. int x, y, i;
  258. x = y = 100;
  259. fsa506_lcd_init(NULL);
  260. color = 0x0; //Black, RGB
  261. rt_kprintf("Brush 0x%X on screen.\n", color);
  262. fsa506_fillscreen(color);
  263. fsa506_lcd_get_pixel((char *)&color, x, y);
  264. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  265. color = 0xffff; //White, RGB
  266. rt_kprintf("Brush 0x%X on screen.\n", color);
  267. fsa506_fillscreen(color);
  268. fsa506_lcd_get_pixel((char *)&color, x, y);
  269. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  270. color = 0x1f; //Blue, RGB
  271. rt_kprintf("Brush 0x%X on screen.\n", color);
  272. fsa506_fillscreen(color);
  273. fsa506_lcd_get_pixel((char *)&color, x, y);
  274. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  275. color = 0x07e0; //Green, RGB
  276. rt_kprintf("Brush 0x%X on screen.\n", color);
  277. fsa506_fillscreen(color);
  278. fsa506_lcd_get_pixel((char *)&color, x, y);
  279. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  280. color = 0xf800; //Red, RGB
  281. rt_kprintf("Brush 0x%X on screen.\n", color);
  282. fsa506_fillscreen(color);
  283. fsa506_lcd_get_pixel((char *)&color, x, y);
  284. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  285. color = 0xffff; //White, RGB
  286. rt_kprintf("lcd draw hline, pixel: 0x%X, x1: %d, x2: %d, y: %d\n", color, x, x + 20, y);
  287. fsa506_lcd_draw_hline((const char *)&color, x, x + 20, y);
  288. color = 0xffff; //White, RGB
  289. rt_kprintf("lcd draw vline, pixel: 0x%X, x: %d, y: %d\n", color, y, y + 20);
  290. fsa506_lcd_draw_vline((const char *)&color, x, y, y + 20);
  291. for (i = 0; i < LINE_LEN; i++)
  292. pixels[i] = 20 + i * 5;
  293. x = y = 50;
  294. rt_kprintf("lcd blit line, start: x: %d, y: %d\n", x, y);
  295. fsa506_lcd_blit_line((const char *)&pixels[0], x, y, LINE_LEN);
  296. x = y = 200;
  297. color = 0x07E0; //Green, RGB
  298. rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  299. fsa506_lcd_set_pixel((const char *)&color, x, y);
  300. color = 0x0;
  301. fsa506_lcd_get_pixel((char *)&color, x, y);
  302. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  303. x = y = 200;
  304. color = 0x1f; //Blue, RGB
  305. rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  306. fsa506_lcd_set_pixel((const char *)&color, x, y);
  307. color = 0x0;
  308. fsa506_lcd_get_pixel((char *)&color, x, y);
  309. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  310. x = y = 200;
  311. color = 0xf800; //Red, RGB
  312. rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  313. fsa506_lcd_set_pixel((const char *)&color, x, y);
  314. color = 0x0;
  315. fsa506_lcd_get_pixel((char *)&color, x, y);
  316. rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
  317. }
  318. MSH_CMD_EXPORT(lcd_test, test lcd display);
  319. #endif
  320. #endif /* if defined(NU_PKG_USING_FSA506) */