lcd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2011-03-05 lgnq ZYMG12864C3 LCD driver
  9. */
  10. #include <rtthread.h>
  11. #include "lcd.h"
  12. #include "font.h"
  13. static struct rt_device_graphic_info _lcd_info;
  14. static rt_uint8_t gui_disp_buf[GUI_LCM_YMAX/8][GUI_LCM_XMAX];
  15. const unsigned char BIT_MASK[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
  16. /* simple font: ' ', '0'~'9','a'~'z','A'~'Z' */
  17. extern const unsigned char FONTTYPE8_8[][8];
  18. rt_uint32_t x;
  19. rt_uint32_t y;
  20. void power_delay(void)
  21. {
  22. rt_uint32_t i = 0x4ffff;
  23. while(i--)
  24. ;
  25. }
  26. void delay(void)
  27. {
  28. rt_uint8_t i = 0x8;
  29. while(i--)
  30. ;
  31. }
  32. void reset_delay(void)
  33. {
  34. rt_uint8_t i = 0xff;
  35. while(i--)
  36. ;
  37. }
  38. void lcd_write_cmd(unsigned char command)
  39. {
  40. rt_uint8_t i;
  41. LCD_PS_LOW();
  42. LCD_CS_LOW();
  43. LCD_CD_LOW();
  44. for (i=0; i<8; i++)
  45. {
  46. if (command & (0x80 >> i))
  47. LCD_DATA_HIGH();
  48. else
  49. LCD_DATA_LOW();
  50. LCD_CLK_LOW();
  51. delay();
  52. LCD_CLK_HIGH();
  53. delay();
  54. }
  55. LCD_CS_HIGH();
  56. }
  57. void lcd_write_data(unsigned char data)
  58. {
  59. rt_uint8_t i;
  60. LCD_PS_LOW();
  61. LCD_CS_LOW();
  62. LCD_CD_HIGH();
  63. for (i=0; i<8; i++)
  64. {
  65. if (data & (0x80 >> i))
  66. LCD_DATA_HIGH();
  67. else
  68. LCD_DATA_LOW();
  69. LCD_CLK_LOW();
  70. delay();
  71. LCD_CLK_HIGH();
  72. delay();
  73. }
  74. LCD_CS_HIGH();
  75. }
  76. #ifdef RT_USING_RTGUI
  77. #include <rtgui/driver.h>
  78. #include <rtgui/color.h>
  79. static void rt_hw_lcd_update(struct rt_device_rect_info *rect_info)
  80. {
  81. rt_uint8_t i,j = GUI_LCM_XMAX;
  82. rt_uint8_t* p = (rt_uint8_t*)gui_disp_buf;
  83. for (i=0; i<GUI_LCM_PAGE; i++)
  84. {
  85. lcd_write_cmd(SET_PAGE_ADDR_0|i);
  86. lcd_write_cmd(SET_COLH_ADDR_0);
  87. lcd_write_cmd(SET_COLL_ADDR_0);
  88. j = GUI_LCM_XMAX;
  89. while (j--)
  90. {
  91. lcd_write_data(*p++);
  92. delay();
  93. }
  94. }
  95. }
  96. static rt_uint8_t * rt_hw_lcd_get_framebuffer(void)
  97. {
  98. return(rt_uint8_t *)gui_disp_buf;
  99. }
  100. static void rt_hw_lcd_set_pixel(rtgui_color_t *c, int x, int y)
  101. {
  102. rt_uint8_t page;
  103. page = y/8;
  104. if (*c == rtgui_color_to_565(black))
  105. gui_disp_buf[page][x] |= 1<<(y%8);
  106. else
  107. if (*c == rtgui_color_to_565(white))
  108. gui_disp_buf[page][x] &= ~(1<<(y%8));
  109. }
  110. static void rt_hw_lcd_get_pixel(rtgui_color_t *c, int x, int y)
  111. {
  112. rt_uint8_t page;
  113. page = y/8;
  114. if (gui_disp_buf[page][x] & (1<<(y%8)))
  115. *c = black;
  116. else
  117. *c = white;
  118. }
  119. static void rt_hw_lcd_draw_hline(rtgui_color_t *c, int x1, int x2, int y)
  120. {
  121. rt_uint8_t page;
  122. rt_uint8_t i;
  123. page = y/8;
  124. for (i=x1; i<x2; i++)
  125. {
  126. if (*c == rtgui_color_to_565(black))
  127. gui_disp_buf[page][i] |= 1<<(y%8);
  128. else
  129. if (*c == rtgui_color_to_565(white))
  130. gui_disp_buf[page][i] &= ~(1<<(y%8));
  131. }
  132. }
  133. static void rt_hw_lcd_draw_vline(rtgui_color_t *c, int x, int y1, int y2)
  134. {
  135. rt_uint8_t y;
  136. for (y = y1; y < y2; y ++)
  137. {
  138. rt_hw_lcd_set_pixel(c, x, y);
  139. }
  140. }
  141. static void rt_hw_lcd_draw_raw_hline(rt_uint8_t *pixels, int x1, int x2, int y)
  142. {
  143. rt_uint8_t coll;
  144. rt_uint8_t colh;
  145. rt_uint8_t page;
  146. rt_uint8_t i;
  147. page = y/8;
  148. for (i=x1; i<x2; i++)
  149. {
  150. gui_disp_buf[page][i] |= 1<<(y%8);
  151. coll = i & 0x0f;
  152. colh = i >> 4;
  153. lcd_write_cmd(SET_PAGE_ADDR_0 | page);
  154. lcd_write_cmd(SET_COLH_ADDR_0 | colh);
  155. lcd_write_cmd(SET_COLL_ADDR_0 | coll);
  156. lcd_write_data(gui_disp_buf[page][i]);
  157. }
  158. }
  159. const struct rtgui_graphic_driver_ops _lcd_ops =
  160. {
  161. rt_hw_lcd_set_pixel,
  162. rt_hw_lcd_get_pixel,
  163. rt_hw_lcd_draw_hline,
  164. rt_hw_lcd_draw_vline,
  165. rt_hw_lcd_draw_raw_hline
  166. };
  167. #endif
  168. void lcd_io_init()
  169. {
  170. /* Release the analog input function*/
  171. FM3_GPIO->ADE =0x03;
  172. /*Select CPIO function*/
  173. LCD_CS_PFR &= ~LCD_CS;
  174. /*Make pin output*/
  175. LCD_CS_DDR |= LCD_CS;
  176. /*Select CPIO function*/
  177. LCD_CD_PFR &= ~LCD_CD;
  178. /*Make pin output*/
  179. LCD_CD_DDR |= LCD_CD;
  180. /*Select CPIO function*/
  181. LCD_PS_PFR &= ~LCD_PS;
  182. /*Make pin output*/
  183. LCD_PS_DDR |= LCD_PS;
  184. /*Select CPIO function*/
  185. LCD_CLK_PFR &= ~LCD_CLK;
  186. /*Make pin output*/
  187. LCD_CLK_DDR |= LCD_CLK;
  188. /*Select CPIO function*/
  189. LCD_DATA_PFR &= ~LCD_DATA;
  190. /*Make pin output*/
  191. LCD_DATA_DDR |= LCD_DATA;
  192. }
  193. /* RT-Thread Device Interface */
  194. static rt_err_t rt_lcd_init (rt_device_t dev)
  195. {
  196. lcd_io_init();
  197. power_delay();
  198. lcd_write_cmd(DISPLAY_OFF);
  199. reset_delay();
  200. // Resetting circuit
  201. lcd_write_cmd(RESET_LCD);
  202. reset_delay();
  203. // LCD bias setting
  204. lcd_write_cmd(SET_LCD_BIAS_9);
  205. reset_delay();
  206. // ADC selection: display from left to right
  207. lcd_write_cmd(SET_ADC_NORMAL);
  208. reset_delay();
  209. // Common output state selection: display from up to down
  210. lcd_write_cmd(COM_SCAN_DIR_REVERSE);
  211. reset_delay();
  212. lcd_write_cmd(POWER_BOOSTER_ON);
  213. power_delay(); // 50ms requried
  214. lcd_write_cmd(POWER_REGULATOR_ON);
  215. power_delay(); // 50ms
  216. lcd_write_cmd(POWER_FOLLOWER_ON);
  217. power_delay(); // 50ms
  218. // Setting the built-in resistance radio for regulation of the V0 voltage
  219. // Electronic volume control
  220. // Power control setting
  221. lcd_write_cmd(SET_ELECVOL_REG|0x05);
  222. delay();
  223. lcd_write_cmd(SET_ELECVOL_MODE);
  224. delay();
  225. lcd_write_cmd(SET_ELECVOL_REG);
  226. delay();
  227. // LCD_Clear();
  228. delay();
  229. lcd_write_cmd(SET_PAGE_ADDR_0);
  230. delay();
  231. lcd_write_cmd(SET_COLH_ADDR_0);
  232. delay();
  233. lcd_write_cmd(SET_COLL_ADDR_0);
  234. delay();
  235. lcd_write_cmd(DISPLAY_ON);
  236. delay();
  237. lcd_write_cmd(DISPLAY_ALL_ON);
  238. delay();
  239. lcd_write_cmd(DISPLAY_OFF);
  240. delay();
  241. lcd_write_cmd(DISPLAY_ON);
  242. delay();
  243. lcd_write_cmd(DISPLAY_ALL_NORMAL);
  244. delay();
  245. return RT_EOK;
  246. }
  247. /*******************************************************************************
  248. * Function Name : LCD_FillAll
  249. * Description : Fill the whole LCD.
  250. * Input : None
  251. * Output : None
  252. * Return : None
  253. *******************************************************************************/
  254. void LCD_FillAll(unsigned char* buffer)
  255. {
  256. unsigned char i,j = GUI_LCM_XMAX;
  257. unsigned char* p = buffer;
  258. for (i=0; i<GUI_LCM_PAGE; i++)
  259. {
  260. lcd_write_cmd(SET_PAGE_ADDR_0|i);
  261. lcd_write_cmd(SET_COLH_ADDR_0);
  262. lcd_write_cmd(SET_COLL_ADDR_0);
  263. j = GUI_LCM_XMAX;
  264. while (j--)
  265. {
  266. lcd_write_data(*p++);
  267. delay();
  268. }
  269. }
  270. }
  271. /*******************************************************************************
  272. * Function Name : LCD_ClearSCR
  273. * Description : clean screen
  274. * Input : None
  275. * Output : None
  276. * Return : None
  277. *******************************************************************************/
  278. void LCD_ClearSCR(void)
  279. {
  280. unsigned char i, j;
  281. for(i=0; i<GUI_LCM_PAGE; i++)
  282. {
  283. for(j = 0; j < GUI_LCM_XMAX; j++)
  284. gui_disp_buf[i][j] = 0;
  285. }
  286. LCD_FillAll((unsigned char*)gui_disp_buf);
  287. }
  288. /****************************************************************************
  289. * Function Name : LCD_UpdatePoint
  290. * Description : refresh the point in screen
  291. * Input : x X-coordinate
  292. y Y-coordinate
  293. * Output : None
  294. * Return : None
  295. ****************************************************************************/
  296. void LCD_UpdatePoint(unsigned int x, unsigned int y)
  297. {
  298. unsigned char coll, colh, page;
  299. page = y / 8;
  300. coll = x & 0x0f;
  301. colh = x >> 4;
  302. lcd_write_cmd(SET_PAGE_ADDR_0 | page); // page no.
  303. lcd_write_cmd(SET_COLH_ADDR_0 | colh); // fixed col first addr
  304. lcd_write_cmd(SET_COLL_ADDR_0 | coll);
  305. lcd_write_data(gui_disp_buf[page][x]);
  306. }
  307. /****************************************************************************
  308. * Function Name : LCD_PutChar
  309. * Description : output a char to screen
  310. (the char only can be ' ','0'~'9','A'~'Z','a'~'z')
  311. * Input : x X-coordinate
  312. y Y-coordinate
  313. ch character
  314. * Output : None
  315. * Return : 1 Success
  316. 0 Fail
  317. ****************************************************************************/
  318. unsigned char LCD_PutChar(unsigned long x, unsigned long y, unsigned char ch)
  319. {
  320. unsigned char data;
  321. unsigned char i, j;
  322. if( x >=(GUI_LCM_XMAX-8) ) return(0);
  323. if( y >=(GUI_LCM_YMAX-8) ) return(0);
  324. if(ch == 0x20)
  325. ch -= 0x20;
  326. else if((ch >= 0x30)&&(ch <= 0x39))
  327. ch -= 0x2f;
  328. else if((ch >= 0x41)&&(ch <= 0x5a))
  329. ch -= 0x36;
  330. else if((ch >= 0x61)&&(ch <= 0x7a))
  331. ch -= 0x3C;
  332. else
  333. return(0);
  334. for(i = 0; i < 8; i++)
  335. {
  336. data = FONTTYPE8_8[ch][i];
  337. for(j = 0; j < 8; j++)
  338. {
  339. if( (data&BIT_MASK[j]) == 0)
  340. gui_disp_buf[y / 8][x] &= (~(0x01 << ( y % 8)));
  341. else
  342. gui_disp_buf[y / 8][x] |= (0x01 <<( y % 8));
  343. LCD_UpdatePoint(x, y);
  344. x ++;
  345. }
  346. x -= 8;
  347. y++;
  348. }
  349. return(1);
  350. }
  351. /****************************************************************************
  352. * Function Name : LCD_PutString
  353. * Description : output string to screen
  354. * Input : x X-coordinate
  355. y Y-coordinate
  356. str pointer to string
  357. * Output : None
  358. * Return : None
  359. ****************************************************************************/
  360. void LCD_PutString(unsigned long x, unsigned long y, char *str)
  361. {
  362. while(1)
  363. {
  364. if( (*str)=='\0' ) break;
  365. if( LCD_PutChar(x, y, *str++) == 0 ) break;
  366. x += 6;
  367. }
  368. }
  369. static rt_err_t rt_lcd_control (rt_device_t dev, int cmd, void *args)
  370. {
  371. switch (cmd)
  372. {
  373. #ifdef RT_USING_RTGUI
  374. case RTGRAPHIC_CTRL_RECT_UPDATE:
  375. rt_hw_lcd_update(args);
  376. break;
  377. case RTGRAPHIC_CTRL_POWERON:
  378. break;
  379. case RTGRAPHIC_CTRL_POWEROFF:
  380. break;
  381. case RTGRAPHIC_CTRL_GET_INFO:
  382. rt_memcpy(args, &_lcd_info, sizeof(_lcd_info));
  383. break;
  384. case RTGRAPHIC_CTRL_SET_MODE:
  385. break;
  386. #else
  387. case RT_DEVICE_CTRL_LCD_DISPLAY_ON:
  388. lcd_write_cmd(DISPLAY_ON);
  389. break;
  390. case RT_DEVICE_CTRL_LCD_DISPLAY_OFF:
  391. lcd_write_cmd(DISPLAY_OFF);
  392. break;
  393. case RT_DEVICE_CTRL_LCD_PUT_STRING:
  394. LCD_PutString(x, y, (char*)args);
  395. break;
  396. case RT_DEVICE_CTRL_LCD_CLEAR_SCR:
  397. LCD_ClearSCR();
  398. break;
  399. #endif
  400. }
  401. return RT_EOK;
  402. }
  403. void rt_hw_lcd_init(void)
  404. {
  405. rt_device_t lcd = rt_malloc(sizeof(struct rt_device));
  406. if (lcd == RT_NULL) return; /* no memory yet */
  407. _lcd_info.bits_per_pixel = 16;
  408. _lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565;
  409. _lcd_info.framebuffer = RT_NULL;
  410. _lcd_info.width = LCD_WIDTH;
  411. _lcd_info.height = LCD_HEIGHT;
  412. /* init device structure */
  413. lcd->type = RT_Device_Class_Unknown;
  414. lcd->init = rt_lcd_init;
  415. lcd->open = RT_NULL;
  416. lcd->close = RT_NULL;
  417. lcd->control = rt_lcd_control;
  418. #ifdef RT_USING_RTGUI
  419. lcd->user_data = (void*)&_lcd_ops;
  420. #endif
  421. /* register lcd device to RT-Thread */
  422. rt_device_register(lcd, "lcd", RT_DEVICE_FLAG_RDWR);
  423. }