gd32f307c_lcd_eval.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*!
  2. \file gd32f307c_lcd_eval.c
  3. \brief LCD driver functions
  4. \version 2017-02-10, V1.0.0, firmware for GD32F30x
  5. \version 2018-10-10, V1.1.0, firmware for GD32F30x
  6. \version 2018-12-25, V2.0.0, firmware for GD32F30x
  7. \version 2020-09-30, V2.1.0, firmware for GD32F30x
  8. */
  9. /*
  10. Copyright (c) 2020, GigaDevice Semiconductor Inc.
  11. Redistribution and use in source and binary forms, with or without modification,
  12. are permitted provided that the following conditions are met:
  13. 1. Redistributions of source code must retain the above copyright notice, this
  14. list of conditions and the following disclaimer.
  15. 2. Redistributions in binary form must reproduce the above copyright notice,
  16. this list of conditions and the following disclaimer in the documentation
  17. and/or other materials provided with the distribution.
  18. 3. Neither the name of the copyright holder nor the names of its contributors
  19. may be used to endorse or promote products derived from this software without
  20. specific prior written permission.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  23. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  24. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  25. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  28. WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  30. OF SUCH DAMAGE.
  31. */
  32. #include "drv_usb_hw.h"
  33. #include "gd32f307c_lcd_eval.h"
  34. #include "lcd_font.h"
  35. #include <string.h>
  36. #define LCD_ILI9320 0x8989
  37. #define LCD_ILI9325 0x9325
  38. #define ABS(X) ((X) > 0 ? (X) : -(X))
  39. static font_struct *cur_fonts;
  40. /* set the cursor of LCD */
  41. static void lcd_cursor_set(uint16_t x,uint16_t y);
  42. __IO uint16_t cur_text_color = 0x0000U;
  43. __IO uint16_t cur_back_color = 0xFFFFU;
  44. __IO uint16_t cur_text_direction = CHAR_DIRECTION_HORIZONTAL;
  45. /*!
  46. \brief initializes the LCD of GD EVAL board
  47. \param[in] none
  48. \param[out] none
  49. \retval none
  50. */
  51. void gd_eval_lcd_init(void)
  52. {
  53. __IO uint32_t lcd_id = 0;
  54. exmc_lcd_init();
  55. usb_mdelay(50);
  56. /* Read the LCD ID */
  57. lcd_id = lcd_register_read(R0);
  58. /* check if the LCD is ILI9320 controller */
  59. if (LCD_ILI9320 == lcd_id) {
  60. lcd_init();
  61. }
  62. }
  63. /*!
  64. \brief lcd peripheral initialize
  65. \param[in] none
  66. \param[out] none
  67. \retval none
  68. */
  69. void exmc_lcd_init(void)
  70. {
  71. exmc_norsram_parameter_struct lcd_init_struct;
  72. exmc_norsram_timing_parameter_struct lcd_timing_init_struct;
  73. /* EXMC clock enable */
  74. rcu_periph_clock_enable(RCU_EXMC);
  75. /* GPIO clock enable */
  76. rcu_periph_clock_enable(RCU_GPIOD);
  77. rcu_periph_clock_enable(RCU_GPIOE);
  78. rcu_periph_clock_enable(RCU_GPIOG);
  79. /* configure EXMC_D[0~15]*/
  80. /* PD14(EXMC_D0), PD15(EXMC_D1),PD0(EXMC_D2), PD1(EXMC_D3), PD8(EXMC_D13), PD9(EXMC_D14), PD10(EXMC_D15) */
  81. gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_8 | GPIO_PIN_9 |
  82. GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
  83. /* PE7(EXMC_D4), PE8(EXMC_D5), PE9(EXMC_D6), PE10(EXMC_D7), PE11(EXMC_D8), PE12(EXMC_D9),
  84. PE13(EXMC_D10), PE14(EXMC_D11), PE15(EXMC_D12) */
  85. gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |
  86. GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
  87. GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
  88. /* configure PE2(EXMC_A23) */
  89. gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
  90. /* configure PD4(NOE) and PD5(NWE) */
  91. gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4 | GPIO_PIN_5);
  92. /* configure EXMC NE1 */
  93. gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
  94. lcd_timing_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
  95. lcd_timing_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
  96. lcd_timing_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_DISABLE;
  97. lcd_timing_init_struct.bus_latency = 2;
  98. lcd_timing_init_struct.asyn_data_setuptime = 10;
  99. lcd_timing_init_struct.asyn_address_holdtime = 2;
  100. lcd_timing_init_struct.asyn_address_setuptime = 5;
  101. lcd_init_struct.norsram_region = EXMC_BANK0_NORSRAM_REGION0;
  102. lcd_init_struct.write_mode = EXMC_ASYN_WRITE;
  103. lcd_init_struct.extended_mode = DISABLE;
  104. lcd_init_struct.asyn_wait = DISABLE;
  105. lcd_init_struct.nwait_signal = DISABLE;
  106. lcd_init_struct.memory_write = ENABLE;
  107. lcd_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;
  108. lcd_init_struct.wrap_burst_mode = DISABLE;
  109. lcd_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;
  110. lcd_init_struct.burst_mode = DISABLE;
  111. lcd_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;
  112. lcd_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM;
  113. lcd_init_struct.address_data_mux = DISABLE;
  114. lcd_init_struct.read_write_timing = &lcd_timing_init_struct;
  115. lcd_init_struct.write_timing = &lcd_timing_init_struct;
  116. exmc_norsram_init(&lcd_init_struct);
  117. exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION1);
  118. }
  119. /*!
  120. \brief write data to the selected LCD register
  121. \param[in] register_id: the selected register id
  122. \param[in] value: the register value to be written
  123. \param[out] none
  124. \retval none
  125. */
  126. void lcd_register_write(uint16_t register_id,uint16_t value)
  127. {
  128. *(__IO uint16_t *) (BANK0_LCD_C)= register_id;
  129. *(__IO uint16_t *) (BANK0_LCD_D)= value;
  130. }
  131. /*!
  132. \brief read the value of LCD register
  133. \param[in] register_id: the register id
  134. \param[out] none
  135. \retval the register value
  136. */
  137. uint16_t lcd_register_read(uint8_t register_id)
  138. {
  139. uint16_t data;
  140. *(__IO uint16_t *) (BANK0_LCD_C)= register_id;
  141. data = *(__IO uint16_t *) (BANK0_LCD_D);
  142. return data;
  143. }
  144. /*!
  145. \brief write command to LCD register
  146. \param[in] value: the register value to be written
  147. \param[out] none
  148. \retval none
  149. */
  150. void lcd_command_write(uint16_t value)
  151. {
  152. /* write 16-bit index, then write reg */
  153. *(__IO uint16_t *) (BANK0_LCD_D) = value;
  154. }
  155. /*!
  156. \brief prepare to write to the LCD GRAM register(R22h)
  157. \param[in] none
  158. \param[out] none
  159. \retval none
  160. */
  161. void lcd_gram_write_prepare(void)
  162. {
  163. *(__IO uint16_t *) (BANK0_LCD_C) = 0x0022;
  164. }
  165. /*!
  166. \brief write RGB code to the LCD GRAM register
  167. \param[in] rgb_code: the pixel color in RGB mode (5-6-5)
  168. \param[out] none
  169. \retval none
  170. */
  171. void lcd_gram_write(uint16_t rgb_code)
  172. {
  173. /* write 16-bit GRAM register */
  174. *(__IO uint16_t *) (BANK0_LCD_D) = rgb_code;
  175. }
  176. /*!
  177. \brief read data from GRAM
  178. \param[in] none
  179. \param[out] none
  180. \retval GRAM value
  181. */
  182. uint16_t lcd_gram_read(void)
  183. {
  184. uint16_t data;
  185. /* write GRAM register (R22h) */
  186. *(__IO uint16_t *) (BANK0_LCD_C) = 0x0022;
  187. /* dummy read (invalid data) */
  188. *(__IO uint16_t *) (BANK0_LCD_D);
  189. data = *(__IO uint16_t *) (BANK0_LCD_D);
  190. return data;
  191. }
  192. /*!
  193. \brief initialize the LCD
  194. \param[in] none
  195. \param[out] none
  196. \retval none
  197. */
  198. void lcd_init(void)
  199. {
  200. uint16_t i;
  201. if(1){ /*!< if(device_code == 0x8989) */
  202. lcd_register_write(0x0000,0x0001);
  203. lcd_register_write(0x0003,0xA8A4);
  204. lcd_register_write(0x000C,0x0000);
  205. lcd_register_write(0x000D,0x080C);
  206. lcd_register_write(0x000E,0x2B00);
  207. lcd_register_write(0x001E,0x00B0);
  208. lcd_register_write(0x0001,0x693F);
  209. lcd_register_write(0x0002,0x0600);
  210. lcd_register_write(0x0010,0x0000);
  211. lcd_register_write(0x0011,0x6070);
  212. lcd_register_write(0x0005,0x0000);
  213. lcd_register_write(0x0006,0x0000);
  214. lcd_register_write(0x0016,0xEF1C);
  215. lcd_register_write(0x0017,0x0003);
  216. lcd_register_write(0x0007,0x0233);
  217. lcd_register_write(0x000B,0x0000);
  218. lcd_register_write(0x000F,0x0000);
  219. lcd_register_write(0x0041,0x0000);
  220. lcd_register_write(0x0042,0x0000);
  221. lcd_register_write(0x0048,0x0000);
  222. lcd_register_write(0x0049,0x013F);
  223. lcd_register_write(0x004A,0x0000);
  224. lcd_register_write(0x004B,0x0000);
  225. lcd_register_write(0x0044,0xEF00);
  226. lcd_register_write(0x0045,0x0000);
  227. lcd_register_write(0x0046,0x013F);
  228. lcd_register_write(0x0030,0x0707);
  229. lcd_register_write(0x0031,0x0204);
  230. lcd_register_write(0x0032,0x0204);
  231. lcd_register_write(0x0033,0x0502);
  232. lcd_register_write(0x0034,0x0507);
  233. lcd_register_write(0x0035,0x0204);
  234. lcd_register_write(0x0036,0x0204);
  235. lcd_register_write(0x0037,0x0502);
  236. lcd_register_write(0x003A,0x0302);
  237. lcd_register_write(0x003B,0x0302);
  238. lcd_register_write(0x0023,0x0000);
  239. lcd_register_write(0x0024,0x0000);
  240. lcd_register_write(0x0025,0x8000);
  241. lcd_register_write(0x004e,0);
  242. lcd_register_write(0x004f,0);
  243. }else{
  244. return;
  245. }
  246. for(i=50000;i>0;i--);
  247. }
  248. /*!
  249. \brief set the text color
  250. \param[in] color: LCD color
  251. \arg LCD_COLOR_WHITE
  252. \arg LCD_COLOR_BLACK
  253. \arg LCD_COLOR_GREY
  254. \arg LCD_COLOR_BLUE
  255. \arg LCD_COLOR_BLUE2
  256. \arg LCD_COLOR_RED
  257. \arg LCD_COLOR_MAGENTA
  258. \arg LCD_COLOR_GREEN
  259. \arg LCD_COLOR_CYAN
  260. \arg LCD_COLOR_YELLOW
  261. \param[out] none
  262. \retval none
  263. */
  264. void lcd_text_color_set(__IO uint16_t color)
  265. {
  266. cur_text_color = color;
  267. }
  268. /*!
  269. \brief get the current text color
  270. \param[in] none
  271. \param[out] none
  272. \retval LCD color
  273. \arg LCD_COLOR_WHITE
  274. \arg LCD_COLOR_BLACK
  275. \arg LCD_COLOR_GREY
  276. \arg LCD_COLOR_BLUE
  277. \arg LCD_COLOR_BLUE2
  278. \arg LCD_COLOR_RED
  279. \arg LCD_COLOR_MAGENTA
  280. \arg LCD_COLOR_GREEN
  281. \arg LCD_COLOR_CYAN
  282. \arg LCD_COLOR_YELLOW
  283. */
  284. uint16_t lcd_text_color_get(void)
  285. {
  286. return cur_text_color;
  287. }
  288. /*!
  289. \brief set the background color
  290. \param[in] color: LCD color
  291. \arg LCD_COLOR_WHITE
  292. \arg LCD_COLOR_BLACK
  293. \arg LCD_COLOR_GREY
  294. \arg LCD_COLOR_BLUE
  295. \arg LCD_COLOR_BLUE2
  296. \arg LCD_COLOR_RED
  297. \arg LCD_COLOR_MAGENTA
  298. \arg LCD_COLOR_GREEN
  299. \arg LCD_COLOR_CYAN
  300. \arg LCD_COLOR_YELLOW
  301. \param[out] none
  302. \retval none
  303. */
  304. void lcd_background_color_set(__IO uint16_t color)
  305. {
  306. cur_back_color = color;
  307. }
  308. /*!
  309. \brief get the current background color
  310. \param[in] none
  311. \param[out] none
  312. \retval LCD color
  313. \arg LCD_COLOR_WHITE
  314. \arg LCD_COLOR_BLACK
  315. \arg LCD_COLOR_GREY
  316. \arg LCD_COLOR_BLUE
  317. \arg LCD_COLOR_BLUE2
  318. \arg LCD_COLOR_RED
  319. \arg LCD_COLOR_MAGENTA
  320. \arg LCD_COLOR_GREEN
  321. \arg LCD_COLOR_CYAN
  322. \arg LCD_COLOR_YELLOW
  323. */
  324. uint16_t lcd_background_color_get(void)
  325. {
  326. return cur_back_color;
  327. }
  328. /*!
  329. \brief set the text font
  330. \param[in] font: the text font
  331. \param[out] none
  332. \retval none
  333. */
  334. void lcd_font_set(font_struct *fonts)
  335. {
  336. cur_fonts = fonts;
  337. }
  338. /*!
  339. \brief get the text font
  340. \param[in] none
  341. \param[out] none
  342. \retval the text font
  343. */
  344. font_struct *lcd_font_get(void)
  345. {
  346. return cur_fonts;
  347. }
  348. /*!
  349. \brief set the cursor of LCD
  350. \param[in] x: the row-coordinate
  351. \param[in] y: the column-coordinate
  352. \param[out] none
  353. \retval none
  354. */
  355. static void lcd_cursor_set(uint16_t x,uint16_t y)
  356. {
  357. lcd_register_write(0x004e,x);
  358. lcd_register_write(0x004f,y);
  359. }
  360. /*!
  361. \brief clear the LCD screen to the specified color
  362. \param[in] color: specified screen color
  363. \param[out] none
  364. \retval none
  365. */
  366. void lcd_clear(uint16_t color)
  367. {
  368. uint32_t index=0;
  369. lcd_cursor_set(0,0);
  370. /* prepare to write GRAM */
  371. lcd_gram_write_prepare();
  372. for(index=0;index<76800;index++){
  373. *(__IO uint16_t *) (BANK0_LCD_D) = color;
  374. }
  375. }
  376. /*!
  377. \brief set the point according to the specified position and color
  378. \param[in] x: the row-coordinate
  379. \param[in] y: the column-coordinate
  380. \param[in] point: specified color of the point
  381. \param[out] none
  382. \retval none
  383. */
  384. void lcd_point_set(uint16_t x,uint16_t y,uint16_t point)
  385. {
  386. if ((x > 240)||(y > 320)){
  387. return;
  388. }
  389. lcd_cursor_set(x,y);
  390. lcd_gram_write_prepare();
  391. lcd_gram_write(point);
  392. }
  393. /*!
  394. \brief get point GRAM according to the specified position
  395. \param[in] x: the row-coordinate
  396. \param[in] y: the column-coordinate
  397. \param[out] none
  398. \retval GRAM value of point
  399. */
  400. uint16_t lcd_point_get(uint16_t x,uint16_t y)
  401. {
  402. uint16_t data;
  403. if ((x > 240)||(y > 320)){
  404. return 0;
  405. }
  406. lcd_cursor_set(x,y);
  407. data = lcd_gram_read();
  408. return data;
  409. }
  410. /*!
  411. \brief draw a horizontal line on LCD screen
  412. \param[in] x: the row-coordinate
  413. \param[in] start_y: the start column-coordinate
  414. \param[in] end_y: the end column-coordinate
  415. \param[in] color: specified color of the point
  416. \param[in] width: line width
  417. \param[out] none
  418. \retval none
  419. */
  420. void lcd_hline_draw(uint16_t x,uint16_t start_y,uint16_t end_y,uint16_t color,uint16_t width)
  421. {
  422. uint16_t i, y;
  423. for (i = 0; i < width; i++) {
  424. uint16_t sx = x + i;
  425. for (y = start_y; y < end_y; y++) {
  426. lcd_point_set(sx, y, color);
  427. }
  428. }
  429. }
  430. /*!
  431. \brief draw a rectangle according to the specified position and color
  432. \param[in] start_x: the start position of row-coordinate
  433. \param[in] start_y: the start position of column-coordinate
  434. \param[in] end_x: the end position of row-coordinate
  435. \param[in] end_y: the end position of column-coordinate
  436. \param[in] point: specified color of the point
  437. \param[out] none
  438. \retval none
  439. */
  440. void lcd_rectangle_draw(uint16_t start_x,uint16_t start_y,uint16_t end_x,uint16_t end_y,uint16_t point)
  441. {
  442. uint16_t x,y;
  443. x=start_x;
  444. y=start_y;
  445. /* draw four lines */
  446. for(x=start_x;x<end_x;x++){
  447. /* draw a point */
  448. lcd_point_set(x,y,point);
  449. }
  450. for(y=start_y;y<end_y;y++){
  451. lcd_point_set(x,y,point);
  452. }
  453. for(x=end_x;x>start_x;x--){
  454. lcd_point_set(x,y,point);
  455. }
  456. for(y=end_y;y>start_y;y--){
  457. lcd_point_set(x,y,point);
  458. }
  459. }
  460. /*!
  461. \brief fill the specified color to a rectangle
  462. \param[in] start_x: the start position of row-coordinate
  463. \param[in] start_y: the start position of column-coordinate
  464. \param[in] end_x: the end position of row-coordinate
  465. \param[in] end_y: the end position of column-coordinate
  466. \param[in] color: specified color
  467. \param[out] none
  468. \retval none
  469. */
  470. void lcd_rectangle_fill(uint16_t start_x,uint16_t start_y,uint16_t width,uint16_t height)
  471. {
  472. uint16_t x, y;
  473. x = start_x;
  474. y = start_y;
  475. for (x = start_x; x < start_x+width; x++) {
  476. for (y = start_y; y < start_y+height; y++) {
  477. lcd_point_set(x, y, cur_text_color);
  478. }
  479. }
  480. }
  481. /*!
  482. \brief display a char on LCD screen according to the specified position
  483. \param[in] x: the start position of row-coordinate
  484. \param[in] y: the start position of column-coordinate
  485. \param[in] c: the char
  486. \param[in] char_color: the color of char
  487. \param[in] c_format: the struct of char format
  488. font: CHAR_FONT_8_16 or CHAR_FONT_16_24
  489. direction: CHAR_DIRECTION_HORIZONTAL or CHAR_DIRECTION_VERTICAL
  490. char_color: the color of char
  491. bk_color: the color of backgroud
  492. \param[out] none
  493. \retval none
  494. */
  495. void lcd_char_display(uint16_t x,uint16_t y,uint8_t c)
  496. {
  497. uint16_t i = 0, j = 0;
  498. uint8_t temp_char = 0;
  499. for (i = 0; i < cur_fonts->height; i++) {
  500. temp_char = cur_fonts->table[((c - 0x20) * 16) + i];
  501. if(CHAR_DIRECTION_HORIZONTAL == cur_text_direction){
  502. for (j = 0; j < cur_fonts->width; j++) {
  503. if (((temp_char >> (7 - j)) & 0x01) == 0x01) {
  504. /* set point of char */
  505. lcd_point_set(x - i, y + j, cur_text_color);
  506. } else {
  507. /* set point of background */
  508. lcd_point_set(x - i, y + j, cur_back_color);
  509. }
  510. }
  511. }else{
  512. for (j = 0; j < cur_fonts->width; j++) {
  513. if (((temp_char >> (7 - j)) & 0x01) == 0x01) {
  514. /* set point of char */
  515. lcd_point_set(x + j, y + i, cur_text_color);
  516. } else {
  517. /* set point of background */
  518. lcd_point_set(x + j, y + i, cur_back_color);
  519. }
  520. }
  521. }
  522. }
  523. }
  524. /* display the vertical character on LCD */
  525. void lcd_vertical_char_display(uint16_t line, uint16_t column, uint8_t ascii)
  526. {
  527. lcd_char_display(line, column, ascii);
  528. }
  529. void lcd_vertical_string_display(uint16_t stringline, uint16_t offset, uint8_t *ptr)
  530. {
  531. uint16_t i = 0U;
  532. int len = strlen((const char *)ptr);
  533. for (i = 0; i < len; i ++) {
  534. lcd_char_display(stringline, (offset + 8 * i), *ptr++);
  535. }
  536. }