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 * 2021-10-14 spaceman first version
9 */
10
11 #include <board.h>
12
13 #ifdef BSP_USING_LCD
14 #include <lcd_port.h>
15 #include "lcd.h"
16 #include "drv_gpio.h"
17
18 #define DRV_DEBUG
19 #define LOG_TAG "drv.lcd"
20 #include <drv_log.h>
21
22 #define LCD_DEVICE(dev) (struct drv_lcd_device*)(dev)
23
24
25 static __align(256) volatile rt_uint32_t LTDC_Buf1[LCD_WIDTH * LCD_HEIGHT] = {0x00};
26 static __align(256) volatile rt_uint32_t LTDC_Buf2[LCD_WIDTH * LCD_HEIGHT] = {0x00};
27
28
29 struct drv_lcd_device
30 {
31 struct rt_device parent;
32
33 struct rt_device_graphic_info lcd_info;
34
35 struct rt_semaphore lcd_lock;
36
37 /* 0:front_buf is being used 1: back_buf is being used*/
38 rt_uint8_t cur_buf;
39 rt_uint8_t *front_buf;
40 rt_uint8_t *back_buf;
41 };
42
43 struct drv_lcd_device _lcd;
44
drv_lcd_init(struct rt_device * device)45 static rt_err_t drv_lcd_init(struct rt_device *device)
46 {
47 struct drv_lcd_device *lcd = LCD_DEVICE(device);
48 /* nothing, right now */
49 lcd = lcd;
50 return RT_EOK;
51 }
52
drv_lcd_control(struct rt_device * device,int cmd,void * args)53 static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
54 {
55 struct drv_lcd_device *lcd = LCD_DEVICE(device);
56
57 switch (cmd)
58 {
59 case RTGRAPHIC_CTRL_RECT_UPDATE:
60 {
61 /* update */
62 if (_lcd.cur_buf)
63 {
64 /* back_buf is being used */
65 _lcd.lcd_info.framebuffer = _lcd.back_buf;
66 /* Configure the color frame buffer start address */
67 LTDC->DP_SWT = 0;
68 _lcd.cur_buf = 0;
69 }
70 else
71 {
72 /* front_buf is being used */
73 _lcd.lcd_info.framebuffer = _lcd.front_buf;
74 /* Configure the color frame buffer start address */
75 LTDC->DP_SWT = 1;
76 _lcd.cur_buf = 1;
77 }
78 rt_sem_take(&_lcd.lcd_lock, RT_TICK_PER_SECOND / 20);
79 }
80 break;
81
82 case RTGRAPHIC_CTRL_GET_INFO:
83 {
84 struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
85
86 RT_ASSERT(info != RT_NULL);
87 info->pixel_format = lcd->lcd_info.pixel_format;
88 info->bits_per_pixel = LCD_BITS_PER_PIXEL;
89 info->width = lcd->lcd_info.width;
90 info->height = lcd->lcd_info.height;
91 info->framebuffer = lcd->lcd_info.framebuffer;
92 }
93 break;
94 }
95
96 return RT_EOK;
97 }
98
99
100
101
102
stm32_lcd_init(struct drv_lcd_device * lcd)103 rt_err_t stm32_lcd_init(struct drv_lcd_device *lcd)
104 {
105 LCD_Initial((rt_uint32_t)lcd->front_buf, (rt_uint32_t)lcd->back_buf);
106 return RT_EOK;
107 }
108 #if defined(LCD_BACKLIGHT_USING_PWM)
turn_on_lcd_backlight(void)109 void turn_on_lcd_backlight(void)
110 {
111 struct rt_device_pwm *pwm_dev;
112
113 /* turn on the LCD backlight */
114 pwm_dev = (struct rt_device_pwm *)rt_device_find(LCD_PWM_DEV_NAME);
115 /* pwm frequency:100K = 10000ns */
116 rt_pwm_set(pwm_dev, LCD_PWM_DEV_CHANNEL, 10000, 10000);
117 rt_pwm_enable(pwm_dev, LCD_PWM_DEV_CHANNEL);
118 }
119 #elif defined(LCD_BACKLIGHT_USING_GPIO)
turn_on_lcd_backlight(void)120 void turn_on_lcd_backlight(void)
121 {
122 rt_pin_mode(LCD_BL_GPIO_NUM, PIN_MODE_OUTPUT);
123 rt_pin_mode(LCD_DISP_GPIO_NUM, PIN_MODE_OUTPUT);
124
125 rt_pin_write(LCD_DISP_GPIO_NUM, PIN_HIGH);
126 rt_pin_write(LCD_BL_GPIO_NUM, PIN_HIGH);
127 }
128 #else
turn_on_lcd_backlight(void)129 void turn_on_lcd_backlight(void)
130 {
131
132 }
133 #endif
134
135 #ifdef RT_USING_DEVICE_OPS
136 const static struct rt_device_ops lcd_ops =
137 {
138 drv_lcd_init,
139 RT_NULL,
140 RT_NULL,
141 RT_NULL,
142 RT_NULL,
143 drv_lcd_control
144 };
145 #endif
146
147
Lcd_ColorBox(struct drv_lcd_device * lcd,rt_uint16_t xStart,rt_uint16_t yStart,rt_uint16_t xLong,rt_uint16_t yLong,rt_uint32_t Color)148 void Lcd_ColorBox(struct drv_lcd_device *lcd, rt_uint16_t xStart, rt_uint16_t yStart, rt_uint16_t xLong, rt_uint16_t yLong, rt_uint32_t Color)
149 {
150 rt_uint16_t i, j;
151 rt_uint32_t temp;
152 rt_uint32_t *LTDC_Buf = (rt_uint32_t *)lcd->lcd_info.framebuffer;
153 temp = lcd->lcd_info.height * xStart;
154 for (i = 0; i < yLong; i++)
155 {
156 for (j = 0; j < xLong; j++)
157 LTDC_Buf[yStart + i + lcd->lcd_info.height * j + temp] = Color;
158 }
159 lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
160 }
161
LCD_Fill_Pic(struct drv_lcd_device * lcd,rt_uint16_t x,rt_uint16_t y,rt_uint16_t pic_H,rt_uint16_t pic_V,rt_uint32_t * pic)162 void LCD_Fill_Pic(struct drv_lcd_device *lcd, rt_uint16_t x, rt_uint16_t y, rt_uint16_t pic_H, rt_uint16_t pic_V, rt_uint32_t *pic)
163 {
164 rt_uint32_t *LTDC_Buf = (rt_uint32_t *)lcd->lcd_info.framebuffer;
165 rt_uint16_t i, j;
166 rt_uint32_t Xstart, k = 0;
167 Xstart = lcd->lcd_info.height * x;
168 for (i = 0; i < pic_V; i++)
169 {
170 for (j = 0; j < pic_H; j++)
171 LTDC_Buf[Xstart + i + lcd->lcd_info.height * j + y] = pic[k++];
172 }
173 }
174
DrawPixel(struct drv_lcd_device * lcd,rt_uint16_t x,rt_uint16_t y,int Color)175 void DrawPixel(struct drv_lcd_device *lcd, rt_uint16_t x, rt_uint16_t y, int Color)
176 {
177 rt_uint32_t *LTDC_Buf = (rt_uint32_t *)lcd->lcd_info.framebuffer;
178 LTDC_Buf[y + lcd->lcd_info.height * x] = Color;
179 }
180
181
182
183
drv_lcd_hw_init(void)184 int drv_lcd_hw_init(void)
185 {
186 rt_err_t result = RT_EOK;
187 struct rt_device *device = &_lcd.parent;
188
189 /* memset _lcd to zero */
190 rt_memset(&_lcd, 0x00, sizeof(_lcd));
191
192 /* init lcd_lock semaphore */
193 result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
194 if (result != RT_EOK)
195 {
196 LOG_E("init semaphore failed!\n");
197 result = -RT_ENOMEM;
198 goto __exit;
199 }
200
201 /* config LCD dev info */
202 _lcd.lcd_info.height = LCD_HEIGHT;
203 _lcd.lcd_info.width = LCD_WIDTH;
204 _lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
205 _lcd.lcd_info.pixel_format = LCD_PIXEL_FORMAT;
206
207 /* malloc memory for Triple Buffering */
208 _lcd.back_buf = (rt_uint8_t *)LTDC_Buf1;
209 _lcd.front_buf = (rt_uint8_t *)LTDC_Buf2;
210 _lcd.lcd_info.framebuffer = _lcd.back_buf;
211 if (_lcd.lcd_info.framebuffer == RT_NULL || _lcd.back_buf == RT_NULL || _lcd.front_buf == RT_NULL)
212 {
213 LOG_E("init frame buffer failed!\n");
214 result = -RT_ENOMEM;
215 goto __exit;
216 }
217
218 /* memset buff to 0xFF */
219 rt_memset(_lcd.back_buf, 0xFF, LCD_BUF_SIZE);
220 rt_memset(_lcd.front_buf, 0xFF, LCD_BUF_SIZE);
221
222 device->type = RT_Device_Class_Graphic;
223 #ifdef RT_USING_DEVICE_OPS
224 device->ops = &lcd_ops;
225 #else
226 device->init = drv_lcd_init;
227 device->control = drv_lcd_control;
228 #endif
229
230 /* register lcd device */
231 rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
232
233 /* init stm32 LTDC */
234 if (stm32_lcd_init(&_lcd) != RT_EOK)
235 {
236 result = -RT_ERROR;
237 goto __exit;
238 }
239 else
240 {
241 turn_on_lcd_backlight();
242 }
243 LOG_D("lcd register successful!");
244
245 __exit:
246 if (result != RT_EOK)
247 {
248 rt_sem_detach(&_lcd.lcd_lock);
249 }
250 return result;
251 }
252 INIT_DEVICE_EXPORT(drv_lcd_hw_init);
253
254 #ifdef DRV_DEBUG
255 #ifdef FINSH_USING_MSH
lcd_test()256 int lcd_test()
257 {
258 struct drv_lcd_device *lcd;
259 lcd = (struct drv_lcd_device *)rt_device_find("lcd");
260 if(lcd == RT_NULL)
261 {
262 LOG_E("find lcd device failed!\n");
263 return -1;
264 }
265 rt_uint32_t *LTDC_Buf = RT_NULL;
266
267 LOG_D("red");
268 /* red */
269 LTDC_Buf = (rt_uint32_t *)lcd->lcd_info.framebuffer;
270 for (int i = 0; i < LCD_BUF_SIZE / 4; i++)
271 LTDC_Buf[i] = Red;
272 lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
273 rt_thread_mdelay(1000);
274 LOG_D("green");
275 /* green */
276 LTDC_Buf = (rt_uint32_t *)lcd->lcd_info.framebuffer;
277 for (int i = 0; i < LCD_BUF_SIZE / 4; i++)
278 LTDC_Buf[i] = Green;
279 lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
280 rt_thread_mdelay(1000);
281 LOG_D("blue");
282 /* blue */
283 LTDC_Buf = (rt_uint32_t *)lcd->lcd_info.framebuffer;
284 for (int i = 0; i < LCD_BUF_SIZE / 4; i++)
285 LTDC_Buf[i] = Blue;
286 lcd->parent.control(&lcd->parent, RTGRAPHIC_CTRL_RECT_UPDATE, RT_NULL);
287
288 return 0;
289 }
290 MSH_CMD_EXPORT(lcd_test, lcd_test);
291
292
293
294
295
296 #endif /* FINSH_USING_MSH */
297 #endif /* DRV_DEBUG */
298 #endif /* BSP_USING_LCD */
299