【摘要】
我在前面分享了两篇文章一篇是关于硬件spi驱动ST7789LCD屏,一篇是硬件I2C驱动触摸屏GT911的,本篇将结合两篇的文章,移植LVGL9.2版本。主要的重点中如何添加lvgl源码,并实现LCD屏的刷新接口,触摸接口的适配。同时在最后展示移植效果。移植主要采用gui_guider这款开源的软件来实现界面的设计。
【软件环境】
1、mdk5.41。
2、Gui_guider。
【界面设计】
1、打开Gui_Guider创建一个自定的的屏,长宽与LCD屏一至。
2、使用简单的计算器的模版,再加上一个数据时钟,设计效果如下:
3、生成C的代码后,将文件夹下的lvgl下的src复制到工程中的LVGL中
4、将src下面的所有的文件夹下的.c添加到工程中,并添加头文件目录到工程中。
5、复制gui_guder下的generated、custom两个文件夹到工程的LVGL目录下,并将generated、custom下面的.c添加到工程中,同时添加头文件目录到工程中。
6、找到lvgl源码,将exapmle/porting下面的lv_port_disp_template.h/c以及lv_port_indev_template.c/h添加到工程中,并把去掉文件的template。
7、把lv_port_disp.h/c、lv_port_indev.c的条件编译修改为if 1。
8、在lv_port_disp.c中添加lcd.h的头文件,以及hal_spi.h头文件。修改刷新函数代码如下:
static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map)
{
SPI_InitTypeDef SPI_InitStruct;
if(disp_flush_enabled) {
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
uint16_t *buf16 = (uint16_t *)px_map;
lcd_set_address(area->x1, area->y1, area->x2, area->y2);
lcd_write_ram();
LCD_CS(0);
LCD_WR(1);
// 计算需要传输的数据长度
uint32_t data_length = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * BYTE_PER_PIXEL;
// 打印数据长度
// printf("Data length: %u bytes\n", data_length);
for(uint32_t i = 0; i < data_length/2; i++) {
SPI1->TXREG = (*buf16)>>8;
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT));
SPI1->TXREG = (*buf16)&0xFF;
while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT));
buf16++;
}
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_display_flush_ready(disp_drv);
}
9、在lv_port_disp.h中添加宏定义屏的长与宽:
/*********************
* DEFINES
*********************/
#define MY_DISP_HOR_RES 240
#define MY_DISP_VER_RES 320
10、打开lv_port_indev.c/h,修改条件编译为#if 1,同时添加gt911.h到工程中
11、注释掉除touch之外的代码。在lv_port_indev_init函数中添加gt911的初始化函数,同时添加全局变量:extern Touch_Struct User_Touch;
12、添加获取触摸代码如下:
/*Initialize your touchpad*/
static void touchpad_init(void)
{
/*Your code comes here*/
GTP_Init();
}
/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_t * indev_drv, lv_indev_data_t * data)
{
static int32_t last_x = 0;
static int32_t last_y = 0;
/*Save the pressed coordinates and the state*/
if(touchpad_is_pressed()) {
touchpad_get_xy(&last_x, &last_y);
data->state = LV_INDEV_STATE_PRESSED;
}
else {
data->state = LV_INDEV_STATE_RELEASED;
}
/*Set the last pressed coordinates*/
data->point.x = last_x;
data->point.y = last_y;
}
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
/*Your code comes here*/
GTXXXX_Scanf(); // ����ɨ��
if (User_Touch.Touch_State == 0x80)
{
User_Touch.Touch_State = 0;
User_Touch.Touch_Number = 0;
return true;
}
return false;
}
/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(int32_t * x, int32_t * y)
{
uint32_t tmp;
/* 获取原始坐标 */
(*y) = User_Touch.Touch_XY[0].X_Point;
(*x) = User_Touch.Touch_XY[0].Y_Point;
//x 当前读取的范围为0-320 需要转换为0-240
(*x) = (*x) * 240 / 320;
//y 当前读取的范围为0-240 需要转换为0-320
(*y) = (*y) * 320 / 240;
}
13、修改MM32F5370.sct,需要修改ROM的长度、内存的长度、STACK以及HEAP的长度,修改后代码如下:
/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(int32_t * x, int32_t * y)
{
uint32_t tmp;
/* 获取原始坐标 */
(*y) = User_Touch.Touch_XY[0].X_Point;
(*x) = User_Touch.Touch_XY[0].Y_Point;
//x 当前读取的范围为0-320 需要转换为0-240
(*x) = (*x) * 240 / 320;
//y 当前读取的范围为0-240 需要转换为0-320
(*y) = (*y) * 320 / 240;
}
14、在main.c中添加dsip以及indev的头文件。
15、在mm32f5370_it.c中的systickHandle中添加lvgl的心跳包:
void SysTick_Handler(void)
{
if (0 != PLATFORM_DelayTick)
{
PLATFORM_DelayTick--;
}
lv_tick_inc(1);
}
16、在main中函数中添加lvgl的初始以及lvgl的界面初始化,其代码如下:
lv_ui guider_ui; // 声明外部变量
/***********************************************************************************************************************
* @brief This function is main entrance
* @note main
* @param none
* @retval none
*********************************************************************************************************************/
int main(void)
{
PLATFORM_Init();
lcd_init();
lcd_clear(BLUE);
lcd_show_string(30, 100, 200, 30, (uint8_t *)("hello world"), 24, 0);
lcd_show_string(20, 140, 200, 30, (uint8_t *)("Mini-F5375-OB"), 24, 0);
lv_init();
lv_port_disp_init();
lv_port_indev_init();
// 初始化GUI界面
setup_ui(&guider_ui); // 通常由SquareLine生成
while (1)
{
lv_timer_handler();
PLATFORM_DelayMS(2);
}
}
到此代码添加完成
【实验效果】
【总结】
通过上面的实验,MM32F5370通过SPI可以非常高效的驱动LCD,并通过LVGL来轻松实现复杂的应用。但是由于内存有限,不能申请到大的显示缓存,但是从实验上看可以稳定的跑到26Fps以上。