DSP_控制程序框架与优化

本文仅代表个人观点,若有不同意见,请评论区讨论或私信留言。

中心思想

除了那些只需要运行一次的配置程序以外,基于DSP的控制程序可分为两个部分,① 对实时性要求高的部分,②对实时性要求不高的部分。

① 对实时性要求高的程序,建议采用中断处理程序实现。

② 对实时性要求低的程序,建议写在主程序的while(1),用队列的方式实现。比如与上位机通信的程序建议全部写在这个部分。

1、中断程序的优化加速是必要的

在基于DSP的控制程序框架中, 实时性要求高的那部分程序,一般包含传感器的采样和解码、控制器程序、控制量(驱动量)下发程序。首先,我们要有一个共识,CPU在任何一个时刻,都只能运行某一个中断程序或者主程序。 假设现有某控制系统,要求控制器以5kHz的频率实时控制。理想情况下的CPU时间片图1所示。

DSP_控制程序框架与优化_第1张图片 图1

在0.0002s内, CPU要完成很多不同任务。 其中T1~T4这几个时间段,CPU在跑中断程序。 而剩下的T5~T8这些空隙,则是可以用来运行while(1)里面的程序。 在上图的这种情况下,控制程序是可以完成5kHz实时控制的要求的。 然而,真实的CPU时间片图是很难通过技术手段画出来的,图1仅仅只是我对理想情况的臆想和猜测。

如果系统处于理想情况下,假设所有会被触发的中断INT1 ~ INTn,在0.0002s内要分别发生N1~Nn次,中断INT1 ~ INTn的中断处理程序运行一次需要的时间分别为T1 ~ Tn。那么所有中断处理程序在0.0002s内占用的总时间Tint为:

{T_{\operatorname{int} }} = \sum\limits_{i = 1}^n {​{N_i} \cdot {T_i}}

显然, 我们一定是期望Tint < 0.0002s,因为CPU还需要留点时间给主程序去运行那些实时性要求不高的程序。关于CPU的时间片,更贴近真实的情况是,CPU正在运行某一个中断程序时,还没有运行结束,另一个中断请求就来了,这个时候另一个中断只能等当前的中断运行完,然后接着运行。因为中断请求在CPU时间片的哪个时刻发生,往往是我们不能控制的。  有时候甚至CPU正在运行某一个中断程序的时候,可能另外来了2个甚至更多的中断请求,这个时候DSP应该会让它们按优先级排队等候,然后等当前中断程序运行结束后,对这些中断依次处理。  即使发生了上述这些情况, 只要满足 Tint < 0.0002s的条件,那系统仍然会正常运行,5kHz的控制频率要求仍然会被满足。

然而,事实上,CPU也有可能出现如图2所示的非理想的情况

DSP_控制程序框架与优化_第2张图片 图2

即  Tint > 0.0002s的情况。下面我们分两种情况来讨论

1、Tint只比0.0002s大一点点(比如0.00025s), 而且CPU时间片的排列有疏有密(简单说就是能给主程序留时间出来),在这种情况下,系统可能也能勉强以我们察觉不到的异常方式,正常运行着,控制性能也能满足我们的要求。  控制器的离散化是按照0.0002s离散的,如果你实际的执行不是0.0002s执行一次,那系统的运行状态肯定不是我们所期望的。

2、如果是Tint >> 0.0002s的情况,那系统就会出现各种问题,常见的问题就是无法获取某些传感器数据、无法与上位机通信。可能的原因我认为是:优先级高且运行时间长的中断总占着CPU的话,其他低优先级的中断处理程序根本不会被执行,主程序的while(1)里面的程序也不会被执行。(红字这段话还有待证明)

Tint量化可以借鉴DSP_TMS320F28377D_使用定时器实现<获取代码块运算时间>的功能,得到每个中断的处理程序运行一次的时间,然后根据每个中断在0.0002s内的运行次数,就可以通过之前给出公式来计算啦

