本文仅代表个人观点,若有不同意见,请评论区讨论或私信留言。
中心思想:
基于DSP的控制程序可分为两个部分,① 对实时性要求高的部分,②对实时性要求不高的部分。
① 对实时性要求高的程序,建议采用中断处理程序实现。
② 对实时性要求低的程序,建议写在主程序的while(1),用队列的方式实现。比如与上位机通信的程序建议全部写在这个部分。
1、中断程序的优化加速是必要的
在基于DSP的控制程序框架中, 实时性要求高的那部分程序,一般包含传感器的采样和解码、控制器程序、控制量(驱动量)下发程序。默认状态下DSP程序是没有配置中断嵌套的(如果要搞中断嵌套可以去这篇→TMS320F28335软件设置中断优先级的原理_28335中断优先级_死灰如风的博客-CSDN博客)。首先,我们要有一个共识,即便是你弄了中断嵌套,CPU在任何一个时刻,都只能运行某一个中断程序或者主程序。 假设现有某控制系统,要求控制器以5kHz的频率实时控制。理想情况下的时间片示意图如下。
在0.0002s(5kHz)内, 我们的CPU干了很多事情。 T1+T2+...+T8 = T。 其中T1~T4这几个时间段,CPU都在跑中断程序。 而剩下的T5~T8这些空隙,则是可以用来跑主程序,比如while(1)里面的程序。 (注:上图只是示意, 比如我传感器ADC采集是20kHz的,一个控制周期T内,有就会有4次T1。 反正无论你有多少个中断,你都能够在一个控制周期T内跑完,这个就是理想情况)。
然而实际上,很有可能发生下面这种情况。
当我CPU正在运行某一个中断的时候,另一个中断来了,这时候排队等候,等上一个中断运行完。如果控制回路需要的所有的中断程序运行一次的时间加起来,小于我们所期望的控制周期时间T吗,这时候也没问题。 但如果说所有的中断程序的运行时间加起来远远大于我们所期望的控制周期时间T。而某些对于控制系统而言非常重要的中断程序,优先级很低,排队总排在后面。那这时候程序运行就会出现异常啦。 这个时候我们就急需优化中断处理程序啦,特别是优先级高的中断处理函数。优先级高且运行时间长的中断总占着CPU的话,其他低优先级的中断处理程序根本不会被执行,主程序的while(1)里面的程序也不会被执行。(红字这段话还有待证明,可以用两个优先级不同的定时器中断来证明,在高优先级的定时器中断里面做一个超过改定时器计数的长延迟,看看低优先级的定时器中断会不会进,有时间我去测试一下)。
无论高优先级中断会不会长时间占用CPU导致低优先级中断和主程序不被运行。 如果所有的中断程序0.0002s时间片的运行时间总和 > 0.0002s,程序的运行都不会正常。因为控制器的离散化是按照0.0002s离散的,如果你实际的执行不是0.0002s执行一次,那系统的运行状态肯定不是我们所期望的。
所以:
中断程序要想尽一切办法加速,能简化的要尽量去简化。
曾经本人干过一个蠢事,就是在控制算法的那个定时器中断里面,去编码和发送串口数据到上位机(非常耗时),这样的做法会让控制算法的中断程序占用大量的CPU时间。
关于DSP程序的加速方法,我研究了一些,可以参考参考。
DSP_TMS320F28377D_算法加速方法1_拷贝程序到RAM运行-CSDN博客
DSP_TMS320F28377D_算法加速方法2_添加浮点运算快速补充库rts2800_fpu32_fast_supplement.lib_江湖上都叫我秋博的博客-CSDN博客DSP_TMS320F28377D_算法加速方法3_使用TMU库加速_江湖上都叫我秋博的博客-CSDN博客
DSP_TMS320F28377D_算法加速方法4_C语言编程优化_江湖上都叫我秋博的博客-CSDN博客
2、避免CPU资源浪费
另一个值得注意的一点,传感器信息的获取分为主动触发的采样方式 和 被动的接收中断方式
1、主动触发采样是可以通过程序去配置的,建议把采样频率配置成和控制回路的频率一致,如果高于控制回路的频率,则会造成CPU资源浪费。
2、被动的接收中断方式 ,采样频率取决于传感器给控制器发送数据的频率。 如果传感器以高于你控制回路频率给你发送数据(比如传感器以20KHz的频率给你发数据, 但是你控制回路是5kHz的)。如果你以传感器给你的高频率去接收数据并解码,那么将会造成资源浪费。 那么建议你被动接收传感器数据的中断程序中,做一个计数分频判断,比如计数值➗4的余数不为0的时候,我直接清除接收缓存,直接清中断返回。计数值➗4的余数为0的时候,我就把数据存下来并解码以备使用。 这样的处理方式,4帧数据中,3帧直接丢弃,只有1帧做了接收和数据处理。 这样本质上来说已经避免了CPU资源浪费。
3、上位机通信单独拎出强调
作为一个又写上位机又写下位机的苦命人,深知DSP上用于和上位机通信程序会占用大量的CPU资源。 这里单独拎出来讲一下,无论接收和发送数据,我都建议用小队列的方式放在主程序while(1)中,接收上位机命令是个不频繁的操作,但我还是建议接收中断直接把接收到的原始数据拷贝出来就关中断,上位机可把一帧数据才成几个小队列发过来。DSP这边通过检测帧头和帧尾这些手段来判断是否抓取了一个完整的数据包。 发送数据到上位机就是个体力活了,有时候要求上位机显示系统实时的状态信息,那么首先我们发送到上位机的数据就得做不得假啦,数据量肯定很大,而且还相对高频。 对于此,我的建议是高频小队列,什么意思呢? 你可以把你所有需要发送的数据都用队列的方式存储起来(存储这个动作相比于发送数据的动作耗时更短的), 然后比如我1kHz的频率,只要我队列不为空,我就取一个出来进行一次发送,但每次只发送8个字节或更少(一次如果只发8字节,发送数据的耗时是不长的)。 它等价于 50Hz 160字节。 这种做法的优势是,你如果一次性发送160字节,会占据CPU非常长的时间。 这一次发送会导致控制系统其他所有功能完全崩溃了。