te;
initStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
initStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
initStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
initStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
initStructure.DMA_Priority = DMA_Priority_High;
initStructure.DMA_Mode = DMA_Mode_Normal;
DMA_Init(DMA1_Channel3, &initStructure);
// Start transfer
DMA_Cmd(DMA1_Channel3, ENABLE);
while (!DMA_GetFlagStatus(DMA1_FLAG_TC3));
DMA_ClearFlag(DMA1_FLAG_TC3);
DMA_Cmd(DMA1_Channel3, DISABLE);
ST7735_CS_HIGH;
// Indicate you are ready with the flushing
lv_disp_flush_ready(disp);
}
3. 修改色彩字节顺序
上面修改完成后, 再次运行LVGL示例, 会发现颜色不正确, 这是因为在DMA传输中, 将一个 16bit 强转为两个 8bit 了, ST7735收到的两个字节的顺序有变化, 需要编辑 lv_conf.h, 将LV_COLOR_16_SWAP
设为1
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 1
源代码
以上LVGL DMA 示例的完整源代码已经提交到 GitHub: https://github.com/IOsetting/air32f103-template/tree/master/Examples/NonFreeRTOS/SPI/ST7735_LVGL_DMA
集成到 FreeRTOS
进一步, 在 FreeRTOS 中运行 DMA 传输的 LVGL. 在 FreeRTOS 中 LVGL 的初始化是一样的, 有变化的是初始化的时间点, 还有延时函数的修改
1. 将初始化从 main() 移入任务handler
新建lvglTaskHandler()
用于处理LVGL初始化, 缓存初始化和执行benchmark, 并用固定间隔调用lv_timer_handler()
static void lvglTaskHandler(void *pvParameters)
{
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xPeriod = pdMS_TO_TICKS(10);
(void)(pvParameters); // Suppress "unused parameter" warning
ST7735_Init();
lv_init();
// Initialize the display buffer.
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, ST7735_WIDTH * ST7735_HEIGHT / 10);
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
disp_drv.draw_buf = &draw_buf; /*Assign the buffer to the display*/
disp_drv.hor_res = ST7735_WIDTH; /*Set the horizontal resolution of the display*/
disp_drv.ver_res = ST7735_HEIGHT; /*Set the vertical resolution of the display*/
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
lv_demo_benchmark();
while (1)
{
lv_timer_handler();
vTaskDelayUntil(&xLastWakeTime, xPeriod);
}
}
在 main() 中创建任务, 栈深度1024, 需要 4KByte 内存
xTaskCreate(
lvglTaskHandler, // Task function point
"LVGL Task", // Task name
1024, // Stack size, each take 4 bytes(32bit)
NULL, // Parameters
LVGL_TASK_PRORITY, // Priority
NULL); // Task handler
2. 修改延时函数
更新图像的方法不变, 但是需要修改 ST7735 的延时函数, 修改 st7735.c, 引入FreeRTOS.h
, 将Delay_Ms(ms);
替换为 vTaskDelay(ms);
3. 中断设置
在 FreeRTOSConfig.h 中, 设置系统最高的, 可以安全使用FreeRTOS方法的中断优先级为1
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
因为 AIR32F103 的中断为 3 bit, 可用的优先级为 0 到 7, 这样对于优先级为 0 的中断是不受FreeRTOS控制的, 小于等于 1 的是受FreeRTOS控制的, 可以在中断处理中调用 FreeRTOS 的方法.
将TIM3的中断优先级设置为2
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
4. 裁剪 LVGL
因为集成FreeRTOS, 加上运行 Benchmark, 256KB 的 Flash 容量就捉襟见肘了, 默认配置下编译出来会有300多KB, 需要进行压缩
首先确认编译参数已经优化, rules.mk 中, 优化项改为-O3
或-Os
# c flags
OPT ?= -O3
编辑 lv_conf.h 关闭一切不必要的组件, 使用尽可能小的字体(可以用10像素字体), 具体的改动可以参考示例代码.
源代码
以上LVGL+FreeRTO 示例的源代码已经提交到 GitHu