(一)Littlevgl
基于MIT协议的LittleVGL可以自由地应用与各种DIY、商业场合,不需要担心版权问题,其风格相比与更加友好圆滑。
此外,LittleVGL大概是我目前用过最容易移植的MCU UI组件了,stm32F412-discovery探索板我在三四年前就入手了,本意是做些小型UI开发,结果回来移植了半天的stemwin也没有成功,遂积灰,之前成功地在NXP的LPC54628上跑通了FreeRTOS+LittleVGL,因此这次想用freertos裸机跑一次。
stm32f412-discovery官方开发板:驱动芯片ft6x06+st7789h2,屏幕分辨率240x240,MCU屏接口引脚D0-D15,电容触摸屏
(二)资料
源码: github(由于M国对开源糟糕的态度,暂时无法直接登上去):https://github.com/lvgl/lvgl
gitee(我看了下跟github进度是一样的):https://gitee.com/mirrors/lvgl?_from=gitee_search
WIKI(里面有API手册下载地址):https://docs.lvgl.io/v7/en/html/
手册下载地址:https://docs.lvgl.io/v7/en/html/_downloads/39cea4971f327964c804e4e6bc96bfb4/LVGL.pdf
(三)移植显示
1-使用cubemxide生成stm32f412-discovery例程
2-从GITEE上克隆源码下来,把SRC下面的文件放到middleware/littlevgl下面,加入头文件路径:
${workspace_loc:/${ProjName}/Middlewares/littlevgl
切记,只可以定位到littlevgl文件夹,若再定义到内部,会出现大量的未定义error。
另外注意,littlevgl文件夹内部、同级各有一个lvgl.h文件,都不可或缺。
3-在Core/SRC下面创建littlevlg_support的头文件和源文件,再加入lv_conf.h和lv_ex_conf.h
4-support_support.c文件代码如下:
用于显示的驱动函数:
void lv_port_disp_init(void)
{
BSP_LCD_Init();
BSP_LCD_Clear(LCD_COLOR_WHITE);
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
static lv_disp_buf_t disp_buf_2;
static lv_color_t buf2_1[LV_HOR_RES_MAX * 240];
static lv_color_t buf2_2[LV_HOR_RES_MAX * 240];
lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 240);
disp_drv.buffer = &disp_buf_2;
disp_drv.hor_res = LCD_WIDTH;
disp_drv.ver_res = LCD_HEIGHT;
disp_drv.flush_cb = DEMO_FlushDisplay;
lv_disp_drv_register(&disp_drv);
}
DEMO_FlushDisplay驱动ST7789H2:
typedef struct
{
__IO uint16_t REG;
__IO uint16_t RAM;
}LCD_CONTROLLER_TypeDef;
#define FMC_BANK1_BASE ((uint32_t)(0x60000000 | 0x00000000))
#define FMC_BANK1 ((LCD_CONTROLLER_TypeDef *) FMC_BANK1_BASE)
static void DEMO_FlushDisplay(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
uint16_t Xpos = area->x1;
uint16_t Ypos = area->y1;
uint16_t Xsize = (area->x2-area->x1)+1;
uint16_t Ysize = (area->y2-area->y1)+1;
ST7789H2_SetDisplayWindow(Xpos, Ypos, Xsize, Ysize);
uint32_t posY;
uint32_t nb_line = 0;
for (posY = Ypos; posY < (Ypos + Ysize); posY ++)
{
ST7789H2_SetCursor(Xpos, posY);
ST7789H2_WriteReg(ST7789H2_WRITE_RAM, (uint8_t*)NULL, 0);
uint32_t i = 0;
uint32_t posX;
uint16_t *rgb565 = (uint16_t*)color_p + nb_line * (Xsize);
for (posX = Xpos; posX < (Xsize + Xpos); posX++)
{
if (posX != (Xsize + Xpos))
{
FMC_BANK1->RAM = (uint16_t)rgb565[i];
__DSB();
}
i++;
}
nb_line++;
}
ST7789H2_SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize());
lv_disp_flush_ready(disp_drv);
}
其中有一行值得注意,不知道出于何种原因,littlevgl给过来的area变量存储的size总是小一码的,导致右下边缘各有一条一个像素的白边,并且像素依次退了一格,画面扭曲。因此需要额外加一个像素:
uint16_t Xsize = (area->x2-area->x1)+1;
uint16_t Ysize = (area->y2-area->y1)+1;
:
(四)移植触摸
1-触摸初始化函数:
void lv_port_indev_init(void)
{
lv_indev_drv_t indev_drv;
BSP_TS_InitEx(240, 240, TS_ORIENTATION_PORTRAIT);
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = DEMO_ReadTouch;
lv_indev_drv_register(&indev_drv);
}
2-驱动FT6X06芯片读取触摸情况的接口函数:
static bool DEMO_ReadTouch(lv_indev_drv_t * indev_drv, lv_indev_data_t *data)
{
static uint16_t x,y;
__IO TS_StateTypeDef ts;
BSP_TS_GetState((TS_StateTypeDef *)&ts);
if((ts.touchX[0] >= BSP_LCD_GetXSize()) ||(ts.touchY[0] >= BSP_LCD_GetYSize()) )
{
ts.touchX[0] = 0;
ts.touchY[0] = 0;
}
x = ts.touchX[0];
y = ts.touchY[0];
y=240-y;
data->state = LV_INDEV_STATE_REL;
if(0!=ts.touchDetected)
{
data->state = LV_INDEV_STATE_PR;
}
data->point.x = y;
data->point.y = x;
return false;
}
3-
这里有个问题,移植的时候触摸一直没有反应,经过排查是触摸芯片没有通讯上,后来发现原来是默认工程有个针对FT6X06的复位引脚被默认初始化并拉低
解决见:stm32f412-discovery探索板-ft6x06驱动问题
(五)工程
工程