sandeepmistry / arduino-LoRa

An Arduino library for sending and receiving data using LoRa radios.
MIT License
1.61k stars 621 forks source link

ESP32 InstrFetchProhibited when trying to send data from receive function called by onReceive(). #556

Closed PepeProf closed 2 years ago

PepeProf commented 2 years ago

Hello,

Currently I am having problems sending back a package from the receive function called by onReceive(). Everything is working correctly, all the pins are connected correctly and sending/receiving is working just fine.

First I send a package to the ESP32 with type 0x02 and the ESP answers back with package type 0x03. And in my case the package is sent back (type 0x03), but the ESP32 crashes, after it tries to leave the onPackageReceive() function.

Problematic ESP code:

#include <SPI.h>
#include <LoRa.h>

//====== Defining Pins =============
#define RF_RST  22
#define RF_CS   15
#define RF_SCK  18
#define RF_MOSI 23
#define RF_MISO 19
#define RF_IRQ  11
//==================================

SPIClass hspi = NULL;

byte localAddress = 0x00;

void setup() {
  Serial.begin(115200);
  Serial.println("Starting...");

  //========================== Initalizing Radio SPI ==================================
  hspi = SPIClass(HSPI);
  LoRa.setSPI(hspi);

  LoRa.setPins(RF_CS, RF_RST, RF_IRQ);// set CS, reset, IRQ pin
  if (!LoRa.begin(868E6)) Serial.println("LoRa init failed. Check your connections.");

  //============================== MY ADDRESS =========================================
  localAddress = 0x02; 
  //=================================================================================== 

  LoRa.setTxPower(5);
  Serial.println("LoRa init succeeded.");

  LoRa.onReceive(onPackageReceive);
  LoRa.receive();
  //===================================================================================
}

void loop() 
{
  delay(100);
}

void onPackageReceive(int packetSize) {
    if (packetSize <= 0) return;

    byte to = LoRa.read();

    if (to == localAddress || to == 0xff) {}
    else return;

    byte type = LoRa.read();
    byte from = LoRa.read();

    Serial.println("============== Package Received ==============");
    Serial.print("   To: "); Serial.println(to, HEX);
    Serial.print("   From: "); Serial.println(from, HEX);
    Serial.print("   Type: "); Serial.println(type, HEX);
    Serial.print("   RSSI: "); Serial.println(LoRa.packetRssi());
    Serial.println("=============================================");

    if (type == 0x02)
    {
        sendPackage(from, 0x03);
        Serial.println("Sent!");
    }

}

void sendPackage(byte destination, byte type)
{

    LoRa.beginPacket();

    LoRa.write(destination);
    LoRa.write(type);
    LoRa.write(localAddress);
    LoRa.endPacket();

    LoRa.receive();

    Serial.println("=============# Package Sent #=============");
    Serial.print("   To: "); Serial.println(destination, HEX);
    Serial.print("   From: "); Serial.println(localAddress, HEX);
    Serial.print("   Package Type: "); Serial.println(type, HEX);
    Serial.println("==========================================");
}

Serial monitor:

Starting...
LoRa init succeeded.
============== Package Received ==============
   To: 2
   From: 1
   Type: 2
   RSSI: -61
=============================================
=============# Package Sent #=============
   To: 1
   From: 2
   Package Type: 3
==========================================
Sent!
Guru Meditation Error: Core  1 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x00000010  PS      : 0x00050a33  A0      : 0x00000010  A1      : 0x3ffbea70  
A2      : 0x3ffbeab0  A3      : 0x3ffc013c  A4      : 0x3f4002f1  A5      : 0x00000010  
A6      : 0x00000002  A7      : 0x3ffbeaad  A8      : 0xff000000  A9      : 0x800d0eb0  
A10     : 0x3ffbead0  A11     : 0x3ffc013c  A12     : 0x00000001  A13     : 0x00000010  
A14     : 0x00000001  A15     : 0x7ff00000  SAR     : 0x0000000d  EXCCAUSE: 0x00000014  
EXCVADDR: 0x00000010  LBEG    : 0x3ffbfed0  LEND    : 0x00000001  LCOUNT  : 0x3ffc013c  

