FreeRTOS
2021-04-13 13:07:04 0 举报
AI智能生成
FreeRTOS 自学笔记
作者其他创作
大纲/内容
FreeRTOS
任务的状态
运行态
非运行态
阻塞状态
概述:一个任务正在等待某个事件
等待的事件的类型
1.定时事件-延迟事件 或 到了绝对绝对的时间点
2.同步事件-源于其他任务或中断的事件,比如事件在等待队列中有数据的到来
挂起状态
概述:对任务调度器而言不可见
进入该状态函数-vTaskSuspend()
唤醒该状态函数-vTaskResume OR vTaskResumeFromISR()
就绪状态
概述:非运行态中,即没有阻塞 也 没有挂起,能够被运行但还没运行
中断管理
延迟中断处理
采用二值信号量
二值信号量是任务与任务间、任务与中断间同步的重要手段
二值信号量发生在特定的中断中,用于解除阻塞的任务
计数信号量
事件计数
在这种用法中,每次事件发生时,中断服务例程都会“给出(Give)”信号量——信号量在每次被给出时其计数值加 1。延迟处理任务每处理一个任务都会”获取(Take)”一次信号量——信号量在每次被获取时其计数值减 1。信号量的计数值其实就是已发生事件的数目与已处理事件的数目之间的差值
资源管理
在这种用法中,信号量的计数值用于表示可用资源的数目。一个任务要获取资源的控制权,其必须先获得信号量——使信号量的计数值减 1。当计数值减至 0,则表示没有可用资源。当任务利用资源完成工作后,将给出(归还)信号量——使信号量的计数值加 1。
在中断服务例程中使用队列
信号量
用于事件通信
队列
即可:事件通信
又可:传递数据
临界区
概念:基本临界区是指宏 taskENTER_CRITICAL()与 taskEXIT_CRITICAL()之间的代码区间
实现1:简单的关闭全局中断
优点:临界区嵌套是安全的,因为内核有维护一个嵌套深度计数。临界区只会在嵌套深度为 0 时才会真正退出——即在为每个之前调用的 taskENTER_CRITICAL()都配套调用了 taskEXIT_CRITICAL()之后。
缺点:临界区必须只具有很短的时间,否则会反过来影响中断响应时间
实现2:临界区时间较长,挂起任务调度器
互斥信号量
优先级反转
这就会导致一个高优先级任务在等待一个低优先级任务,而低优先级任务却无法执行!
优先级继承
优先级继承暂时地将互斥量持有者的优先级提升至所有等待此互斥量的任务所具有的最高优先级。
死锁
死锁是利用互斥量提供互斥功能的另一个潜在缺陷。Deadlock 有时候会被更戏剧性地称为”deadly embrace(抱死)”。任务 A 在等待一个被任务 B 持有的互斥量,而任务 B 也在等待一个被任务 A 持有的互斥量
另外需要注意的是互斥量不能在中断服务函数中使用,因为其特有的优先级继承机制只在任务起作用,在中断的上下文环境毫无意义。
守护任务
守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源——其它任务要访问该资源只能间接地通过守护任务提供的服务
内存管理
Heap_1.c
定义数组的形式
特点:只分配不释放
Heap_1.c 实现了一个非常基本的 pvPortMalloc()版本,而且没有实现 vPortFree()。如果应用程序不需要删除任务,队列或者信号量
具备确定性
Heap_2.c
特点:既可以分配 也 可以释放,易形成碎片
Heap_2.c 适合用于那些重复创建与删除具有相同栈空间任务的应用程序
具备不确定性
但是比大多数标准库实现的 malloc()与 free()更有效率
Heap_3.c
Heap_3.c 简单地调用了标准库函数 malloc()和 free(),但是通过暂时挂起调度器使得函数调用备线程安全特性。
Heap_4.c
在Heap_2.c的基础上支持合并相邻的空闲内存块,减少内存碎片
一般物联网平台使用的是heap_4.c
Heap_5.c
在Heap_4.c的基础上,采用最佳匹配算法和合并算法,允许内存堆跨越多个非连续的内存区,即允许在不连续的内存堆中实现内存分配。比如在在图形显示,可能芯片内部的RAM补足额外扩展SDRAM,那这种内存管理方案则比较合适
错误排查
栈溢出
每个任务都独立维护自己的栈空间,栈空间总量在任务创建时进行设定。uxTaskGetStackHighWaterMark()主要用来查询指定任务的运行历史中,其栈空间还差多少就要溢出。这个值被称为栈空间的”高水线(High Water Mark)”。
运行时栈侦测
Run Time Stack Checking - Method 1
configCHECK_FOR_STACK_OVERFLOW = 1
内核会在任务上下文保存后检查栈指针是否还指向有效栈空间。一旦检测到栈指针的指向已经超出任务栈的有效范围,栈溢出钩子函数就会被调用。
潜在风险:方法 1 具有较快的执行速度,但栈溢出有可能发生在两次上下文保存之间,这种情况不会被侦测到。
Run Time Stack Checking - Method 2
补充方式:方法 2 会检查任务栈的最后 20个字节,查看预置在这里的标记数据是否被覆盖。如果最后 20 个字节的标记数据与预设值不同,则栈溢出钩子函数就会被调用
configCHECK_FOR_STACK_OVERFLOW = 2
方法 2 没有方法 1 的执行速度快,但测试仅仅 20 个字节相对来说也是很快的。这种方法应该可以侦测到任何时候发生的栈溢出,虽然理论上还是有可能漏掉一些情况,但这些情况几乎是不可能发生的。
0 条评论
回复 删除
下一页