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