LVGL和FreeRTOS可视化跟踪

张开发
2026/6/11 9:27:58 15 分钟阅读
LVGL和FreeRTOS可视化跟踪
一、LVGL用量跟踪lv_mem_monitor_t mon; lv_mem_monitor(mon); printf(\r\n LVGL Memory Info \r\n); printf(Total size: %d bytes (%.1f KB)\r\n, mon.total_size, mon.total_size / 1024.0); printf(Free size: %d bytes (%.1f KB)\r\n, mon.free_size, mon.free_size / 1024.0); printf(Used size: %d bytes (%.1f KB)\r\n, mon.total_size - mon.free_size, (mon.total_size - mon.free_size) / 1024.0); printf(Max used (peak): %d bytes (%.1f KB)\r\n, mon.max_used, mon.max_used / 1024.0); printf(Used percent: %d%%\r\n, mon.used_pct); printf(Free blocks: %d\r\n, mon.free_cnt); printf(Used blocks: %d\r\n, mon.used_cnt); printf(Biggest free block:%d bytes\r\n, mon.free_biggest_size); printf(Fragmentation: %d%%\r\n, mon.frag_pct); printf(\r\n); LVGL Memory Info Total size: 20480 bytes (20.0 KB) Free size: 9764 bytes (9.5 KB) Used size: 10716 bytes (10.5 KB) Max used (peak): 11940 bytes (11.7 KB) Used percent: 53% Free blocks: 7 Used blocks: 273 Biggest free block:9484 bytes Fragmentation: 3% 一、字段含义详解字段类型含义说明mon.total_sizeuint32_t总内存大小LVGL 动态内存池的总大小即LV_MEM_SIZE配置的值mon.free_sizeuint32_t当前空闲内存当前未使用的内存字节数mon.free_biggest_sizeuint32_t最大空闲块大小内存池中最大的连续空闲块碎片化程度指标mon.free_cntuint32_t空闲块数量内存池中被分割成多少块空闲区域越多说明碎片越严重mon.used_cntuint32_t已使用块数量当前已分配的内存块数量mon.max_useduint32_t历史最大使用量从启动到现在的峰值使用量字节mon.used_pctuint8_t使用百分比当前使用量占总量的百分比0-100%mon.frag_pctuint8_t碎片化百分比内存碎片化程度0-100%越高越严重根据这些信息判断内存是否够用指标健康状态需要关注危险free_size 20% 总量10-20% 10%frag_pct 30%30-50% 50%free_biggest_size 预期单次分配大小- 预期单次分配大小LVGL 内存分析当前配置项目值状态LV_MEM_SIZE20,480 字节 (20 KB)✅当前使用10,716 字节 (10.5 KB)✅峰值使用11,940 字节 (11.7 KB)✅空闲内存9,764 字节 (9.5 KB)✅ 充裕碎片化3%✅ 非常健康二、FreeFTOS任务跟踪FREERTOS_CONFIG_H //任务跟踪 extern volatile uint32_t CPU_RunTime; #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime 0ul) #define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 1//启用运行时间统计功能 #define configUSE_TRACE_FACILITY 1//启用可视化跟踪调试 #define configUSE_STATS_FORMATTING_FUNCTIONS 1//开启后才能使用vTaskList--------------------------------------------- 任务名 任务状态 优先级 剩余栈 任务序号 Tmr Svc X 31 172 5 IDLE R 0 118 4 led2 B 2 42 2 led1 B 1 106 1 Lvgl B 5 650 3 ---------------------------------------------一、整体概念FreeRTOS 的任务运行时间统计功能核心思想是用一个高精度计数器来记录时间每个任务开始运行时记录开始值任务切换时计算差值累加到该任务的运行时间中。二、关键宏定义的含义cextern volatile uint32_t CPU_RunTime; // 全局时间计数器 // 1. 初始化函数重置计数器 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime 0ul) // 2. 获取当前时间返回当前计数值 #define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime这两个宏的作用宏调用时机作用portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()系统启动时vTaskStartScheduler()内调用一次初始化时间计数器portGET_RUN_TIME_COUNTER_VALUE()每次任务切换时调用获取当前时间值用于计算任务运行时长三、你的实现流程1. 定时器5提供时间基准20kHzc// TIM5 中断服务函数20kHz 50us 一次 void TIM5_IRQHandler(void) { if (TIM_GetITStatus(TIM5, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM5, TIM_IT_Update); CPU_RunTime; // 每 50us 增加 1 } }时间单位20kHz 中断频率 → 每次中断间隔 1 / 20000 50 微秒CPU_RunTime每增加 1代表过去了 50 微秒2. 系统启动时初始化c// FreeRTOS 内核启动时vTaskStartScheduler() 内部 // 会调用 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() // 相当于执行 CPU_RunTime 0; // 从 0 开始计数3. 任务切换时计算运行时间FreeRTOS 内核在任务切换时会执行以下逻辑简化版c// 当前任务要切出了计算它运行了多久 void vTaskSwitchContext(void) { // 1. 获取当前时间 uint32_t current_time portGET_RUN_TIME_COUNTER_VALUE(); // CPU_RunTime // 2. 计算当前任务的运行时间增量 uint32_t delta current_time - last_time; // last_time 是上次切换时的时间 // 3. 累加到当前任务的运行时间统计中 pxCurrentTCB-ulRunTimeCounter delta; // 4. 记录当前时间供下次计算用 last_time current_time; // 5. 切换到下一个任务... }四、数据流向图textTIM5 中断 (20kHz) ↓ CPU_RunTime (每 50us 1) ↓ [时间计数器] ↓ ┌────────────────┼────────────────┐ ↓ ↓ ↓ 任务切换时 任务切换时 任务切换时 ↓ ↓ ↓ 计算 Task1 计算 Task2 计算 Task3 运行时间 运行时间 运行时间 ↓ ↓ ↓ Task1.counter Task2.counter Task3.counter 增加 delta 增加 delta 增加 delta五、最终输出vTaskGetRunTimeStats()当你调用vTaskGetRunTimeStats(info_buffer)时会输出类似textTask Name Abs Time % Time -------------- ---------- ------- Idle Task 12345678 45% Task_LED 8765432 32% Task_ADC 6543210 23%计算公式text某任务的运行时间 该任务的 ulRunTimeCounter × 时间单位 总运行时间 所有任务 ulRunTimeCounter 之和 CPU 使用率 (某任务运行时间 / 总运行时间) × 100%六、配置含义方案1使用vTaskList()查看任务状态不需要运行时间统计如果你只需要查看任务状态任务名、状态、优先级、堆栈剩余不需要 CPU 运行时间统计c/* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 0 // 改为 0 #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 // 改为 1vTaskList 需要此时可以使用vTaskList()✅ 可用方案2使用vTaskGetRunTimeStats()查看 CPU 使用率需要运行时间统计如果你需要查看每个任务的 CPU 使用率c/* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 1 #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 // 改为 1此时可以使用vTaskList()✅ 可用vTaskGetRunTimeStats()✅ 可用方案3只统计运行时间不输出格式化信息不常用c#define configGENERATE_RUN_TIME_STATS 1 #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 0这种情况下运行时间统计功能已启用但vTaskGetRunTimeStats()函数不存在需要自己实现统计信息的输出一般不推荐这样用七、软件定时器时机uint8_t CPU_RunInfo[400] {0}; void vTimerCallback( TimerHandle_t xTimer ) { //回调函数内部尽量不要使用延时 阻塞性质的操作 memset(CPU_RunInfo,0,400); //信息缓冲区清零 vTaskList((char *)CPU_RunInfo); //获取任务运行时间信息 printf(---------------------------------------------\r\n); printf(任务名 任务状态 优先级 剩余栈 任务序号\r\n); printf(%s, CPU_RunInfo); printf(---------------------------------------------\r\n); } //任务跟踪 timer1 xTimerCreate(Timer1,1000,pdTRUE,(void*)0,vTimerCallback); // 启动定时器 if(timer1 ! NULL) { xTimerStart(timer1, 1000); // 最多等待 1 秒 }一、核心概念定时器周期 采样间隔采样间隔决定了你能看到系统行为的精细程度和响应速度。二、两个关键影响1. 时间分辨率周期越短→ 采样越密集 → 能看到更细微的状态变化周期越长→ 采样越稀疏 → 可能错过中间状态2. 响应延迟周期越短→ 问题被发现得越快周期越长→ 问题暴露得越晚三、取舍关系方向优点代价周期短细节丰富、响应快CPU占用高、输出量大周期长资源占用低信息粗糙、响应慢

更多文章