盼盼_dRglQm · 1 天前

【Mini-F5375-OB开发板评测】移植LVGL

【摘要】
我在前面分享了两篇文章一篇是关于硬件spi驱动ST7789LCD屏,一篇是硬件I2C驱动触摸屏GT911的,本篇将结合两篇的文章,移植LVGL9.2版本。主要的重点中如何添加lvgl源码,并实现LCD屏的刷新接口,触摸接口的适配。同时在最后展示移植效果。移植主要采用gui_guider这款开源的软件来实现界面的设计。
【软件环境】
1、mdk5.41。
2、Gui_guider。
【界面设计】
1、打开Gui_Guider创建一个自定的的屏,长宽与LCD屏一至。
2、使用简单的计算器的模版,再加上一个数据时钟,设计效果如下:
image.png
3、生成C的代码后,将文件夹下的lvgl下的src复制到工程中的LVGL中
image.png
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。

image.png
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;
image.png
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);
    }
}

到此代码添加完成
【实验效果】
3aa223f985452ee6924db8158a69cb4.jpglvgl.gif
【总结】
通过上面的实验,MM32F5370通过SPI可以非常高效的驱动LCD,并通过LVGL来轻松实现复杂的应用。但是由于内存有限,不能申请到大的显示缓存,但是从实验上看可以稳定的跑到26Fps以上。

推荐阅读
关注数
0
文章数
18
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息