lcd_fsa506.c 13 KB

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