This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28379D:__enable_interrupts 与__restore_interrupts

Guru**** 2614885 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1576201/tms320f28379d-__enable_interrupts-vs-__restore_interrupts

部件号:TMS320F28379D


工具/软件:

你(们)好

我的问题

请参阅以下背景一章以了解扩展的上下文。

有三个内在函数用于处理全局 可中断

  1. __disable_interrupts
  2. __enable_interrupts
  3. __restore_interrupts

#3. 当您想要在禁用中断后恢复中断时、这无疑是一个候选方案。

但筛选文档和论坛时、90%的用户都使用#1。 和#2.、只调用#2。 如果位 0 (INTM)、则从#1 返回值。 为 1。

此外、driverlib 仅提供使用#1 的函数。 和#2。  

我想知道为什么会这样,作为#3。 (restore(接缝到更简单和直接的使用。

通过查看 SPRU514Y 中记录的这些内在函数中的汇编指令、我看到了#3。 (恢复)恢复整个 ST1 寄存器、而#1 和#2 调用 SETC 和 CLRC 仅影响 DNGM 和 INTM。

我的问题是:

大多数源使用更麻烦的 __disable_interrupts /_ enable_interrupts 是否有原因?

使用 __restore_interrupts 及其完整的 ST1 延迟是否会产生意外的副作用?

背景

为了保护代码的关键部分免受由于计时或对共享对象的访问而导致的中断影响、我使用了此结构。

bool irqWasEnabled = ! Interrupt_disableGlobal();
// Critical
// code
// lines
// ...
if( irqWasEnabled )
{
    Interrupt_enableGlobal();
}
// ...

最后一部分可以重构为单行体

if( irqWasEnabled ) Interrupt_enableGlobal(); 

但这在许多编码标准中是不允许的。

所以我看了其他的构造显然的解决方案是做一对函数所以我得到

NoInterrupt_start();
// Critical
// code
// lines
// ...
NoInterrupt_end();
// ...

然后、这些函数使用文件静态变量来承载状态(从_start 到_end) 因此、如果代码中的两个位置调用这些函数(一个位于中断上下文中)、那么我必须研究该变量周围是否可能存在竞态条件。

为了便于参考、这些函数的实现方式为

typedef unsigned int irqStatus_t;

static irqStatus_t irqStatus = False;

static void NoInterrupt_start( void )
{
    IrqWasEnabled = ! Interrupt_disableGlobal();
}

static void NoInterrupt_end( void )
{
    if( IrqWasEnabled )
    {
        Interrupt_enableGlobal();
    }
}

但在这次搜索中我发现了这个内在函数

 void __restore_interrupts( irqStatus_t val );

这看起来像是一种更简单的解决方法、我可以使用它

irqStatus_t irqState = __disable_interrupts();
// Critical
// code
// lines
// ...
__restore_interrupts( irqState );
// ...

但正如本文开头所述、我不确定 __restore_interrupts 是否会有其他副作用。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Martin:

    我正在调查您的问题、并将在接下来的 2-3 天内回复您。

    此致、

    Delaney

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Martin:

    对延迟深表歉意。 __restore_interrupts () 函数恢复整个 ST1 寄存器、而不仅仅是寄存器中的 INTM 和 DBGM 位。 调用__enable_interrupts ()/__disable_interrupts () 的 driverlib 函数的目的只是启用/禁用中断,而不是写入 ST1 中的任何其他状态字段。  

    使用 __restore_interrupts () 的风险是:

    1. 您可以覆盖不相关的状态标志。
      假设 CPU 在禁用和恢复中断之间修改了一个状态位(如 SXM 或 OVC)。
      当您稍后调用__restore_interrupts () 时、这些中间更新会被有序地执行—您实际上是将 CPU 状态寄存器回滚到较早的时刻、而不仅仅是重新启用中断。
    2. 与中断上下文的不可预测交互。
      如果此序列发生在 ISR 内部或附近(或者如果发生嵌套)、您可以恢复与当前 CPU 状态不一致的中断前 ST1 值、尤其是当编译器期望某些 ST1 位保持在中断进入期间设置的位时。

    此致、

    Delaney

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、我可以看到寄存器中的其他位。

    我无法获得的是对在关键部分中这些位将发生变化的情况的完整概述。

    在关键部分执行期间、不会发生中断、这就是这些命令的用途。

    我只看到 PUSH 汇编器指令和 SETC 汇编器指令之间出现中断的可能性很小、根据手册、这一结果由 __disable_interrupts 函数生成。

    PUSH ST1
    SETC INTM, DBGM
    POP reg16

    但我们假设在 Push 和 SETC 之间正好发生中断。

    由于 ST1 是上下文保存的一部分(与 SPRU430F 中的表 3-5 相对应)。  

    我假设 ST1 在中断退出时、即PUSH ST1 发生时回到中断之前的位置。 因此堆栈上的版本仍然正确。

    如果此假设不正确、请告诉我。

    在临界区结束时、我调用 _restore_interrupts、它应该会生成以下汇编器指令:

    PUSH val
    POP ST1

    我假设 POP ST1 是重新启用中断的位置、并且此操作是原子操作。

    因此、我认为在恢复 ST1 之前不可能发生中断。

    因此、我能看到的唯一来源是在关键段内运行的代码是否以某种方式影响 ST1 寄存器。

    那么我的问题仍然是、除了此处讨论的内在函数之外、C 编译器生成的任何指令是否会影响 ST1 并因此是否会被恢复操作覆盖?

    还不包括调用 “MSETC XF“等内容的内联汇编器。

    如果我错过了一些内容、请告诉我。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    N: Off-topic:我有点惊讶,这个论坛中的代码插入块不支持汇编器。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Martin:

    我将在接下来的 1-2 天内回复您。

    此致、

    Delaney

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    过了很长时间? :-)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Martin:

    对延迟深表歉意、我一直没能及时回答 E2E 的问题。

    [引述 userid=“172948" url="“ url="~“~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1576201/tms320f28379d-__enable_interrupts-vs-__restore_interrupts/6085083

    因此、我能看到的唯一来源是在关键段内运行的代码是否以某种方式影响 ST1 寄存器。

    [/报价]

    以上是正确的,那就是风险 — 由编译器生成的用于更改 ST1 寄存器的关键部分内的代码。

    问题不会是得到中断或竞态条件导致的、而是 ST1 中的状态位在编译器生成的代码期间发生变化。  如果关键部分中的代码不影响状态位、您可以安全地使用__restore_interrupts () 函数。 我特别没有可避免的命令列表、但我建议在连接调试器的情况下逐步浏览关键部分、并观察 CCS 寄存器视图中的 ST1 C28x 寄存器 (Continuous Refresh On) 来进行检查。 这应该是确定性的、因为代码是由编译器生成的且可不间断的。  

    此致、

    Delaney