FreeRTOS 入门与实践 —— 实践(4)
引入:屏蔽 / 使能中断,暂停 / 恢复调度器前面的互斥量,引入过临界资源的概念,已经实现临界资源的互斥访问),要。
一,资源管理(Resource Management)
引入:屏蔽 / 使能中断,暂停 / 恢复调度器
(前面的互斥量,引入过临界资源的概念,已经实现临界资源的互斥访问),要独立地访问临界资源,有 3 种方法:
- 公平竞争,如互斥量的获得
- 屏蔽中断(中断争抢资源时)
- 禁止调度器(不进行任务切换)
1,屏蔽中断(之后要使能中断)
在 taskENTER_CRITICA()/taskEXIT_CRITICAL()之间:低优先级的中断被屏蔽了,高优先级的中断可以产生;分界点是宏设置的configMAX_SYSCALL_INTERRUPT_PRIORITY。
【注意】:
- 这部分中断 ISR 里,不允许使用 FreeRTOS 的 API 函数(任务调度依赖于中断、依赖于 API 函数,所以:这两段代码之间,不会有任务调度产生)
- 可以递归使用,内部会记录嵌套的深度
- 用屏蔽中断的方法访问临界资源很粗鲁(中断、任务调度无法正常运行),要尽可能快的执行
/* 在任务中,当前时刻中断是使能的
* 执行这句代码后,屏蔽中断*/
taskENTER_CRITICAL();
/* 访问临界资源 */
/* 重新使能中断 */
taskEXIT_CRITICAL();
void vAnInterruptServiceRoutine( void )
{
/* 用来记录当前中断是否使能 */
UBaseType_t uxSavedInterruptStatus;
/* 在 ISR 中,当前时刻中断可能是使能的,也可能是禁止的
* 所以要记录当前状态, 后面要恢复为原先的状态
* 执行这句代码后,屏蔽中断
*/
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
/* 访问临界资源 */
/* 恢复中断状态 */
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
/* 现在,当前 ISR 可以被更高优先级的中断打断了 */
}
2,暂停调度器
关中断的代价太大了,如果只是禁止别的任务竞争,暂停调度器就可以了:在这期间, 中断还是可以发生、处理。(也可递归使用)
vTaskSuspendScheduler();
/* 访问临界资源 */
xTaskResumeScheduler();
【写队列xQueueSend保证互斥操作通过先关闭中断实现,xQueueSendFromISR内部也关中断,而且有保存中断状态操作;事件组通过调度器开闭实现,任务间抢占临界资源不需要关中断】
示例:I2C 的互斥访问 (之前用 GetI2C获得互斥量,PutI2C释放互斥量 ),可改为暂停调度器 与 恢复调度器。【问题:若调度器暂停时间过长,其它任务都无法执行;用信号量、互斥量更合理】
二,调试与优化
1,调试
FreeRTOS 提供了很多调试手段:打印、断言 configASSERT、Trace、Hook 函数(回调函数)。详见手册 19章。
判断栈溢出的方法有两种:
- 当前任务被切换出去之前,它的整个运行现场都被保存在栈里,这时很可能就是它对栈的使用到达了峰值。(高效但不准确(运行过程中A函数 用了大量的栈,但之后才调度A函数))
- 在栈中填入固定值:如 0xa5,检测栈里最后 16 字节的数据,如果不是 0xa5 的话表示栈即将、或者已经被用完了。(效率不如方法 1,能捕获几乎所有的栈溢出)
2,优化
Win 中系统卡断时,可查看任务管理器找到消耗 CPU 资源多的程序。
FreeRTOS 中,也可以 查看任务使用CPU的情况、使用栈的情况,然后针对性地进行优化。即 “任务的统计”信息。
1)栈的使用情况:
在创建任务时分配了栈,可以填入固定的数值比如 0xa5,以后可以使用以下函数查看" 栈的高水位",也就是还有多少空余的栈空间(原理是:从栈底往顶逐个字节判断,值持续是 0xa5 就表明空闲):
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
2)任务运行时间统计
Tick 中断函数统计当前任务的累计运行时间不精确(有更高优先级的任务就绪时,当前任务还没运行一个完整的Tick 就被抢占了),需要比 Tick 更快的时钟来衡量任务运行时间。

代码执行流程:在任务切换时统计运行时间

- uxTaskGetSystemState:获得任务的统计信息,在一个 TaskStatus_t 结构体里
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
uint32_t * const pulTotalRunTime );
void vTaskList( signed char *pcWriteBuffer );

void vTaskGetRunTimeStats( signed char *pcWriteBuffer )

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐



所有评论(0)