AVR SEI 指令

电器工程 avr 中断 集会
2022-01-16 02:12:30

AVR SEI 指令 ( http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_SEI.html ) 在启用中断之前等待下一条指令完成。

如果我使用另一条指令设置 SREG 中的 I 标志,这也会等待 1 条指令吗?

换句话说:等待是 SEI 指令的特性还是状态寄存器的特性?

如果它是 SEI 指令的一个特性,那么在执行 SEI 的周期中还是在下一条指令的周期中,该标志实际上是在什么时候设置的?

4个回答

实验结果!

虽然其他答案是经过深思熟虑且有充分理由的,但它们都是不完整的或只是推测。在文档不明确的地方,我们必须进行试验,并且必须测试每个案例。

这个问题值得一个结论性的答案,所以让我们拿出一个 AVR 并开始设置一些位!

程序

为了测试,我做了一个小 Arduino (ATMEGA328P) 程序,它可以...

  1. 设置一个永远不会返回的 ISR ( while (1))
  2. 将 ISR 分配给我可以在软件中触发的源(变INT0低)
  3. 禁用中断
  4. 启用并触发中断,因此它将处于挂起状态

我使用了一个测试台,它会在启用中断后在单条指令中打开 LED。通过尝试在测试台中启用中断并检查 LED 的不同方法,我可以判断启用指令之后的指令是否已执行。

如果 LED 没有亮起,那么我知道 ISR 在启用中断后立即执行(并锁定)。

如果 LED 确实亮了,那么我知道在调用 ISR 之前允许执行下一条指令。

结果

SEI说明(基本情况)

代码:

sei

结果:LED 亮起。执行以下指令。

OUT操作说明

代码:

in  r16,0x3f   // Get SREG
ori r16,128    // Set I bit 
out 0x3f,r16   // Save back to SREG

结果:

带领。执行以下指令。

ST操作说明

代码:

   clr r29        // Clear Y high byte
   ldi r28,0x5f   // Set Y low byte to point to SREG
   ld r16, Y      // Get SREG
   ori r16,128    // Set I bit 
   st Y,r16       // Put SREG

结果:

带领。执行以下指令。

结论!

问:等待是 SEI 指令的特性还是状态寄存器的特性?

A:看起来,将ISREG从 a更改0为 a1将允许下一条指令执行,即使存在未决中断,也不管使用什么指令设置该位。

笔记

这实际上变成了一个非常有趣的问题,有很多复杂性。如果您对他的详细信息感兴趣,请查看...

http://wp.josh.com/2016/01/05/different-ways-to-set-i-bit-in-avr-sreg-besides-sei/

我从文档中了解到,执行sei指令与直接将 1 写入 SREG 的 I 位没有什么不同。该指令的优点是您无需先将值加载1<<I到工作寄存器中即可更改 SREG,从而节省时间。

详细说明,使用sei

sei ; One cycle

使用设置位sbi(仅当 SREG 位于寄存器映射的低 32 字节时才有效,但似乎大多数情况下不是全部。)

sbi SREG,7 ; Two cycles

直接在 SREG 中写入 I 位:

in  r24,SREG ;
ori r24,0x80 ;
out SREG,r24 ; Three cycles

I一旦sei指令(或sbiout)完成,该位应在 SREG 中设置。但是,直到下一条指令完成后,才会处理任何挂起的中断- 该位将被设置,但需要一个额外的周期才能启用中断。因为中断不能在指令中间处理,并且有些指令需要超过一个周期才能执行,所以它们将启用它所需的时间指定为一条指令。这应该适用于所有版本的代码 - 即上述每个版本都会导致指令延迟。


经过一番搜索,我在 Arduino 论坛上找到了这个帖子,其中执行了几个不同的测试来验证行为。好像和我上面说的一样。

此外,根据该线程,如果I已设置标志,则不会导致中断sei的延迟响应,这意味着延迟响应不是由指令本身引起的,而是由I标志控制的内部硬件引起的-因此,任何改变 SREG 中标志的操作,无论是sei具有完全相同的行为。outsts

恕我直言,写入 SREG 仍然延迟 1 条指令可以这样测试(伪代码):

ISR() { PORTA = 0; while(1); }
main() 
{
    cli();
    DDRA = 0xff;
    configure_isr_for_level_interrupt_that_will_trigger_immediately();
    SREG = 0xff;
    cli();
    PORTA = 0xff;
    while(1);
}

不幸的是我没有时间去做:(

这不是它所说的。文件说

SEI 之后的指令将在任何未决中断之前执行。

并不是说它等待下一条指令。我读到这个标志是立即设置的,但即使启用,在执行下一条指令之前不会处理任何中断。