正点原子学习小组
直播中

cszzlsw

9年用户 202经验值
擅长:嵌入式技术
私信 关注
[经验]

【正点原子STM32战舰V4开发板体验】第二弹,lvgl显示移植

1,接上篇:

【正点原子STM32战舰V4开发板体验】开发板使用rtthread系统体验,上篇我们通过rt-studio成功建立了基于战舰V4的开发板了,今次就要向前迈进一步了,把屏幕点亮并移植lvgl.

2.添加spi的屏幕驱动

这里使用的是ili9488屏幕驱动芯片,使用SPI来通信,分辨率是320*480,能显示挺多东西,用来做点带屏幕的应用再合适不过了,要点亮这样的屏幕,首先需要在rtt中添加SPI驱动,并启用dma以加快画面的刷新速度,我这里用的是SPI2:
image.png

3.添加ili9488驱动和spi_lcd驱动框架:

文件内容见附件

把文件放到main,c同级目录即可,如果是做工程项目,也可以放到其他地方
image.png

不出意外的话,编译能够通过,如果编译不能通过,就需要修改这个文件,把spi的注释取消掉,也就是启用spi模块:\\board\\CubeMX_Config\\Inc\\stm32f1xx_hal_conf.h
image.png

4.添加外部Sram

经过之前的步骤这里就可以实现编译通过了,但是还不能运行,因为运行会发现内存不够, 这里就需要启用外部SRAM,战舰V4用的sram总共空间是1MB,具体的信息在官方的开发手册上有介绍:

在rtt上启动外部sram也比较简单,首先打开软件包:
image.png

然后同时还要开启large heap模式:
image.png

在工程的链接文件还要添加外部存储,数据的来源可在日志中看到:
image.png

这样系统就能自动识别到外部的sram并自动初始化了.相关日志如下:
image.png

5.lcd屏幕的简单

然后下载固件之后,在命令行终端输入help可以看到有ili9488_test这个指令.
image.png

把屏幕和开发板正确连线之后,就可以进行测试了,

输入这个指令之后,如果顺利的话就会在屏幕上打印出测试图形,如果未能打出测试图形,而是显示spi传输失败等信息的话,就需要添加spi的msp初始化代码:

//\board\CubeMX_Config\Src\stm32f1xx_hal_msp.c

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(spiHandle->Instance==SPI2)
    {
        /* SPI2 clock enable */
        __HAL_RCC_SPI2_CLK_ENABLE();

        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**SPI2 GPIO Configuration
        PB13     ------> SPI2_SCK
        PB14     ------> SPI2_MISO
        PB15     ------> SPI2_MOSI
        */
        GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);


    }
}

6.添加lvgl软件包

要添加lvgl软件包,打开RT-Thread Setting文件, 软件包的对应位置找到lvgl,版本不要选择latest,选8.3.x的就行,如果不想用rtt开源团队处理过的lvgl包,也可以到github上下载当前最新版本:

https://github.com/lvgl/lvgl

在添加软件包的同时可以把LVGL music player demo选中,这样会同时download一份音乐播放器的demo,可以测试lvgl是否可以正常显示:
image.png

添加完软件包之后Ctrl+S保存,经过一段时间的缓冲,会提示lvgl代码下载成功,

然后会看到在pacakge里出现lvgl和music demo软件包:
image.png

然后可以尝试编译一次,会提示错误,错误内容是lv_port_disp_init等函数没有定义:
image.png

这里就是移植lvgl的关键了,需要我们把这些文件添加到main,c或者其他某个参与编译的文件里,这里先编写空的函数让编译通过:
image.png

然后编译的同时可能会出现一些警告导致编译无法进行,此时需要将
LVGL-v8.3.1\\\\lv_conf_template.h拷贝到src文件夹内并重命名为lv_conf.h,并把代码里开头的#if 0改为#if 1让代码参与编译:
image.png

此时再次编译,会有些重复定义的内容,这是由于有些内容已经在\\\\LVGL-v8.3.1\\\\env_support\\\\rt-thread\\\\lv_rt_thread_conf.h文件里定义了,这里把重复的地方在lv_conf.h中注释掉即可:

到这里一般就能够编译通过了.

7.编写lv_port_disp_init函数

在lvgl原生的软件包内有这个函数的解释,主要是要理解到这个函数里面具体要做的事情,具体文件在这里:

examples\porting\lv_port_disp_template.c,注意这个文件需要用原生的lvgl代码才能看到

根据这个文件的提示写出我们自己的lv_port_disp_init和disp_flush函数:

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    rt_kprintf(">> %s:%d %d %d %d %d full=%u %p \\\\n",__func__,__LINE__,area->x1, area->y1, area->x2, area->y2,color_p->full,color_p);
    if(disp_flush_enabled ) {
        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

        lcd_fill_array(area->x1, area->y1, area->x2, area->y2,(void *) color_p);

//        int32_t x;
//        int32_t y;
//        for(y = area->y1; y <= area->y2; y++) {
//            for(x = area->x1; x <= area->x2; x++) {
//                /*Put a pixel to the display. For example:*/
//                /*put_px(x, y, *color_p)*/
//                color_p++;
//            }
//        }
    }
    rt_kprintf(">> %s:%d over \\\\n",__func__,__LINE__);
    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}


void lv_port_disp_init(void)
{
    rt_thread_mdelay(5000);
    static lv_disp_draw_buf_t draw_buf_dsc_1;
    lv_disp_draw_buf_init(&draw_buf_dsc_1,lcd_get_lcd_buffer1() , NULL, LCD_BUF_SIZE);

    static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = LCD_HEIGHT;//LCD_WIDTH;
    disp_drv.ver_res = LCD_HEIGHT;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;

    /*Set a display buffer*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
    lcd_clear(WHITE);
}

这里直接将春li988驱动文件里生成的buffer直接赋值到disp_drv.draw_buf,同时在disp_flush函数里直接将要显示的内容通过lcd_fill_array函数输入到lcd中去.

8.编写lv_user_gui_init函数

这里直接贴出函数内容,使用的是自带的那个music demo的代码:

void lv_user_gui_init(void)
{
    extern void lv_demo_music(void);
       lv_demo_music();
}

添加这个函数之后,代码编译会失败,因为这个demo案例所占的代码空间太大了,需要进行精简,具体的精简策略可以是把所有涉及图片的代码都屏蔽掉,或者像我一样直接把大部分的uI都取消,只留一小部分的代码用来验证lvgl是否可以正常运行:
92a7ceb6681b9cc5d627d4c2c32356d.jpg

经过以上步骤之后,我们的程序就能正常运行并显示画面了,到此,lvgl移植就成功了,接下来就是抛弃官方这个占空间的音乐播放器demo,去绘制自己的播放器界面并接入触摸驱动了,一起期待吧.

更多回帖

发帖
×
20
完善资料,
赚取积分