如何保持中断时间短?

Mui*_*uis 11 embedded arm interrupt firmware interrupt-handling

嵌入式编程中最常听到的建议是"保持中断时间短".

现在我的情况是我的main()循环中有一个非常长的运行任务(将大块数据写入SD卡),有时需要100ms.因此,为了保持我的系统响应,我将所有其他内容移动到了中断处理程序.

例如,通常可以在中断中处理传入的UART数据,然后在main()循环中处理传入的命令,然后发回响应.但在我的情况下,命令的整个处理/处理也在中断中进行,因为我的main()循环可以被阻塞(相对)长时间.

最佳解决方案是切换到RTOS,但我没有RAM.我的设计是否有替代方案可以缩短中断时间?

Sec*_*att 10

传统的方法是让Interrupts安排延期程序并尽快结束中断.

中断完成后,延迟程序列表从最重要到最不重要.

考虑你有主要(较低职业)行动和两个中断I1和I2的情况,其中I2比主要重要,但不如I1重要.

在这种情况下,假设您正在运行main和I1触发.I1调度延迟过程并向硬件发信号通知I1已完成.I1的DPC现在开始运行.突然,I2从硬件进来.I2的中断从I1的DPC接管并调度I2的DPC并向硬件发出信号.

然后调度程序返回到I1的DPC(因为它更重要),当I1的DPC完成时,I2的DPC开始(因为它比main更重要),然后最终返回执行到main.

此设计允许您安排不同中断的重要性,鼓励您保持较小的中断,并允许您按有序和按顺序优先级方式完成DPC.


Dan*_*Dan 9

根据CPU架构(中断嵌套和优先级划分,软件中断支持等),有100种不同的方法可以对这只猫进行换肤,但让我们采用一种非常直接的方法,这种方法相对简单易懂并且不受竞争条件和资源共享的影响先占核心的危害.

(免责声明:我的第一选择通常是抢占式实时内核,其中许多可以在极其资源受限的系统中运行...... SecurityMatt的建议很好但是如果你不习惯实现自己的可抢占内核/任务切换器,特别是处理异步(中断触发)抢占,你可以很快地绕过轴.所以我在下面提出的不像基于抢占的内核那样响应,但它更简单,通常是足够的.

创建3个事件/工作队列:

  • Q1是最低优先级,可处理慢速后台SD卡写入
  • Q2保留处理传入UART数据包的请求
  • Q3(最高优先级)保存UART RX FIFO读取请求.

我将UART RX FIFO读取和读取数据包的处理分开,以便在数据包处理之前始终为FIFO读取提供服务; 也许你想把它们放在一起,你的选择.

为此,您可以将大型(~100ms)SD卡写入过程分解为一系列较小的,离散的运行步骤.

因此,例如,要写入5个块,每个块20ms,您编写第一个块,然后将"写下一个块"排队到Q1.您将在每个步骤结束时返回到调度程序,并按优先级顺序扫描队列,从Q3开始.如果Q2和Q3为空,则将下一个事件从Q1中拉出("写下一个块"),再运行该命令20ms,然后再返回并再次扫描队列.如果20ms没有足够的响应,则将每个20ms的块写入分解为更细粒度的步骤,并在下一个工作步骤中不断发布到Q1.

现在为传入的UART东西; 在UART RX ISR中,您可以简单地在Q3中将"读取UART FIFO"命令排入队列,并从中断返回到被中断的20ms"写入块"步骤.一旦CPU完成写入,它就会返回并按优先级顺序扫描队列(如果在中断时块写入刚刚开始,则最坏情况响应将为20ms).队列扫描程序(调度程序)将看到Q3现在有工作要做,它将在返回并再次扫描之前运行该命令.

在最坏的情况下,系统的响应性将由系统中最长的完成运行步骤确定,而不管优先级如何.通过在小型,离散,运行到完成步骤中完成工作,您可以使系统保持高响应性.

请注意,我必须在这里说一般性.也许你想在ISR中读取UART RX FIFO,将数据放入缓冲区,只推迟数据包处理,而不是实际读取FIFO(那时你只有2个队列).你必须自己解决这个问题.但我希望这种方法有道理.

这种具有优先级队列的事件驱动方法正是Quantum Platform(QP)事件驱动框架所使用的方法.QP实际上支持底层的非抢占式(协作式)调度程序,例如此处描述的调度程序,或者每个事件排队时运行调度程序的抢占式调度程序(类似于SecurityMatt建议的方法).您可以在QP网站上查看QP协作调度程序的代码/实现.