{T_{\operatorname{int} }} = \sum\limits_{i = 1}^n {​{N_i} \cdot {T_i}}

另外,比如上位机通信的这种根据用户决定中断触发频率的,可以只算1次。咱们就是尽量把中断处理程序做简化,常用的处理方式就是上位机通过串口发数据过来触发串口接收中断,然后中断处理程序就把接收到的原始数据直接拷贝加入串口数据队列,就可以关中断了。其他事情,都放在while(1)。 总之就是最大限度降低中断程序的复杂度。否则,最坏的情况可能会出现上位机一发命令,系统就会挂掉的情况。

总之,中断程序要想尽一切办法加速,能简化的要尽量去简化,目的是让系统满足Tint < 0.0002s

关于DSP程序的加速方法,我研究了一些,可以参考参考,这4种办法都是可以在中断程序中使用的。

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资源浪费也很关键

如果上述第一点已经做到极致了,中断程序本身已经优化不下去了,可考虑另一种优化的思路,就是规避CPU资源浪费

传感器信息的获取分为主动触发的采样方式 和 被动的接收中断方式  

1、主动触发采样是可以通过程序去配置的,建议把采样频率配置成和对应控制回路的频率一致,如果高于控制回路的频率,则会造成CPU资源浪费。 

2、被动的接收中断方式 ,采样频率取决于传感器给控制器发送数据的频率。 如果传感器以高于你控制回路频率给你发送数据(比如传感器以20KHz的频率给你发数据, 但是你控制回路是5kHz的)。如果你以传感器给你的高频率去接收数据并解码,那么将会造成资源浪费。 那么建议你被动接收传感器数据的中断程序中,做一个计数分频判断,比如计数值➗4的余数不为0的时候,我直接清除接收缓存直接清中断返回。计数值➗4的余数为0的时候,我就把数据存下来并解码以备使用。 这样的处理方式,4帧数据中,3帧直接丢弃,只有1帧做了接收和数据处理。 这样本质上来说也会避免CPU资源浪费

3、上位机通信小技巧 - “高频小队列”

作为一个又写上位机又写下位机的苦命人,深知DSP上用于和上位机通信程序会占用大量的CPU资源。 前面第1点已经谈过了一些相关话题,这里再单独拎出来强调一下,无论接收和发送数据,我都建议用小队列的方式放在主程序while(1)中

1、接收上位机命令是个不频繁的操作,但我还是建议接收中断直接把接收到的原始数据拷贝出来就关中断,上位机可把一帧数据才成几个小队列发过来。DSP这边通过检测帧头和帧尾这些手段来判断是否抓取了一个完整的数据包。 避免上位机发一个命令,直接把系统搞崩的情况。

2、发送数据到上位机就是个体力活了,有时候要求上位机显示系统实时的状态信息,那么首先我们发送到上位机的数据就得做不得假啦,数据量肯定很大,而且还相对高频。 对于此,我的建议是高频小队列,什么意思呢? 你可以把你所有需要发送的数据都用队列的方式存储起来,存储这个动作相比于发送数据的动作耗时更短的, 然后比如我1kHz的频率,只要我队列不为空,我就从队列取一个出来进行一次发送,但每次只发送8个字节或更少(一次如果只发8字节,发送数据的耗时是不长的)。 它等价于 50Hz 160字节。   这种做法的优势是,你如果一次性发送160字节,会占据CPU非常长的时间。 这一次发送也会导致控制系统其他所有功能完全崩溃了。 

总之,控制程序框架分为两个部分:

        对实时性要求高的程序,建议采用中断处理程序实现。

        对实时性要求低的程序,建议写在主程序的while(1),用队列的方式实现。

对于程序的优化建议有三条:

        1、中断程序的优化加速是必要的;

        2、避免CPU资源浪费也很关键;

        3、上位机通信小技巧 - “高频小队列”

感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。

你可能感兴趣的:(DSP,单片机,嵌入式硬件,dsp,框架,控制)