AVR-GCC 意外中断延迟

问题描述 投票:0回答:1

我有一些代码,其中中断抖动是交易杀手。只有一个中断源,并且需要尽可能精确。对于 ATMEGA,最大中断响应是当前指令的长度 + 调用中断例程。
但我的代码表现不稳定。中断延迟看起来要大得多。终于我找到了问题所在。 GCC自己禁用中断!这是一个简单的例子。源代码中根本没有中断使用。

#include <avr/io.h>

void DoJob(void){
    uint8_t buf[256];
    for (uint8_t i = 0; i < 255; i++){
        PORTB=buf[i];
        buf[i]=PORTB;
    }
}

int main(void){
    for(;;){
        DoJob();
    }
}

现在在汇编器列表中出现了惊喜。有 CLI 指令可以禁用中断。

000000cc <DoJob>:
  cc:   cf 93           push    r28
  ce:   df 93           push    r29
  d0:   cd b7           in  r28, 0x3d   ; 61
  d2:   de b7           in  r29, 0x3e   ; 62
  d4:   da 95           dec r29
  d6:   0f b6           in  r0, 0x3f    ; 63

  d8:   f8 94           cli

  da:   de bf           out 0x3e, r29   ; 62
  dc:   0f be           out 0x3f, r0    ; 63
  de:   cd bf           out 0x3d, r28   ; 61
  e0:   fe 01           movw    r30, r28
  e2:   31 96           adiw    r30, 0x01   ; 1
  e4:   ce 01           movw    r24, r28
  e6:   93 95           inc r25
  e8:   21 91           ld  r18, Z+
  ea:   25 b9           out 0x05, r18   ; 5
  ec:   25 b1           in  r18, 0x05   ; 5
  ee:   df 01           movw    r26, r30
  f0:   11 97           sbiw    r26, 0x01   ; 1
  f2:   2c 93           st  X, r18
  f4:   e8 17           cp  r30, r24
  f6:   f9 07           cpc r31, r25
  f8:   b9 f7           brne    .-18        ; 0xe8 <DoJob+0x1c>
  fa:   d3 95           inc r29
  fc:   0f b6           in  r0, 0x3f    ; 63

  fe:   f8 94           cli

 100:   de bf           out 0x3e, r29   ; 62
 102:   0f be           out 0x3f, r0    ; 63
 104:   cd bf           out 0x3d, r28   ; 61
 106:   df 91           pop r29
 108:   cf 91           pop r28
 10a:   08 95           ret

0000010c <main>:
 10c:   0e 94 66 00     call    0xcc    ; 0xcc <DoJob>
 110:   fd cf           rjmp    .-6         ; 0x10c <main>

在这个例子中,解决方案很简单,只需将缓冲区声明为全局即可解决问题。但在实际代码中,无法将所有缓冲区和变量声明为全局,因为没有空间。那么如何避免这种情况,是否还有其他情况编译器在不知道的情况下禁用中断?至少警告编译器这样做应该受到欢迎。我的系统可能每天都会出现一次错误,并且需要很长时间才能发现问题。

interrupt avr latency
1个回答
0
投票

需要中断锁,因为SP的设置必须是原子的。锁在 OUT 0x3d 之前一直有效。

当你确定该函数运行时不会触发任何IRQ,然后将其放入自己的编译单元并添加选项

-mno-interrupts

© www.soinside.com 2019 - 2024. All rights reserved.