Cortex-M3 的关键部分

电器工程 皮质-m3 中断
2022-01-09 23:57:37

我想知道在 Cortex-M3 上实现关键代码部分,由于时序限制或并发问题,不允许出现异常。

就我而言,我正在运行 LPC1758,并且板上有一个 TI CC2500 收发器。CC2500 的引脚可用作 RX 缓冲区中数据的中断线和 TX 缓冲区中的空闲空间。

例如,我想在我的 MCU 的 SRAM 中有一个 TX 缓冲区,当收发器的 TX 缓冲区中有空闲空间时,我想在其中写入这些数据。但是将数据放入 SRAM 缓冲区的程序显然不能被 free-space-in-TX 中断所中断。所以我想做的是在执行填充此缓冲区的过程时暂时禁用中断,但在此过程完成后执行此过程中发生的任何中断。

如何在 Cortex-M3 上做到最好?

3个回答

Cortex M3 支持一对有用的操作(在许多其他机器中也很常见),称为“Load-Exclusive”(LDREX)和“Store-Exclusive”(STREX)。从概念上讲,LDREX 操作执行加载,还设置了一些特殊的硬件来观察加载的位置是否可能被其他东西写入。对最后一个 LDREX 使用的地址执行 STREX 将导致该地址仅在没有其他内容先写入时才被写入。如果存储发生,则 STREX 指令将使用 0 加载寄存器,如果中止,则将加载 1。

请注意,STREX 通常是悲观的。在多种情况下,即使相关位置实际上没有被触及,它也可能决定不执行存储。例如,LDREX 和 STREX 之间的中断将导致 STREX 假设正在监视的位置可能已被击中。出于这个原因,最好尽量减少 LDREX 和 STREX 之间的代码量。例如,考虑如下内容:

内联无效安全增量(uint32_t *addr)
{
  uint32_t 新值;
  {
    新值 = __ldrex(addr) + 1;
  } while(__strex(new_value, addr));
}

编译为:

; 假设 R0 保存有问题的地址;r1 被丢弃
LP:
  ldrex r1,[r0]
  添加 r1,r1,#1
  strex r1,r1,[r0]
  cmp r1,#0 ; 测试是否非零
  bne lp
  .. 代码继续

在代码执行的大部分时间里,LDREX 和 STREX 之间不会发生任何事情来“干扰”它们,因此 STREX 将毫不费力地成功。但是,如果在 LDREX 或 ADD 指令之后立即发生中断,则 STREX 将不会执行存储,而是代码将返回读取 [r0] 的(可能更新的)值并计算新的递增值基于此。

使用 LDREX/STREX 来形成像 safe_increment 这样的操作不仅可以管理关键部分,而且在许多情况下还可以避免对它们的需要。

听起来您的 MCU 软件中需要一些循环缓冲区或 FIFO。通过跟踪数组中的两个索引或指针以进行读取和写入,您可以让前台和后台访问同一个缓冲区而不受干扰。

前台代码可以随时自由地写入循环缓冲区。它在写指针处插入数据,然后递增写指针。

后台(中断处理)代码使用来自读取指针的数据并递增读取指针。

当读写指针相等时,缓冲区为空,后台进程不发送数据。当缓冲区已满时,前台进程拒绝再写入(或者可以覆盖旧数据,具体取决于您的需要)。

使用循环缓冲区来解耦读取器和写入器应该消除禁用中断的需要。

我不记得确切的位置,但在来自 ARM 的库中(不是 TI,ARM,它应该在 CMSIS 或类似的东西下,我使用 ST,但我记得在某处读过这个文件来自 ARM,所以你也应该拥有它) 有一个全局中断禁用选项。这是一个函数调用。(我不在工作,但我明天会查找确切的功能)。我会在你的系统中用一个好听的名字来结束它并禁用中断,做你的事情并再次启用。话虽如此,更好的选择是实现信号量或队列结构,而不是全局中断禁用。