1、介绍
上次我们完成了在Windows上移植LVGL到一个LCD工程当中,感兴趣的小伙伴可以到博主的主页当中去自行查找即可,然后接下来,我们进入到今天的正题,实现LInux操作系统的LVGL移植的操作过程!
2、移植
2.1 需要一个带有LCD代码的工程
下载源码:
LVGL官网:LVGL - Light and Versatile Embedded Graphics Library
LVGL代码库地址(Simulator、Source、Examples、Esp32、MicroPython):https://github.com/lvgl
LVGL源码下载地址:https://github.com/lvgl/lvgl
拿到之后目录分支:
2.2 在自己工程目录下新建LVGL文件
在源码目录下复制:
复制后:
添加文件到工程:
工程目录新建2个分组:
Prot:
LVGLSRC:
还要添加CPU支持文件:
进去themes添加:
添加完成后要添加其他路径:
添加完编译报错:
.\Objects\NewProject.axf: Error: L6218E: Undefined symbol __aeabi_assert (referred from lv_tlsf.o).
解决方法:取消微库
然后进行编译:
2.3 修改底层驱动
GUI ---跟屏幕的关系
打开驱动文件的条件编译 1 使能
选择显示方式:
有些单片机内存小的要用方式1
想要显示更新快那么选择2 DMA刷新 ------用这个屏幕是SPI屏 SPI使用DMA搬运显示提高速度 内存大---1M
这时候会发现方式二的东西没有定义许哟自己定义数组:
添加LCD头文件;
添加一个全局变量static lv_disp_drv_t *disp_drv_p;
此时我们定义的数组报错跳到这个头文件:打开编译
修改屏幕大小:
修改后:
复制使用DMA显示代码:
/********************************************************************************************************* * 函 数 名 : DisPlay_SPI_DMA_Init * 功能说明 : SPI3 DMA1初始化 * 形 参 : 无 * 返 回 值 : 无 * 备 注 : DMA1_Stream7搬运显示数据到SPI3的DR寄存器 *********************************************************************************************************/ static void DisPlay_SPI_DMA_Init() { DMA_InitTypeDef DMA_InitStructure = {0}; NVIC_InitTypeDef NVIC_InitStruct = {0}; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //DMA1时钟使能 DMA_DeInit(DMA1_Stream7); while(DMA_GetCmdStatus(DMA1_Stream7) != DISABLE) {} //等待DMA可配置 /* 配置 DMA Stream */ DMA_InitStructure.DMA_Channel = DMA_Channel_0; //通道选择 DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&SPI3->DR; //DMA外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)buf_2_1; //DMA 存储器0地址 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //存储器到外设模式 DMA_InitStructure.DMA_BufferSize = sizeof(buf_2_2); //数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度:8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用fifo DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //fifo全容量 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输 DMA_Init(DMA1_Stream7, &DMA_InitStructure); //初始化DMA Stream SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE); // SPI3使能DMA发送 NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream7_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&NVIC_InitStruct); DMA_ITConfig(DMA1_Stream7, DMA_IT_TC, ENABLE); DMA_Cmd(DMA1_Stream7, DISABLE); } /********************************************************************************************************* * 函 数 名 : DisPlay_SPI_DMA_Enable * 功能说明 : 配置DMA并启动一次传输 * 形 参 : buf:需要搬运的数据的指针;size:搬运的数据量 * 返 回 值 : 无 * 备 注 : 无 *********************************************************************************************************/ void DisPlay_SPI_DMA_Enable(void *buf, unsigned int size) { DMA1_Stream7->CR &= ~(0x01); while((DMA1_Stream7->CR&0X1)){} DMA1_Stream7->M0AR = (unsigned int)buf; DMA1_Stream7->NDTR = size; DMA1_Stream7->CR |= (0x01); } /********************************************************************************************************* * 函 数 名 : DMA1_Stream7_IRQHandler * 功能说明 : DMA1_Stream7发送完成中断 * 形 参 : 无 * 返 回 值 : 无 * 备 注 : 无 *********************************************************************************************************/ void DMA1_Stream7_IRQHandler(void) { if(DMA_GetITStatus(DMA1_Stream7, DMA_IT_TCIF7) != RESET) //if(DMA1->HISR & (1<<27)) { DMA_ClearITPendingBit(DMA1_Stream7, DMA_IT_TCIF7); //DMA1->HIFCR |= (1<<27); LCD_CS = 1; SPI3->DR; lv_disp_flush_ready(disp_drv_p); /* tell lvgl that flushing is done */ } }
把DMA初始化放到disp_init初始化当中:
修改底层显示:
/* Flush the content of the internal buffer the specific area on the display * You can use DMA or any hardware acceleration to do this operation in the background but * 'lv_disp_flush_ready()' has to be called when finished. */ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ // 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++; // } // } unsigned int size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2; disp_drv_p = disp_drv; LCD_Address_Set(area->x1, area->y1, area->x2, area->y2+1); LCD_CS = 0; DisPlay_SPI_DMA_Enable(color_p, size); /*不使用DMA的显示方法*/ // LCD_Color_Fill(area->x1, area->y1, area->x2-area->x1, area->y2-area->y1+1, (unsigned short *)color_p); /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ // lv_disp_flush_ready(disp_drv); }
2.4 心跳
初始化:
要使用图形库,必须对其进行初始化并设置所需的组件。初始化的顺序:
1、叫lv_init();
2、初始化驱动程序;
3、在LVGL中注册显示和输入设备驱动程序。详细了解显示和输入设备注册;
4、在终端中每隔一毫秒调试一次,向LVGL报告经过的时间。
5、每隔几毫秒调用一次,以处理与LVGL相关的任务。
使用定时器:
现在的LCD乱码的:
修改以下堆栈大小:否则代码一大直接崩溃
打开配置文件:
3、对象
LVGL使用的编程思想就是分类,按键是一个类,图片(按键模块)