本文由RT-Thread论坛@ppacctv 原创发布:https://club.rt-thread.org/ask/article/15d851442a2670c3.html
我的板子是这样的,MCU是STM32F407VGT6
我的TFT-LCD 是这样的,驱动是ili9486,320x480,8bit并口
组合到一起是这样的
LCD 找卖家要的驱动
第一步
第一次移植,不确定问题会在哪发生,所以
Keil + STM32CubeMX
先裸机驱动LCD,验证代码的正确性,减少问题出在LCD这边的可能性。
第二步
裸机没问题,使用RT-Thread Studio新建工程。
在RT-Thread Studio 里,双击 CubeMX Settings,打开CubeMX进行硬件配置
下面是我的配置,Timing的参数先保持CubeMX生成的默认值就好,后面可以慢慢调,调不好LCD没显示的,或者不稳定,不利于移植
时钟、串口、FSMC,设置完,File 菜单,save一下,然后右上角生成 CODE,完事关闭CubeMX。编译一下,应该没有错误。
第三步
到
https://github.com/RT-Thread/...
下载整个lvgl文件夹,复制到我们工程的applications 文件夹下;
到
https://github.com/RT-Thread/...
下载drv_lcd.c/drv_lcd.h 复制到我们工程的drivers 文件夹下;
还有我们的LCD驱动,建个ili9486文件夹,放到 drivers 文件夹下。
然后我们右键我们的工程,属性->C/C++常规->路径和符号->包含->GNU C,将我们的lvgl、ili9486、lvgl/demo 文件夹加入。
这步总之就是将以上文件(夹)加入工程并确保能够被找到,怎么加,个人随便!
第四步
编辑 drv_lcd.h
#define LCD_W 320 //LCD水平宽
#define LCD_H 480 //LCD垂直高
#define LCD_ADDR_BASE 0x60000000 //FSMC地址,命令RAM地址
#define LCD_REGSELECT_BIT 16
#define LCD_ADDR_DATA (LCD_ADDR_BASE + (1 << (LCD_REGSELECT_BIT + 2)) - 2) //数据RAM地址
#define LCD_ADDR_REG LCD_ADDR_BASE //为了方便记忆,改个名
void lcd_fill_array(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end, rt_uint16_t y_end, void *pcolor);
编辑 drv_lcd.c
保留
static struct drv_lcd_device _lcd;
以上,及
void lcd_fill_array(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end,
rt_uint16_t y_end, void *pcolor) {//……}
static rt_err_t drv_lcd_init(struct rt_device *device){//……}
struct rt_device_graphic_ops fsmc_lcd_ops = {//……}
以下的内容,其它都可以删掉,注意定义的一些结构体,后面少了再加。
static rt_err_t drv_lcd_init(struct rt_device *device) {
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
extern void MX_FSMC_Init(void);//CubeMX生成的,图方便把static去掉了
MX_FSMC_Init();
rt_thread_mdelay(50);
ili9486_Init();//驱动程序提供的初始化函数
return RT_EOK;
}
void lcd_fill_array(rt_uint16_t x_start, rt_uint16_t y_start, rt_uint16_t x_end, rt_uint16_t y_end, void *pcolor) {
rt_uint16_t *pixel = RT_NULL;
pixel = (rt_uint16_t *)pcolor;
ili9486_DrawRGBImage(x_start, y_start, x_end-x_start+1, y_end-y_start+1, pixel);
}
向给定区域填充内容,内容由 *pcolor 指向,LVGL好像就靠它绘图的。
注意,为社么要 +1 ,因为 3到5,有5-3+1个端点,分别是3,4,5号端点,LCD填充的是点。
struct rt_device_graphic_ops fsmc_lcd_ops = { RT_NULL, RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL};
直接使用RT_NULL填充,在LVGL当前我没发现有用的地方,有用到参照源文件加就好。
static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args) {
struct drv_lcd_device *lcd = LCD_DEVICE(device);
switch (cmd) {
case RTGRAPHIC_CTRL_GET_INFO: {
struct rt_device_graphic_info *info =
(struct rt_device_graphic_info *) args;
RT_ASSERT(info != RT_NULL);
//this needs to be replaced by the customer
info->pixel_format = lcd->lcd_info.pixel_format;
info->bits_per_pixel = lcd->lcd_info.bits_per_pixel;
info->width = LCD_W;//自己LCD的水平宽度
info->height = LCD_H;//自己LCD的垂直高度
}
break;
}
return RT_EOK;
}
后面没有需要改的,最后的lcd_fill,需要的话可以用来测试,但要实现LCD_Clear函数,使用驱动提供的 ili9486_FillRect 函数实现一下。
void LCD_Clear(uint16_t color) {
ili9486_FillRect(0, 0, LCD_W, LCD_H, color);
}
编辑lv_conf.h
具体意义不说了,论坛教程很多,就是注意自己LCD的色彩深度、宽高……
#define LV_COLOR_16_SWAP 0
#define LV_COLOR_DEPTH 16
#define LV_USE_PERF_MONITOR 1
#include <rtconfig.h>
#define LV_HOR_RES_MAX 320 //LCD的水平宽
#define LV_VER_RES_MAX 480 //LCD的垂直高
#define LV_USE_DEMO_RTT_MUSIC 1
#define LV_DEMO_RTT_MUSIC_AUTO_PLAY 1
#define LV_FONT_MONTSERRAT_12 1
#define LV_FONT_MONTSERRAT_16 1
编辑lv_port_disp.c
这个文件很关键,(个人看法,大佬可以打个脸)本质就是 LVGL 库提供给显示驱动的接口,要完成移植,就的实现这里面的接口。下面是我的实现。
#define MY_DISP_HOR_RES LCD_W //我显示器每行LCD_W个点
static lv_disp_draw_buf_t disp_buf_dsc_2; //可以查看移植模板
static lv_disp_drv_t disp_drv;
//注意缓存大了编译会提示RAM超限的,下面是我更具自己应用的实际取的
//每个缓存一次缓存20行,每行[MY_DISP_HOR_RES个点
lv_color_t buf_2_1[MY_DISP_HOR_RES * 20]; //定义了2块缓存
lv_color_t buf_2_2[MY_DISP_HOR_RES * 20]; //定义了2块缓存
//刷新回调函数
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
//主要就是lcd_fill_array函数的实现,在我们的drv_lcd.c 里面实现的
//画图就靠它
lcd_fill_array(area->x1, area->y1, area->x2, area->y2, color_p);
lv_disp_flush_ready(disp_drv);
}
void lv_port_disp_init(void) {
lv_disp_draw_buf_init(&disp_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10);
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LCD_W; //LCD的水平宽度
disp_drv.ver_res = LCD_H; //LCD的垂直高度
disp_drv.draw_buf = &disp_buf_dsc_2;
disp_drv.flush_cb = disp_flush; //回调函数
lv_disp_drv_register(&disp_drv);
}
lv_port_indev.h/c个人不涉及,忽略,如编译有问题,请酌情处理!
第五步
双击打开RT-Thread Setting,软件包->多媒体包->LVGL,勾选LVGL及player demo就好。
保存,编译,下载,移植完毕。
不会用编辑器,有点乱!