ESP8266/Arduino:为什么需要将ICACHE_RAM_ATTR宏添加到ISR和从那里调用的函数?

ESP8266/Arduino:为什么需要将ICACHE_RAM_ATTR宏添加到ISR和从那里调用的函数?,arduino,esp8266,arduino-esp8266,isr,Arduino,Esp8266,Arduino Esp8266,Isr,我读到我在为ESP8266编写Arduino代码以防止随机崩溃。我还发现,尽管我不确定Espressif ESP8266 SDK的解释是否也适用于ESP8266上的Arduino。我不明白为什么我需要将宏添加到ISRs 第一个问题:为什么我需要将ICACHE\u RAM\u ATTR宏添加到ISRs以及从那里调用的所有函数 下一个问题是,如果我强制内联从ISR调用的函数,会发生什么情况: inline void doStuff() __attribute__((__always_inline__

我读到我在为ESP8266编写Arduino代码以防止随机崩溃。我还发现,尽管我不确定Espressif ESP8266 SDK的解释是否也适用于ESP8266上的Arduino。我不明白为什么我需要将宏添加到ISRs

第一个问题:为什么我需要将ICACHE\u RAM\u ATTR宏添加到ISRs以及从那里调用的所有函数

下一个问题是,如果我强制内联从ISR调用的函数,会发生什么情况:

inline void doStuff() __attribute__((__always_inline__)) { // <-- necessary to add ICACHE_RAM_ATTR here?
    // no more function calls here
}

void ICACHE_RAM_ATTR handleInterrupt() {
    doStuff();
}

inline void doStuff()_属性__((_始终_inline__)){/ICACHE_RAM_ATTR和ICACHE_FLASH_ATTR是链接器属性。编译草图后,您可以说函数是否应存储在RAM或FLASH中(通常不设置任何内容:无缓存)

ESP8266是多任务的,ESP32有两个内核。因此,您可以以多线程方式执行代码,因为它使用RTO

现在的问题是:整个闪存都用于程序和存储。对闪存的读取和写入只能在一个线程上完成。如果您试图通过两个不同的线程同时访问闪存,您的ESP可能会崩溃

这是因为你可以把你的功能放在RAM中而不是闪存中。因此,即使你在EEPROM或闪存中写东西,也可以在不访问闪存的情况下调用这个功能

使用
ICACHE\u RAM\u ATTR
可以将函数放在RAM上

使用
ICACHE\u FLASH\u ATTR
可将该功能置于闪存上(以保存RAM)

中断函数应使用经常调用的ICACHE_RAM_ATTR。函数不应使用任何缓存属性

重要提示:切勿在中断内访问闪存!中断可能发生在闪存访问期间,因此如果您同时尝试访问闪存,则会发生崩溃(有时在使用设备1-2小时后发生)

因为您只有32kb的IRAM(指令RAM),所以您应该尝试只在RAM中放入中断函数,而不是所有函数,即使可以这样做

第二个问题:
不,绝对不行!内联是另一个编译器标志,这样编译器会尝试把你的整个函数放入调用函数= >将一个函数调用转换为C++代码在你的主体中。这并不意味着编译器会做它,只是尝试它。如果函数不再存在,你不能要求把函数放在RAM中。您可以编译您的草图。

非常感谢ICACHE_RAM_ATTR,我在代码的最顶层使用了它……当然,也有一些管脚不能作为中断工作,例如,在我的情况下,我使用的是board WEMOS D1 Mini Pro,管脚D0(GPIO 16)不工作,直到我换到下一个管脚,(GPIO 14)并且它工作正常

ICACHE_RAM_ATTR可以与较新的库一起工作,过时的2.5库也可以在没有这段代码的情况下工作

非常感谢

const uint8_t interruptPin = 14;
volatile byte interruptCounter = 0;
int numberOfInterrupts = 0;
void ICACHE_RAM_ATTR handleInterrupt();

void setup() {

  Serial.begin(9600);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, CHANGE);

}

void handleInterrupt() {
  interruptCounter++;
}

void loop() {

  if(interruptCounter>0){

      interruptCounter--;
      numberOfInterrupts++;

      Serial.print("An interrupt has occurred. Total: ");
      Serial.println(numberOfInterrupts);
  }

}

谢谢你的解释!关于内联:所以我想我应该将ICACHE_RAM_ATTR添加到所有从ISR调用的函数中,即使标记为内联,因为我无法确定它们是否真的会内联?添加ICACHE_RAM_ATTR会阻止内联吗?除了调用没有ICACHE_RAM_ATTR attrib的函数之外还有什么te可能会导致闪存访问?是的,如果您在ISR中调用另一个函数,最好将ICACHE_RAM_ATTR也添加到此函数中。内联函数只是对编译器的请求(),并不意味着它将以100%内联,如果添加ICACHE_RAM_ATTR,它可能会被忽略。你不应该尝试在中断中读取或写入参数或spiff。老实说,我不能说什么将访问闪存。我有一个项目,在中断中使用DAC输出,这也会崩溃,因为它访问和更改一些寄存器(它们在闪存中)。如果中断是计时器,您可以使用例如Ticker,这将防止崩溃。