1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2023-03-24     spaceman          the first version
9  */
10 
11 #include <board.h>
12 
13 #ifdef BSP_USING_LCD_SPI
14 #include <drv_spi.h>
15 #include <drv_lcd_spi.h>
16 #include <drv_lcd_spi_ext.h>
17 #include <lcd_port.h>
18 #include <string.h>
19 
20 #define DRV_DEBUG
21 #define LOG_TAG "drv.lcd"
22 #include <drv_log.h>
23 
24 #define ABS(X) ((X) > 0 ? (X) : -(X))
25 
26 static struct drv_lcd_device _lcd;
27 static rt_uint8_t lcd_bn = 0;
28 
29 // 因为这类SPI的屏幕,每次更新显示时,需要先配置坐标区域、再写显存,
30 // 在显示字符时,如果是一个个点去写坐标写显存,会非常慢,
31 // 因此开辟一片缓冲区,先将需要显示的数据写进缓冲区,最后再批量写入显存。
32 // 用户可以根据实际情况去修改此处缓冲区的大小,
33 // 例如,用户需要显示32*32的汉字时,需要的大小为 32*32*2 = 2048 字节(每个像素点占2字节)
34 static uint16_t LCD_Buff[1024]; // LCD缓冲区,16位宽(每个像素点占2字节)
35 
set_lcd_backlight(rt_uint8_t value)36 static void set_lcd_backlight(rt_uint8_t value)
37 {
38     if (value)
39         rt_pin_write(LCD_BACKLIGHT_PIN, PIN_HIGH);
40     else
41         rt_pin_write(LCD_BACKLIGHT_PIN, PIN_LOW);
42     lcd_bn = value;
43 }
44 
get_lcd_backlight(void)45 static rt_uint8_t get_lcd_backlight(void)
46 {
47     return lcd_bn;
48 }
49 
lcd_writecommand(uint8_t lcd_command)50 static void lcd_writecommand(uint8_t lcd_command)
51 {
52     rt_pin_write(LCD_CMD_DATA_PIN, PIN_LOW); // cmd
53     rt_spi_send((struct rt_spi_device *)_lcd.lcd_spi_dev, &lcd_command, 1);
54 }
55 
lcd_writedata_8bit(uint8_t lcd_data)56 static void lcd_writedata_8bit(uint8_t lcd_data)
57 {
58     rt_pin_write(LCD_CMD_DATA_PIN, PIN_HIGH); // data
59     rt_spi_send((struct rt_spi_device *)_lcd.lcd_spi_dev, &lcd_data, 1);
60 }
61 
lcd_writedata_16bit(uint16_t lcd_data)62 static void lcd_writedata_16bit(uint16_t lcd_data)
63 {
64     uint8_t lcd_data_buff[2];         // 数据发送区
65     lcd_data_buff[0] = lcd_data >> 8; // 将数据拆分
66     lcd_data_buff[1] = lcd_data;
67 
68     rt_pin_write(LCD_CMD_DATA_PIN, PIN_HIGH); // data
69     rt_spi_send((struct rt_spi_device *)_lcd.lcd_spi_dev, lcd_data_buff, 2);
70 }
71 
lcd_writebuff(uint16_t * databuff,uint16_t datasize)72 void lcd_writebuff(uint16_t *databuff, uint16_t datasize)
73 {
74     struct stm32_spi *spi_drv =  rt_container_of(((struct rt_spi_device *)_lcd.lcd_spi_dev)->bus, struct stm32_spi, spi_bus);
75     SPI_HandleTypeDef *spi_handle = &spi_drv->handle;
76 
77     rt_pin_write(LCD_CMD_DATA_PIN, PIN_HIGH); // data
78 
79     // Additional setting (FifoThreshold) are required here, so we do not use rt_spi_configure
80     spi_handle->Init.DataSize   = SPI_DATASIZE_16BIT;
81     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_02DATA;
82     HAL_SPI_Init(spi_handle);
83 
84     rt_spi_send((struct rt_spi_device *)_lcd.lcd_spi_dev, databuff, datasize);
85 
86     spi_handle->Init.DataSize   = SPI_DATASIZE_8BIT;
87     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_08DATA;
88     HAL_SPI_Init(spi_handle);
89 }
90 
lcd_setaddress(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)91 void lcd_setaddress(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
92 {
93     lcd_writecommand(0x2a); //  列地址设置,即X坐标
94     lcd_writedata_16bit(x1);
95     lcd_writedata_16bit(x2);
96 
97     lcd_writecommand(0x2b); //  行地址设置,即Y坐标
98     lcd_writedata_16bit(y1);
99     lcd_writedata_16bit(y2);
100 
101     lcd_writecommand(0x2c); //  开始写入显存,即要显示的颜色数据
102 }
103 
lcd_clear(uint32_t color)104 void lcd_clear(uint32_t color)
105 {
106     rt_err_t res;
107     struct stm32_spi *spi_drv =  rt_container_of(((struct rt_spi_device *)_lcd.lcd_spi_dev)->bus, struct stm32_spi, spi_bus);
108     SPI_HandleTypeDef *spi_handle = &spi_drv->handle;
109 
110     lcd_setaddress(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1); // 设置坐标
111 
112     rt_pin_write(LCD_CMD_DATA_PIN, PIN_HIGH); // data
113 
114     // Additional setting (FifoThreshold) are required here, so we do not use rt_spi_configure
115     spi_handle->Init.DataSize   = SPI_DATASIZE_16BIT;
116     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_02DATA;
117     HAL_SPI_Init(spi_handle);
118 
119     rt_pin_write(LCD_SPI_DEV_CS_PIN, PIN_LOW); // cs
120     res = SPI_Transmit_Ext((uint16_t)color, LCD_WIDTH * LCD_HEIGHT);
121     rt_pin_write(LCD_SPI_DEV_CS_PIN, PIN_HIGH); // cs
122     if(res != RT_EOK)
123         LOG_E("SPI_Transmit_Ext error: %d", res);
124 
125     spi_handle->Init.DataSize   = SPI_DATASIZE_8BIT;
126     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_08DATA;
127     HAL_SPI_Init(spi_handle);
128 }
129 
lcd_clearrect(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint32_t color)130 void lcd_clearrect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color)
131 {
132     rt_err_t res;
133     struct stm32_spi *spi_drv =  rt_container_of(((struct rt_spi_device *)_lcd.lcd_spi_dev)->bus, struct stm32_spi, spi_bus);
134     SPI_HandleTypeDef *spi_handle = &spi_drv->handle;
135 
136     lcd_setaddress(x, y, x + width - 1, y + height - 1); // 设置坐标
137 
138     rt_pin_write(LCD_CMD_DATA_PIN, PIN_HIGH); // data
139 
140     // Additional setting (FifoThreshold) are required here, so we do not use rt_spi_configure
141     spi_handle->Init.DataSize   = SPI_DATASIZE_16BIT;
142     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_02DATA;
143     HAL_SPI_Init(spi_handle);
144 
145     rt_pin_write(LCD_SPI_DEV_CS_PIN, PIN_LOW); // cs
146     res = SPI_Transmit_Ext((uint16_t)color, width * height);
147     rt_pin_write(LCD_SPI_DEV_CS_PIN, PIN_HIGH); // cs
148     if(res != RT_EOK)
149         LOG_E("SPI_Transmit_Ext error: %d", res);
150 
151     spi_handle->Init.DataSize   = SPI_DATASIZE_8BIT;
152     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_08DATA;
153     HAL_SPI_Init(spi_handle);
154 }
155 
lcd_copybuffer(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint16_t * databuff)156 void lcd_copybuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t *databuff)
157 {
158     rt_err_t res;
159     struct stm32_spi *spi_drv =  rt_container_of(((struct rt_spi_device *)_lcd.lcd_spi_dev)->bus, struct stm32_spi, spi_bus);
160     SPI_HandleTypeDef *spi_handle = &spi_drv->handle;
161 
162     lcd_setaddress(x, y, x + width - 1, y + height - 1); // 设置坐标
163 
164     rt_pin_write(LCD_CMD_DATA_PIN, PIN_HIGH); // data
165 
166     // Additional setting (FifoThreshold) are required here, so we do not use rt_spi_configure
167     spi_handle->Init.DataSize   = SPI_DATASIZE_16BIT;
168     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_02DATA;
169     HAL_SPI_Init(spi_handle);
170 
171     rt_pin_write(LCD_SPI_DEV_CS_PIN, PIN_LOW); // cs
172     res = SPI_TransmitBuffer_Ext(databuff, width * height);
173     rt_pin_write(LCD_SPI_DEV_CS_PIN, PIN_HIGH); // cs
174     if(res != RT_EOK)
175         LOG_E("SPI_TransmitBuffer_Ext error: %d", res);
176 
177     spi_handle->Init.DataSize   = SPI_DATASIZE_8BIT;
178     spi_handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_08DATA;
179     HAL_SPI_Init(spi_handle);
180 }
181 
lcd_drawpoint(uint16_t x,uint16_t y,uint32_t color)182 void lcd_drawpoint(uint16_t x, uint16_t y, uint32_t color)
183 {
184     lcd_setaddress(x, y, x, y); //  设置坐标
185     lcd_writedata_16bit(color);
186 }
187 
lcd_drawline(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint32_t color)188 void lcd_drawline(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color)
189 {
190     int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
191             yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
192             curpixel = 0;
193 
194     deltax = ABS(x2 - x1); /* The difference between the x's */
195     deltay = ABS(y2 - y1); /* The difference between the y's */
196     x      = x1;           /* Start x off at the first pixel */
197     y      = y1;           /* Start y off at the first pixel */
198 
199     if (x2 >= x1) /* The x-values are increasing */
200     {
201         xinc1 = 1;
202         xinc2 = 1;
203     } else /* The x-values are decreasing */
204     {
205         xinc1 = -1;
206         xinc2 = -1;
207     }
208 
209     if (y2 >= y1) /* The y-values are increasing */
210     {
211         yinc1 = 1;
212         yinc2 = 1;
213     } else /* The y-values are decreasing */
214     {
215         yinc1 = -1;
216         yinc2 = -1;
217     }
218 
219     if (deltax >= deltay) /* There is at least one x-value for every y-value */
220     {
221         xinc1     = 0; /* Don't change the x when numerator >= denominator */
222         yinc2     = 0; /* Don't change the y for every iteration */
223         den       = deltax;
224         num       = deltax / 2;
225         numadd    = deltay;
226         numpixels = deltax; /* There are more x-values than y-values */
227     } else                  /* There is at least one y-value for every x-value */
228     {
229         xinc2     = 0; /* Don't change the x for every iteration */
230         yinc1     = 0; /* Don't change the y when numerator >= denominator */
231         den       = deltay;
232         num       = deltay / 2;
233         numadd    = deltax;
234         numpixels = deltay; /* There are more y-values than x-values */
235     }
236     for (curpixel = 0; curpixel <= numpixels; curpixel++) {
237         lcd_drawpoint(x, y, color); /* Draw the current pixel */
238         num += numadd;              /* Increase the numerator by the top of the fraction */
239         if (num >= den)             /* Check if numerator >= denominator */
240         {
241             num -= den; /* Calculate the new numerator value */
242             x += xinc1; /* Change the x as appropriate */
243             y += yinc1; /* Change the y as appropriate */
244         }
245         x += xinc2; /* Change the x as appropriate */
246         y += yinc2; /* Change the y as appropriate */
247     }
248 }
249 
lcd_drawline_v(uint16_t x,uint16_t y,uint16_t height,uint32_t color)250 void lcd_drawline_v(uint16_t x, uint16_t y, uint16_t height, uint32_t color)
251 {
252     uint16_t i; // 计数变量
253     for (i = 0; i < height; i++) {
254         LCD_Buff[i] = color; // 写入缓冲区
255     }
256     lcd_setaddress(x, y, x, y + height - 1); // 设置坐标
257     lcd_writebuff(LCD_Buff, height); // 写入显存
258 }
259 
lcd_drawline_h(uint16_t x,uint16_t y,uint16_t width,uint32_t color)260 void lcd_drawline_h(uint16_t x, uint16_t y, uint16_t width, uint32_t color)
261 {
262     uint16_t i; // 计数变量
263     for (i = 0; i < width; i++) {
264         LCD_Buff[i] = color; // 写入缓冲区
265     }
266     lcd_setaddress(x, y, x + width - 1, y); // 设置坐标
267     lcd_writebuff(LCD_Buff, width); // 写入显存
268 }
269 
stm32_lcd_init(struct drv_lcd_device * lcd)270 static rt_err_t stm32_lcd_init(struct drv_lcd_device *lcd)
271 {
272     rt_err_t result;
273     struct rt_spi_configuration cfg;
274 
275     result = rt_hw_spi_device_attach(LCD_SPI_BUS_NAME, LCD_SPI_DEV_NAME, LCD_SPI_DEV_CS_PIN);
276 
277     lcd->lcd_spi_dev = rt_device_find(LCD_SPI_DEV_NAME);
278     cfg.data_width = 8;
279     cfg.mode       = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB | RT_SPI_3WIRE;
280     cfg.max_hz     = LCD_SPI_MAX_SPEED;
281     rt_spi_configure((struct rt_spi_device *)lcd->lcd_spi_dev, &cfg);
282 
283     rt_pin_mode(LCD_BACKLIGHT_PIN, PIN_MODE_OUTPUT);
284     rt_pin_mode(LCD_CMD_DATA_PIN, PIN_MODE_OUTPUT);
285 
286     // init lcd
287     rt_thread_mdelay(10);
288     lcd_writecommand(0x36);   // 显存访问控制 指令,用于设置访问显存的方式
289     lcd_writedata_8bit(0x00); // 配置成 从上到下、从左到右,RGB像素格式 垂直显示
290     // lcd_writedata_8bit(0x70); // 横屏显示
291     // lcd_writedata_8bit(0xA0); // 横屏显示,并上下翻转,RGB像素格式
292     // lcd_writedata_8bit(0xC0); // 垂直显示,并上下翻转,RGB像素格式
293 
294     lcd_writecommand(0x3A);   // 接口像素格式 指令,用于设置使用 12位、16位还是18位色
295     lcd_writedata_8bit(0x05); // 此处配置成 16位 像素格式
296 
297     // 接下来很多都是电压设置指令,直接使用厂家给设定值
298     lcd_writecommand(0xB2);
299     lcd_writedata_8bit(0x0C);
300     lcd_writedata_8bit(0x0C);
301     lcd_writedata_8bit(0x00);
302     lcd_writedata_8bit(0x33);
303     lcd_writedata_8bit(0x33);
304 
305     lcd_writecommand(0xB7);   // 栅极电压设置指令
306     lcd_writedata_8bit(0x35); // VGH = 13.26V,VGL = -10.43V
307 
308     lcd_writecommand(0xBB);   // 公共电压设置指令
309     lcd_writedata_8bit(0x19); // VCOM = 1.35V
310 
311     lcd_writecommand(0xC0);
312     lcd_writedata_8bit(0x2C);
313 
314     lcd_writecommand(0xC2);   // VDV 和 VRH 来源设置
315     lcd_writedata_8bit(0x01); // VDV 和 VRH 由用户自由配置
316 
317     lcd_writecommand(0xC3);   // VRH电压 设置指令
318     lcd_writedata_8bit(0x12); // VRH电压 = 4.6+( vcom+vcom offset+vdv)
319 
320     lcd_writecommand(0xC4);   // VDV电压 设置指令
321     lcd_writedata_8bit(0x20); // VDV电压 = 0v
322 
323     lcd_writecommand(0xC6);   // 正常模式的帧率控制指令
324     lcd_writedata_8bit(0x0F); // 设置屏幕控制器的刷新帧率为60帧
325 
326     lcd_writecommand(0xD0);   // 电源控制指令
327     lcd_writedata_8bit(0xA4); // 无效数据,固定写入0xA4
328     lcd_writedata_8bit(0xA1); // AVDD = 6.8V ,AVDD = -4.8V ,VDS = 2.3V
329 
330     lcd_writecommand(0xE0); // 正极电压伽马值设定
331     lcd_writedata_8bit(0xD0);
332     lcd_writedata_8bit(0x04);
333     lcd_writedata_8bit(0x0D);
334     lcd_writedata_8bit(0x11);
335     lcd_writedata_8bit(0x13);
336     lcd_writedata_8bit(0x2B);
337     lcd_writedata_8bit(0x3F);
338     lcd_writedata_8bit(0x54);
339     lcd_writedata_8bit(0x4C);
340     lcd_writedata_8bit(0x18);
341     lcd_writedata_8bit(0x0D);
342     lcd_writedata_8bit(0x0B);
343     lcd_writedata_8bit(0x1F);
344     lcd_writedata_8bit(0x23);
345 
346     lcd_writecommand(0xE1); // 负极电压伽马值设定
347     lcd_writedata_8bit(0xD0);
348     lcd_writedata_8bit(0x04);
349     lcd_writedata_8bit(0x0C);
350     lcd_writedata_8bit(0x11);
351     lcd_writedata_8bit(0x13);
352     lcd_writedata_8bit(0x2C);
353     lcd_writedata_8bit(0x3F);
354     lcd_writedata_8bit(0x44);
355     lcd_writedata_8bit(0x51);
356     lcd_writedata_8bit(0x2F);
357     lcd_writedata_8bit(0x1F);
358     lcd_writedata_8bit(0x1F);
359     lcd_writedata_8bit(0x20);
360     lcd_writedata_8bit(0x23);
361 
362     lcd_writecommand(0x21); // 打开反显,因为面板是常黑型,操作需要反过来
363 
364     // 退出休眠指令,LCD控制器在刚上电、复位时,会自动进入休眠模式 ,因此操作屏幕之前,需要退出休眠
365     lcd_writecommand(0x11); // 退出休眠 指令
366     rt_thread_mdelay(120);  // 需要等待120ms,让电源电压和时钟电路稳定下来
367 
368     // 打开显示指令,LCD控制器在刚上电、复位时,会自动关闭显示
369     lcd_writecommand(0x29); // 打开显示
370 
371     // set spi handler to ensure SPI_Transmit_Ext/SPI_TransmitBuffer_Ext function can be used
372     struct stm32_spi *spi_drv =  rt_container_of(((struct rt_spi_device *)lcd->lcd_spi_dev)->bus, struct stm32_spi, spi_bus);
373     SPI_HandleTypeDef *spi_handle = &spi_drv->handle;
374     Set_SPI_Handle_Ext(spi_handle);
375 
376     lcd_clear(0xFFFFFF);                   // 清屏
377 
378     // 全部设置完毕之后,打开背光
379     set_lcd_backlight(1);
380 
381     LOG_D("lcd init ok");
382 
383     // lcd_drawline_v(120, 0, LCD_HEIGHT, 0xffaaff);
384     // lcd_drawline_h(0, 120, LCD_WIDTH, 0xffaaff);
385 
386     return result;
387 }
388 
drv_lcd_init(struct rt_device * device)389 static rt_err_t drv_lcd_init(struct rt_device *device)
390 {
391     struct drv_lcd_device *lcd = LCD_DEVICE(device);
392     return stm32_lcd_init(lcd);
393 }
394 
drv_lcd_control(struct rt_device * device,int cmd,void * args)395 static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
396 {
397     struct drv_lcd_device *lcd = LCD_DEVICE(device);
398 
399     switch (cmd) {
400         case RTGRAPHIC_CTRL_RECT_UPDATE: {
401             lcd_setaddress(0, 0, lcd->lcd_info.width - 1, lcd->lcd_info.height - 1);
402             lcd_writebuff((uint16_t*)lcd->lcd_info.framebuffer, LCD_BUF_SIZE / 2); // 16 bit write buffer
403         } break;
404 
405         case RTGRAPHIC_CTRL_GET_INFO: {
406             struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
407 
408             RT_ASSERT(info != RT_NULL);
409             info->pixel_format   = lcd->lcd_info.pixel_format;
410             info->bits_per_pixel = 16;
411             info->width          = lcd->lcd_info.width;
412             info->height         = lcd->lcd_info.height;
413             info->framebuffer    = lcd->lcd_info.framebuffer;
414         } break;
415 
416         case RTGRAPHIC_CTRL_SET_BRIGHTNESS: {
417             set_lcd_backlight(*((rt_uint8_t *)args));
418         } break;
419 
420         case RTGRAPHIC_CTRL_GET_BRIGHTNESS: {
421             *((rt_uint8_t *)args) = get_lcd_backlight();
422         } break;
423 
424         default:
425             return -RT_EINVAL;
426     }
427 
428     return RT_EOK;
429 }
430 
431 #ifdef RT_USING_DEVICE_OPS
432 const static struct rt_device_ops lcd_ops =
433 {
434     drv_lcd_init,
435     RT_NULL,
436     RT_NULL,
437     RT_NULL,
438     RT_NULL,
439     drv_lcd_control
440 };
441 #endif
442 
set_pixel(const char * pixel,int x,int y)443 static void set_pixel(const char *pixel, int x, int y)
444 {
445     lcd_drawpoint(x, y, *pixel);
446 }
447 
draw_hline(const char * pixel,int x1,int x2,int y)448 void draw_hline(const char *pixel, int x1, int x2, int y)
449 {
450     lcd_drawline_h(x1, y, ABS(x2 - x1), *((uint16_t*)pixel));
451 }
452 
draw_vline(const char * pixel,int x,int y1,int y2)453 void draw_vline(const char *pixel, int x, int y1, int y2)
454 {
455     lcd_drawline_v(x, y1, ABS(y2 - y1), *((uint16_t*)pixel));
456 }
457 
458 const static struct rt_device_graphic_ops lcd_graphic_ops =
459 {
460     set_pixel,
461     RT_NULL,
462     draw_hline,
463     draw_vline,
464     RT_NULL
465 };
466 
drv_hw_lcd_init(void)467 int drv_hw_lcd_init(void)
468 {
469     rt_err_t result          = RT_EOK;
470     struct rt_device *device = &_lcd.parent;
471 
472     /* memset _lcd to zero */
473     memset(&_lcd, 0x00, sizeof(_lcd));
474 
475     /* init lcd_lock semaphore */
476     result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
477     if (result != RT_EOK) {
478         LOG_E("init semaphore failed!\n");
479         result = -RT_ENOMEM;
480         goto __exit;
481     }
482 
483     /* config LCD dev info */
484     _lcd.lcd_info.height         = LCD_HEIGHT;
485     _lcd.lcd_info.width          = LCD_WIDTH;
486     _lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
487     _lcd.lcd_info.pixel_format   = LCD_PIXEL_FORMAT;
488 
489     /* malloc memory for Triple Buffering */
490     _lcd.lcd_info.framebuffer = rt_malloc_align(LCD_BUF_SIZE, 32);
491     _lcd.back_buf             = rt_malloc_align(LCD_BUF_SIZE, 32);
492     _lcd.front_buf            = rt_malloc_align(LCD_BUF_SIZE, 32);
493     if (_lcd.lcd_info.framebuffer == RT_NULL || _lcd.back_buf == RT_NULL || _lcd.front_buf == RT_NULL) {
494         LOG_E("init frame buffer failed!\n");
495         result = -RT_ENOMEM;
496         goto __exit;
497     }
498 
499     /* memset buff to 0xFF */
500     memset(_lcd.lcd_info.framebuffer, 0xFF, LCD_BUF_SIZE);
501     memset(_lcd.back_buf, 0xFF, LCD_BUF_SIZE);
502     memset(_lcd.front_buf, 0xFF, LCD_BUF_SIZE);
503 
504     device->type = RT_Device_Class_Graphic;
505 #ifdef RT_USING_DEVICE_OPS
506     device->ops = &lcd_ops;
507 #else
508     device->init    = drv_lcd_init;
509     device->control = drv_lcd_control;
510 #endif
511     device->user_data = (void*)&lcd_graphic_ops;
512 
513     /* register lcd device */
514     rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
515 
516     /* init stm32 spi lcd */
517     if (rt_device_init(device) != RT_EOK) {
518         result = -RT_ERROR;
519         goto __exit;
520     }
521 
522 __exit:
523     if (result != RT_EOK) {
524         rt_sem_delete(&_lcd.lcd_lock);
525 
526         if (_lcd.lcd_info.framebuffer) {
527             rt_free_align(_lcd.lcd_info.framebuffer);
528         }
529 
530         if (_lcd.back_buf) {
531             rt_free_align(_lcd.back_buf);
532         }
533 
534         if (_lcd.front_buf) {
535             rt_free_align(_lcd.front_buf);
536         }
537     }
538     return result;
539 }
540 INIT_DEVICE_EXPORT(drv_hw_lcd_init);
541 
542 #ifdef DRV_DEBUG
543 #ifdef FINSH_USING_MSH
lcd_test()544 int lcd_test()
545 {
546     struct drv_lcd_device *lcd;
547     lcd = (struct drv_lcd_device *)rt_device_find("lcd");
548 
549     rt_device_open((rt_device_t)lcd, RT_DEVICE_FLAG_RDWR);
550 
551     while (1) {
552         /* red */
553         for (int i = 0; i < LCD_BUF_SIZE / 2; i++) {
554             lcd->lcd_info.framebuffer[2 * i]     = 0x00;
555             lcd->lcd_info.framebuffer[2 * i + 1] = 0xF8;
556         }
557         // lcd_clear(0xFFFF00);
558         rt_device_control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
559         rt_thread_mdelay(1000);
560         /* green */
561         for (int i = 0; i < LCD_BUF_SIZE / 2; i++) {
562             lcd->lcd_info.framebuffer[2 * i]     = 0xE0;
563             lcd->lcd_info.framebuffer[2 * i + 1] = 0x07;
564         }
565         // lcd_clear(0xFF00FF);
566         rt_device_control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
567         rt_thread_mdelay(1000);
568         /* blue */
569         for (int i = 0; i < LCD_BUF_SIZE / 2; i++) {
570             lcd->lcd_info.framebuffer[2 * i]     = 0x1F;
571             lcd->lcd_info.framebuffer[2 * i + 1] = 0x00;
572         }
573         // lcd_clear(0x00FFFF);
574         rt_device_control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
575         rt_thread_mdelay(1000);
576     }
577 }
578 MSH_CMD_EXPORT(lcd_test, lcd_test);
579 
lcd_auto_fill(void * para)580 void lcd_auto_fill(void *para)
581 {
582     int num = (int)para;
583     do
584     {
585         lcd_clear(rt_tick_get());
586         rt_thread_mdelay(1000);
587     }while(--num);
588 }
589 
590 #include <stdlib.h> /* atoi */
lcd_fill(int argc,void ** argv)591 void lcd_fill(int argc, void **argv)
592 {
593     static rt_uint8_t lcd_init = 0;
594     rt_device_t lcd = RT_NULL;
595 
596     if(lcd_init == 0)
597     {
598         lcd_init = 1;
599 
600         lcd = rt_device_find("lcd");
601         rt_device_init(lcd);
602     }
603 
604     if(argc == 1)
605     {
606         lcd_auto_fill((void *)1);
607     }
608     else if(argc == 3)
609     {
610         if(rt_strcmp(argv[1], "-t")==0)
611         {
612             rt_thread_t tid = RT_NULL;
613             tid = rt_thread_create("lcd_fill", lcd_auto_fill, (void *)atoi(argv[2]), 512, 23,10);
614             rt_thread_startup(tid);
615         }
616     }
617 }
618 MSH_CMD_EXPORT(lcd_fill, lcd fill test for mcu lcd);
619 #endif /* FINSH_USING_MSH */
620 #endif /* DRV_DEBUG */
621 #endif /* BSP_USING_LCD */
622