文章目录
前言
近期在一些嵌入式系统开发项目中,在使用嵌入式处理器时,遇到了挺多费时费力的事情。所以利用晚上和周末时间,在这些方面深入研究了一下,解锁了一些新技能。后面会用若干篇文章把它总结分享出来,以备将来翻看,同时也希望能够帮到这一领域的粉丝朋友们。
由于实际项目比较庞大,而且不便在网络公开,所以就另起了一个Demo工程,重点介绍其中的原理、方法和特性分析。
Timer中断调度
Timer中断是硬件中断的一种,其在处理器中断框架中的位置如下图所示:
Timer中断工作的过程如下:
TDDRH:TDDR 是一个16位的时钟分频因子寄存器,需要开发者写入分频的倍数。
PSCH:PSC 是一个16位的分频计数寄存器,能随着时钟节拍递减,递减到0时重新装载TDDRH:TDDR 寄存器的值,然后继续循环。每循环一次后TIMH:TIM计数器减1。
PRDH:PRD 是一个32位的周期寄存器,需要开发者写入循环周期的长度。
TIMH:TIM 是一个32位的计数寄存器,能随着分频后的时钟节拍递减。递减到0时重新装载PRDH:PRD寄存器的值,然后继续循环。每循环一次后产生一个Timer中断脉冲。当Timer中断脉冲产生时,就可以作为一个Task调度的Flag,如果有多个不同周期的异步Task,就可以使用多个Timer中断来调度。
举例: 如果我们想制造一个0.01s的Timer中断,并且已知处理器的系统时钟是120MHz。首先设定分频因子为2,那么分频后的时钟频率是60MHz。PRDH:PRD = 0.01s/(1/60,000,000) = 600,000。
Tips: 如果循环周期计算出来不是整数,四舍五入的话就会引入设计误差,这时就可以通过调整分频因子来弥补这种误差。或者循环周期超出了32位的最大值,也可以调整分频因子来修正。
Event中断调度
Event中断是硬件中断的一大类,其在处理器中断框架中的位置如下图所示:
Event中断工作的过程如下:
本文以SCI通信事件为例,来讲解异步任务的调度。
第一步 ,在Hardware Settings中勾上SCI数据接收后中断使能,并配置优先级level,示例如下:
第二步 ,从模块库Scheduling中拖出ISR模块,示例如下:
第三步 ,在硬Hardware Mapping中选择SCI接收中断,并勾上中断服务后清除状态flag,示例如下:
第四步 ,在Simulink Model中创建f()函数调用子系统,连接到前面的ISR模块event端口上,示例如下:
当SCI接收到数据时,就会产生一个中断脉冲。可以作为一个Task调度的Flag,比如响应SCI命令的Task。如果有多个类似的触发型异步Task,就可以使用多个event中断来调度。
StateFlow调度
前面两种任务调度的方法都是依赖于处理器硬件的中断和对应的中断服务程序,这种调用方式通常只适用于小负荷的任务,因为软件不能长时间处于中断服务程序中。如果有大负荷的任务,就要引入Idel Task调度模块,在其内部使用StateFlow等纯软件的方法调度各个任务,示例如下:
Idel Task调度的任务生成C语言中后,实际上就是在main()的while(1){}中全速循环的任务。大部分的软件任务实际上不需要这么快的循环速度,所以也可以用前面Timer周期的思想,用软件变量递减的方式做一些周期性的Flag。示例如下:
cpp
flag = 0;
for(i=0;i<50000;i++){
for(j=0;j<8;j++){
Cnt1 -= 1;
if(Cnt1 == 0){
Cnt1 = 8;
}
}
Cnt2 -= 1;
if(Cnt2 == 0){
Cnt1 = 50000;
flag = 1;
}
}
Tips: 这种软件循环周期,精度不如Timer中断周期高。
有了周期循环的基础后,就可以使用StateFlow调用子系统的方式来调度多任务异步执行,示例如下:
分析和应用
1、使用Timer中断调度任务的方法,任务周期的精度非常高,几乎不会波动,因为它的节拍源是非常稳定的系统时钟。
2、能引起Timer中断周期波动的唯一因素是中断冲突。可以设置Timer中断的优先级,来决定当发生中断冲突时先执行哪个中断。也可以设置Timer中断是否允许抢占,来确定当有新中断产生时Timer中断是否会被打断。
3、使用Event中断调度任务,与Timer中断的工作机制比较相似。并且依赖于处理器中断的原理,可以保证外部Event产生时可以非常快速地响应,也保证了嵌入式系统的实时性。
4、使用StateFlow调度任务,他的基础是软件延时控制的周期循环,很容易受到处理器负荷变化引起的波动。使用StateFlow调度任务的优点是调度非常灵活,能处理的任务量也可以比较大。
5、一种比较完美的任务调度方法时把上述三种方式结合起来,避开各自的劣势,发挥各自的优势。首先可以使用Timer中断产生一个最小的单位周期(例如10ms),然后在此基础上利用软件计数延时的方式产生20ms和50ms的周期Flag,然后进一步开发Stateflow调度任务。这样既可以保证控制周期在一定程度上的稳定性,也能充分发挥Stateflow调度任务的灵活性,同时保留Event中断调度方式的实时性,这样整体嵌入式系统的性能就比较均衡了。如果具体的嵌入式系统应用场景中,值要求哪一方面的绝对性能,那么就可以完全只依赖于其中一种任务调度方式,抛弃其他的调度方式。
总结
以上就是本人在研发中使用嵌入式处理器做异步任务调度时,一些个人理解和分析的总结,主要介绍了三种异步任务调度的工作原理,展示了具体的使用方法,并对比分析了这些不同方式的特点差异和各自的适用场景。
后续还会分享另外几个最近解锁的嵌入式处理器新技能,欢迎评论区留言、点赞、收藏和关注,这些鼓励和支持都将成文本人持续分享的动力。
另外,上述例程使用的Demo工程,可以到笔者的主页查找和下载。
参考资料
cpp
TMS320F28003x Real-Time Microcontrollers datasheet.pdf
版权声明,原创文章,转载和引用请注明出处和链接,侵权必究!