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