项目场景:
将LVGL和FreeRTOS结合使用
问题描述
LVGL例程无法正常显示
原因分析:
LVGL和FreeRTOS结合主要要解决两个问题:1、lvgl的时基(用于记录lvgl运行时间)2、lv_task_handler() 如何正确调度
首先利用CUBEMX生成带FreeRTOS的代码框架。再将lvgl相关文件加入工程中,主要需要更改的是FreeRTOSConfig.h文件和 lv_conf.h
解决方案:
1、lvgl的时基:在没有操作系统时,一般可以通过SysTick_Handler()每1ms中断一次调用lv_tick_inc(1);
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
lv_tick_inc(1);
}
而CUBEMX自动生成的带FreeRTOS会将SysTick 中断、SVC 中断、PendSV 中断删掉。并且HAL库中时基CUBEMX会推荐使用其他定时器来实现否则会出现冲突。刚开始移植时我并没有修改这个时钟来源选择的是SysTick,并且在SysTick_Handler中调用lv_tick_inc(1);但是FreeRTOS任务之间无法实现正常的切换。导致FreeRTOS中的 port.c 文件中的任务调度函数无法执行,任务无法切换。
第一种方式: 为了保证lvgl和FreeRTOS不冲突,在“FreeRTOSConfig.h”中配置“configUSE_TICK_HOOK” 为 1 (可裁剪,一定要配置) 重写钩子函数,加入lv_tick_inc(1);这里是利用了FreeRTOS的时基每隔1ms就会进入这个钩子函数。如果不加无法正常显示。
void vApplicationTickHook( void )
{
/* This function will be called by each tick interrupt if
configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be
added here, but the tick hook is called from an interrupt context, so
code must not attempt to block, and only the interrupt safe FreeRTOS API
functions can be used (those that end in FromISR()). */
// 告诉lvgl已经过去1毫秒
lv_tick_inc(1);
}
这个函数放在任意位置都可以。
第二种方式: 修改lv_conf.h文件配置#define LV_TICK_CUSTOM 1。这样就不需要加lv_tick_inc(1);这段代码
/*Use a custom tick source that tells the elapsed time in milliseconds.
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "FreeRTOS.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (xTaskGetTickCount()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
2、lv_task_handler() 如何正确调度:创建一个进程调用lv_task_handler(); 注意如果用了多个进程栈的大小要合理分配如果栈的大小超过FreeRTOSConfig.h设置的大小任务会无法正常切换
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configTOTAL_HEAP_SIZE ((size_t)32768)
osThreadId_t LvHandlerTaskHandle;
const osThreadAttr_t LvHandlerTask_attributes = {
.name = "LvHandlerTask",
.stack_size = 128*24,
.priority = (osPriority_t) osPriorityHigh,
};
LvHandlerTaskHandle = osThreadNew(LvHandlerTask, NULL, &LvHandlerTask_attributes);
void LvHandlerTask(void *argument)
{
while(1)
{
lv_task_handler();
// printf("LvHandlerTask\r\n");
osDelay(5);
}
}
实现效果:
创建了两个任务,分别执行