ELF file SHA256: 0000000000000000

Backtrace: 0x00000010:0x3ffbea70 0x0000000d:0x3ffbea90 0x400d20a9:0x3ffbeab0 0x400d20a9:0x3ffbead0 0x400d0ead:0x3ffbeaf0 0x400d14f9:0x3ffbeb10 0x40080eba:0x3ffbeb30 0x40080f05:0x3ffbeb50 0x400838ed:0x3ffbeb70 0x40080ee5:0x3ffbc6b0 0x400e2727:0x3ffbc6d0 0x40087676:0x3ffbc6f0 0x400861e1:0x3ffbc710

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
Starting...
LoRa init succeeded.

Decoded backtrace:

Decoding stack results
0x400d20a9: Print::println(char const*) at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\Print.cpp line 196
0x400d20a9: Print::println(char const*) at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\Print.cpp line 196
0x400d0ead: onPackageReceive(int) at D:\Users\pepe\Desktop\arduino\sketch_nov06a/sketch_nov06a.ino line 70
0x400d14f9: LoRaClass::handleDio0Rise() at C:\Users\Pepe\Documents\Arduino\libraries\LoRa\src\LoRa.cpp line 704
0x40080eba: LoRaClass::onDio0Rise() at C:\Users\Pepe\Documents\Arduino\libraries\LoRa\src\LoRa.cpp line 760
0x40080f05: __onPinInterrupt at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\esp32-hal-gpio.c line 220
0x40080ee5: __onPinInterrupt at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\esp32-hal-gpio.c line 226
0x400e2727: esp_vApplicationIdleHook at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/freertos_hooks.c line 63
0x40087676: prvIdleTask at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c line 3382
0x400861e1: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

I would really appreciate if someone could help me.

Kongduino commented 2 years ago

Hi,

First I took the liberty to clean up your code to make it more legible. Note that it's better to read the full packet first, and then deal with its contents. You want to flush the buffer anyway.

#include <SPI.h>
#include <LoRa.h>

//====== Defining Pins =============
#define RF_RST  22
#define RF_CS   15
#define RF_SCK  18
#define RF_MOSI 23
#define RF_MISO 19
#define RF_IRQ  11
//==================================

SPIClass hspi = NULL;
byte localAddress = 0x00;

void setup() {
  Serial.begin(115200);
  Serial.println("Starting...");
  //========================== Initalizing Radio SPI ==================================
  hspi = SPIClass(HSPI);
  LoRa.setSPI(hspi);
  LoRa.setPins(RF_CS, RF_RST, RF_IRQ);// set CS, reset, IRQ pin
  if (!LoRa.begin(868E6)) Serial.println("LoRa init failed. Check your connections.");
  //============================== MY ADDRESS =========================================
  localAddress = 0x02;
  //===================================================================================
  LoRa.setTxPower(5);
  Serial.println("LoRa init succeeded.");
  LoRa.onReceive(onPackageReceive);
  LoRa.receive();
  //===================================================================================
}

void loop() {
  delay(100);
}

void onPackageReceive(int packetSize) {
  if (packetSize) {
    Serial.println("Received packet");
    char buff[16];
    memset(buff, 0, 16);
    int ix = 0;
    while (LoRa.available()) {
      char c = (char)LoRa.read();
      buff[ix++] = c;
    }
    byte to = buff[0];
    if (to == localAddress || to == 0xff) {
      byte type = buff[1];
      byte from = buff[2];
      Serial.println("============== Package Received ==============");
      Serial.print("   To: "); Serial.println(to, HEX);
      Serial.print("   From: "); Serial.println(from, HEX);
      Serial.print("   Type: "); Serial.println(type, HEX);
      Serial.print("   RSSI: "); Serial.println(LoRa.packetRssi());
      Serial.println("=============================================");
      if (type == 0x02) {
        sendPackage(from, 0x03);
        Serial.println("Sent!");
      }
    }
  }
}

void sendPackage(byte destination, byte type) {
  LoRa.beginPacket();
  LoRa.write(destination);
  LoRa.write(type);
  LoRa.write(localAddress);
  LoRa.endPacket();
  LoRa.receive();
  Serial.println("=============# Package Sent #=============");
  Serial.print("   To: "); Serial.println(destination, HEX);
  Serial.print("   From: "); Serial.println(localAddress, HEX);
  Serial.print("   Package Type: "); Serial.println(type, HEX);
  Serial.println("==========================================");
}

