【正点原子STM32战舰V4开发板体验】开发板使用rtthread系统体验,上篇我们通过rt-studio成功建立了基于战舰V4的开发板了,今次就要向前迈进一步了,把屏幕点亮并移植lvgl.
这里使用的是ili9488屏幕驱动芯片,使用SPI来通信,分辨率是320*480,能显示挺多东西,用来做点带屏幕的应用再合适不过了,要点亮这样的屏幕,首先需要在rtt中添加SPI驱动,并启用dma以加快画面的刷新速度,我这里用的是SPI2:
文件内容见附件
把文件放到main,c同级目录即可,如果是做工程项目,也可以放到其他地方
不出意外的话,编译能够通过,如果编译不能通过,就需要修改这个文件,把spi的注释取消掉,也就是启用spi模块:\\board\\CubeMX_Config\\Inc\\stm32f1xx_hal_conf.h
经过之前的步骤这里就可以实现编译通过了,但是还不能运行,因为运行会发现内存不够, 这里就需要启用外部SRAM,战舰V4用的sram总共空间是1MB,具体的信息在官方的开发手册上有介绍:
在rtt上启动外部sram也比较简单,首先打开软件包:
然后同时还要开启large heap模式:
在工程的链接文件还要添加外部存储,数据的来源可在日志中看到:
这样系统就能自动识别到外部的sram并自动初始化了.相关日志如下:
然后下载固件之后,在命令行终端输入help可以看到有ili9488_test
这个指令.
把屏幕和开发板正确连线之后,就可以进行测试了,
输入这个指令之后,如果顺利的话就会在屏幕上打印出测试图形,如果未能打出测试图形,而是显示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);
}
}
要添加lvgl软件包,打开RT-Thread Setting文件, 软件包的对应位置找到lvgl,版本不要选择latest,选8.3.x的就行,如果不想用rtt开源团队处理过的lvgl包,也可以到github上下载当前最新版本:
https://github.com/lvgl/lvgl
在添加软件包的同时可以把LVGL music player demo选中,这样会同时download一份音乐播放器的demo,可以测试lvgl是否可以正常显示:
添加完软件包之后Ctrl+S保存,经过一段时间的缓冲,会提示lvgl代码下载成功,
然后会看到在pacakge里出现lvgl和music demo软件包:
然后可以尝试编译一次,会提示错误,错误内容是lv_port_disp_init
等函数没有定义:
这里就是移植lvgl的关键了,需要我们把这些文件添加到main,c或者其他某个参与编译的文件里,这里先编写空的函数让编译通过:
然后编译的同时可能会出现一些警告导致编译无法进行,此时需要将LVGL-v8.3.1\\\\lv_conf_template.h
拷贝到src
文件夹内并重命名为lv_conf.h
,并把代码里开头的#if 0
改为#if 1
让代码参与编译:
此时再次编译,会有些重复定义的内容,这是由于有些内容已经在\\\\LVGL-v8.3.1\\\\env_support\\\\rt-thread\\\\lv_rt_thread_conf.h
文件里定义了,这里把重复的地方在lv_conf.h中注释掉即可:
到这里一般就能够编译通过了.
在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中去.
这里直接贴出函数内容,使用的是自带的那个music demo的代码:
void lv_user_gui_init(void)
{
extern void lv_demo_music(void);
lv_demo_music();
}
添加这个函数之后,代码编译会失败,因为这个demo案例所占的代码空间太大了,需要进行精简,具体的精简策略可以是把所有涉及图片的代码都屏蔽掉,或者像我一样直接把大部分的uI都取消,只留一小部分的代码用来验证lvgl是否可以正常运行:
经过以上步骤之后,我们的程序就能正常运行并显示画面了,到此,lvgl移植就成功了,接下来就是抛弃官方这个占空间的音乐播放器demo,去绘制自己的播放器界面并接入触摸驱动了,一起期待吧.
更多回帖