Cortex-M3的关键部分


10

我想知道在Cortex-M3上实现关键代码部分的情况,这些部分由于时序限制或并发问题而不允许例外。

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

例如,我想在我的MCU的SRAM中有一个TX缓冲区,而当收发器的TX缓冲区中有可用空间时,我想在其中写入此数据。但是,将数据放入SRAM缓冲区的例程显然不能被TX中的自由空间中断中断。因此,我想做的是在执行此过程以填充此缓冲区时临时禁用中断,但在此过程完成后执行此过程期间会发生任何中断。

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

Answers:


11

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

请注意,STREX通常是悲观的。在许多情况下,即使实际上未触摸过相关位置,它也可能决定不执行商店。例如,LDREX和STREX之间的中断将导致STREX假定正在监视的位置可能已命中。因此,通常最好将LDREX和STREX之间的代码量减到最少。例如,考虑如下内容:

内联void safe_increment(uint32_t * addr)
{
  uint32_t new_value;
  做
  {
    new_value = __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之类的操作,不仅可以管理关键部分,而且在许多情况下都可以避免需要它们。


因此,没有办法“阻止”中断,以便一旦解除阻止就可以再次为其服务?我意识到,即使有可能,这也可能是一个不太好的解决方案,但我只是想了解有关ARM中断处理的更多信息。
埃米尔·埃里克森

3
可以禁用中断,并且在Cortex-M0上通常没有实际的替代方法。我认为LDREX / STREX方法比禁用中断更为干净,尽管可以肯定的是,在许多情况下,它并不重要(我认为启用和禁用最终每个为一个周期,而禁用五个周期可能没什么大不了的) 。请注意,如果将代码迁移到多核CPU,则ldrex / strex方法将起作用,而禁用中断的方法则不会。此外,某些RTOS的运行代码权限降低,不允许禁用中断。
2012年

无论如何,我可能最终都会使用FreeRTOS,所以我自己不会这样做,但是无论如何我都想学习。与丢弃过程中发生的任何中断相反,我应该使用哪种禁用中断的方法来阻止中断(如上所述)?如果我想丢弃它们怎么办?
埃米尔·埃里克森

上面的一个答案是不可信的,因为相关的代码缺少括号:while(STREXW(new_value, addr); 如果您的代码甚至无法编译,我们如何相信您所说的正确?

@Tim:对不起,我的打字并不完美;我没有为比较而编写的实际代码,因此我不记得我使用的系统是使用STREXW还是__STREXW,但是编译器参考列出了__strex作为内在函数(不同于STREXW,它仅限于32位STREX,__ strex内在用法根据提供的指针大小生成STREXB,STREXH或STREX)
supercat

4

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

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

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

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

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


是的,我显然要使用循环缓冲区,但是递增和递减不是原子操作。
埃米尔·埃里克森

3
@Emil:不必一定要。对于具有两个指针和一个“不可用”插槽的经典循环缓冲区,所需要做的就是内存写入是原子的并按顺序执行。读者拥有一个指针,作家拥有另一个指针,尽管他们两个都可以读取任何一个指针,但是只有该指针的所有者才可以写他的指针。到那时,您所需要的只是原子顺序写入。
约翰·R·斯特罗姆

2

我记不清确切的位置,但是在来自ARM的库中(不是TI,ARM,它应该在CMSIS或类似的东西下),我使用ST,但我记得在某处读到该文件来自ARM,所以您也应该拥有它)有一个全局中断禁用选项。这是一个函数调用。(我不在工作,但是明天我将查找确切的功能)。我会在您的系统中用一个不错的名称将其包装起来,并禁用中断,执行您的操作,然后再次启用。话虽如此,更好的选择是实现信号量或队列结构,而不是全局中断禁用。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.