Now the error points to Serial.println("Sent!");, which is weird at best... "Sent!" does indeed get printed, as we can see in the Serial Monitor output...

0x400d20a9: Print::println(char const*) at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\Print.cpp line 196
0x400d20a9: Print::println(char const*) at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\Print.cpp line 196
0x400d0ead: onPackageReceive(int) at D:\Users\pepe\Desktop\arduino\sketch_nov06a/sketch_nov06a.ino line 70

So the crash happens on line 196 of Print.cpp:

193 size_t Print::println(const char c[])
194 {
195     size_t n = print(c);
196     n += println();  // <-------- Say whu'?
197     return n;
198 }

There's nothing there that warrants throwing a fit. What happens if you remove altogether Serial.println("Sent!");, or move it to the sendPackage() routine? Does it still break?

PepeProf commented 2 years ago

First of all, thank you for replying!

It is kinda strange, if I remove every Serial.print then it throws:

Decoding stack results

0x400d1265: LoRaClass::receive(int) at C:\Users\Pepe\Documents\Arduino\libraries\LoRa\src\LoRa.cpp line 418
0x400d0d77: sendPackage(unsigned char, unsigned char) at D:\Users\pepe\Desktop\arduino\sketch_nov06a/sketch_nov06a.ino line 75
0x400d0ded: onPackageReceive(int) at D:\Users\pepe\Desktop\arduino\sketch_nov06a/sketch_nov06a.ino line 61
0x400d145f: LoRaClass::handleDio0Rise() at C:\Users\Pepe\Documents\Arduino\libraries\LoRa\src\LoRa.cpp line 721
0x400d1419: LoRaClass::handleDio0Rise() at C:\Users\Pepe\Documents\Arduino\libraries\LoRa\src\LoRa.cpp line 704
0x40080eba: LoRaClass::onDio0Rise() at C:\Users\Pepe\Documents\Arduino\libraries\LoRa\src\LoRa.cpp line 760
0x40080f05: __onPinInterrupt at C:\Users\Pepe\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\esp32-hal-gpio.c line 220

But if I also remove LoRa.receive() from sendPackage(byte destination, byte type), then it works which cannot believe because I am sure that I've tried that before.... 🤔 I think that little modification in the code did the trick! But I need to put it in receive mode after the onPackageReceive function runs.

Is it possible to put LoRa.receive() in the function without crashing the whole ESP? Or how would you do that?

Kongduino commented 2 years ago

I suspect that the LoRa.receive() happens too quickly after LoRa.endPacket(). Maybe try to do LoRa.endPacket(false); first (instead of LoRa.endPacket();, to see if that helps: looking at the source code, it seems the code doesn't necessarily wait for the Tx process to be done before closing up.

int LoRaClass::endPacket(bool async) {
    if ((async) && (_onTxDone))
      writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE
  // put in TX mode
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);
  if (!async) {
    // wait for TX done
    while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
      yield();
    }
    // clear IRQs
    writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
  }
  return 1;
}

So asking endPacket() to wait could be a good idea. And possibly even adding a delay before LoRa.receive() too.

PepeProf commented 2 years ago

Hello, Unfortunately I was unable to put LoRa.receive() in the function, no matter how big delays I added, or add false to the function.

So what I did, that I modified the LoRa.cpp file a little:

ICACHE_RAM_ATTR int LoRaClass::endPacket(bool async)
{

  if ((async) && (_onTxDone))
      writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE

  // put in TX mode
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);

  if (!async) {
    // wait for TX done
    while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {}
    // clear IRQ's
    writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
    //Modified part:
    delay(1);
    writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE
    writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
  }

  return 1;
}

And now, I don't have to care about adding LoRa.receive() anywhere in the code, because it will automatically go back to receive mode after a packet is sent.

So thank you for helping me!

Kongduino commented 2 years ago

Hacking the library is always iffy, as the next update will wipe it out. But that looks like it's worth a PR. Great job.