jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.54k stars 384 forks source link

ESP8266 hangs using SX127x_Receive_Interrupt example #234

Closed HamzaHajeir closed 3 years ago

HamzaHajeir commented 3 years ago

Describe the bug I'm using SX127x_Receive_Interrupt example to react in non-blocking mode, I'm using ESP8266 NodeMCU. The module works well in Receive mode (without interrupt).

When interrupt is activated, the module (ESP8266) just shuts off (I don't really know what happens there). The Builtin LEDs just turns off.

The hang/shut occurs when the message is sent from the other side.

NodeMCU can be rebooted through reset pin. Note : I can verify it's not a problem in interrupt by trying to touch D0 with 3.3V.

Wiring

Ra-01 (SX1278) | NodeMCU NSS to D1 DIO0 to D0 RESET to D2 DIO1 to SD3 SCK to D5 MISO to D6 MOSI to D7

ESP8266 Arduino Core : 2.7.1 Configurations : image

To Reproduce

// include the library
#include <RadioLib.h>
#define D1  5
#define D0 16
#define D2 4

const int csPin = D1;    // LoRa radio chip select
const int resetPin = D2; // LoRa radio reset
const int irqPin = D0;   // change for your board; must be a hardware interrupt pin
const int DIO1 = 10;     // change for your board; must be a hardware interrupt pin
const int DIO0 = irqPin; // change for your board; must be a hardware interrupt pin

// SX1278 has the following connections:
// NSS pin:   5 D1
// DIO0 pin:  16 D0
// RESET pin: 4 :D2
// DIO1 pin:  10 SD3
//SCK : D5
//MISO : D6
//MOSI : D7
SX1278 radio = new Module(csPin, DIO0, resetPin, DIO1);

void setup() {
  Serial.begin(115200);

  // initialize SX1278 with default settings
  Serial.print(F("[SX1278] Initializing ... "));
    int state = radio.begin(434.0f,125.0f,7);
  if (state == ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // set the function that will be called
  // when new packet is received
  radio.setDio0Action(setFlag);

  // start listening for LoRa packets
  Serial.print(F("[SX1278] Starting to listen ... "));
  state = radio.startReceive();
  if (state == ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // if needed, 'listen' mode can be disabled by calling
  // any of the following methods:
  //
  // radio.standby()
  // radio.sleep()
  // radio.transmit();
  // radio.receive();
  // radio.readData();
  // radio.scanChannel();
}

// flag to indicate that a packet was received
volatile bool receivedFlag = false;

// disable interrupt when it's not needed
volatile bool enableInterrupt = true;

// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
ICACHE_RAM_ATTR void setFlag(void) {
  // check if the interrupt is enabled
  if(!enableInterrupt) {
    return;
  }

  // we got a packet, set the flag
  receivedFlag = true;
}

void loop() {
  // check if the flag is set
  if(receivedFlag) {
    // disable the interrupt service routine while
    // processing the data
    enableInterrupt = false;

    // reset flag
    receivedFlag = false;

    // you can read received data as an Arduino String
    String str;
    int state = radio.readData(str);

    // you can also read received data as byte array
    /*
      byte byteArr[8];
      int state = radio.readData(byteArr, 8);
    */

    if (state == ERR_NONE) {
      // packet was successfully received
      Serial.println(F("[SX1278] Received packet!"));

      // print data of the packet
      Serial.print(F("[SX1278] Data:\t\t"));
      Serial.println(str);

      // print RSSI (Received Signal Strength Indicator)
      Serial.print(F("[SX1278] RSSI:\t\t"));
      Serial.print(radio.getRSSI());
      Serial.println(F(" dBm"));

      // print SNR (Signal-to-Noise Ratio)
      Serial.print(F("[SX1278] SNR:\t\t"));
      Serial.print(radio.getSNR());
      Serial.println(F(" dB"));

      // print frequency error
      Serial.print(F("[SX1278] Frequency error:\t"));
      Serial.print(radio.getFrequencyError());
      Serial.println(F(" Hz"));

    } else if (state == ERR_CRC_MISMATCH) {
      // packet was received, but is malformed
      Serial.println(F("[SX1278] CRC error!"));

    } else {
      // some other error occurred
      Serial.print(F("[SX1278] Failed, code "));
      Serial.println(state);

    }

    // put module back to listen mode
    radio.startReceive();

    // we're ready to receive more packets,
    // enable interrupt service routine
    enableInterrupt = true;
  }

}

Serial output

M   SX127x
R   1   9   
W   1   9   
R   1   9   
R   1   9   
R   1   9   
W   1   8   
R   1   8   
R   1   8   
W   1   88  
R   1   88  
R   1   88  
W   1   89  
R   1   89  
R   1   89  
R   1   89  
W   1   89  
R   1   89  
R   39  12  
W   39  12  
R   39  12  
R   1   89  
W   1   89  
R   1   89  
R   B   2B  
W   B   23  
R   B   23  
R   1   89  
W   1   89  
R   1   89  
R   1   89  
R   20  0   
W   20  0   
R   20  0   
R   21  8   
W   21  8   
R   21  8   
R   24  0   
W   24  0   
R   24  0   
R   1   89  
R   1   89  
W   1   89  
R   1   89  
R   6   6C  
W   6   6C  
R   6   6C  
R   7   80  
W   7   80  
R   7   80  
R   8   0   
W   8   0   
R   8   0   
R   1   89  
R   1   89  
W   1   89  
R   1   89  
R   1D  72  
W   1D  72  
R   1D  72  
Symbol length: 0.01 ms
R   26  4   
W   26  4   
R   26  4   
R   1   89  
R   1   89  
W   1   89  
R   1   89  
R   1D  72  
W   1D  72  
R   1D  72  
R   1E  70  
W   1E  70  
R   1E  70  
R   31  C3  
W   31  C3  
R   31  C3  
R   37  A   
W   37  A   
R   37  A   
Symbol length: 1.02 ms
R   26  4   
W   26  4   
R   26  4   
R   1   89  
R   1   89  
W   1   89  
R   1   89  
R   1D  72  
W   1D  76  
R   1D  76  
R   1   89  
W   1   89  
R   1   89  
R   9   4F  
W   9   CF  
R   9   CF  
R   9   CF  
W   9   F8  
R   9   F8  
R   4D  84  
W   4D  84  
R   4D  84  
R   1   89  
R   1   89  
W   1   89  
R   1   89  
R   26  4   
W   26  4   
R   26  4   
success!
[SX1278] Starting to listen ... R   1   89  
W   1   89  
R   1   89  
R   1   89  
R   40  0   
W   40  0   
R   40  0   
R   1   89  
W   12  FF  
R   F   0   
W   F   0   
R   F   0   
R   D   0   
W   D   0   
R   D   0   
R   1   89  
W   1   8D  
R   1   8D  
success!

Additional info (please complete):

jgromes commented 3 years ago

When interrupt is activated, the module (ESP8266) just shuts off (I don't really know what happens there).

Sounds like not an issue in the library then - on ESP8266, if the software hangs, the internal watchdog resets it. If no reset occurs, then it looks like more of a hardware issue.

The Builtin LEDs just turns off

Maybe there's a pin collision then? I haven't used NodeMCU before.

Note : I can verify it's not a problem in interrupt by trying to touch D0 with 3.3V.

So you tied D0 to 3V3 and what happened then? Did the interrupt not occur? Did it occur but didn't hang? Keep in mind that the interrupt is edge-sensitive, if you literally just "touched" D0 with a wire connected to 3.3V, there will be at least several dozen edges and it will likely trigger the interrupt more than once.

HamzaHajeir commented 3 years ago

Sounds like not an issue in the library then - on ESP8266, if the software hangs, the internal watchdog resets it. If no reset occurs, then it looks like more of a hardware issue.

I can't agree nor disagree.

So you tied D0 to 3V3 and what happened then? Did the interrupt not occur? Did it occur but didn't hang? Keep in mind that the interrupt is edge-sensitive, if you literally just "touched" D0 with a wire connected to 3.3V, there will be at least several dozen edges and it will likely trigger the interrupt more than once.

That's right, The interrupt just gets served without MCU gets 'hanged'.

I'll investigate more to the issue. and update with results/news.

HamzaHajeir commented 3 years ago

It 'could' be ESP8266 pin interrupt not available on D0.

If DIO0 is to inform for 'packet sent'/'packet received', What does DIO1 do ? Is it necessary to provide the library with ?

jgromes commented 3 years ago

Surely if D0 didn't support external interrupt, you wouldn't have been able to trigger it manually.

DIO1 is used in blocking receive and in channel activity detection to get the timeout event, it doesn't have to be used for interrupt receive (but it also shouldn't affect anything).

HamzaHajeir commented 3 years ago

I don't know whether this is a new issue or we can continue here.

I've the other end node runs on another library, However When configurations are identical and equals to RadioLib default configurations, It received perfectly. Configurations include :

When I Activate CRC at both sides, Receiver (ESP8266 running RadioLib) doesn't receive.

But it received successfully when I put this line radio.setDio0Action(setFlag); in the setup().

The code becomes :

#include <RadioLib.h>
#define D1  5
#define D0 16
#define D2 4

const int csPin = D1;    // LoRa radio chip select
const int resetPin = D2; // LoRa radio reset
const int irqPin = D0;   // change for your board; must be a hardware interrupt pin
const int DIO1 = 10;     // change for your board; must be a hardware interrupt pin
const int DIO0 = irqPin; // change for your board; must be a hardware interrupt pin

// SX1278 has the following connections:
// NSS pin:   5 D1
// DIO0 pin:  16 D0
// RESET pin: 4 :D2
// DIO1 pin:  10 SD3
SX1278 radio = new Module(csPin, DIO0, resetPin, DIO1);

// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1278 radio = RadioShield.ModuleA;

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);

  // initialize SX1278 with default settings
  Serial.print(F("[SX1278] Initializing ... "));
  radio.setCRC(true);
  int state = radio.begin();
  if (state == ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  radio.setDio0Action(setFlag);

}

void loop() {
  Serial.print(F("[SX1278] Waiting for incoming transmission ... "));

  // you can receive data as an Arduino String
  // NOTE: receive() is a blocking method!
  //       See example ReceiveInterrupt for details
  //       on non-blocking reception method.
  String str;
  int state = radio.receive(str);

  // you can also receive data as byte array
  /*
    byte byteArr[8];
    int state = radio.receive(byteArr, 8);
  */

  if (state == ERR_NONE) {
    // packet was successfully received
    Serial.println(F("success!"));

    // print the data of the packet
    Serial.print(F("[SX1278] Data:\t\t\t"));
    Serial.println(str);

    // print the RSSI (Received Signal Strength Indicator)
    // of the last received packet
    Serial.print(F("[SX1278] RSSI:\t\t\t"));
    Serial.print(radio.getRSSI());
    Serial.println(F(" dBm"));

    // print the SNR (Signal-to-Noise Ratio)
    // of the last received packet
    Serial.print(F("[SX1278] SNR:\t\t\t"));
    Serial.print(radio.getSNR());
    Serial.println(F(" dB"));

    // print frequency error
    // of the last received packet
    Serial.print(F("[SX1278] Frequency error:\t"));
    Serial.print(radio.getFrequencyError());
    Serial.println(F(" Hz"));

  } else if (state == ERR_RX_TIMEOUT) {
    // timeout occurred while waiting for a packet
    Serial.println(F("timeout!"));

  } else if (state == ERR_CRC_MISMATCH) {
    // packet was received, but is malformed
    Serial.println(F("CRC error!"));

  } else {
    // some other error occurred
    Serial.print(F("failed, code "));
    Serial.println(state);

  }
}

// flag to indicate that a packet was received
volatile bool receivedFlag = false;

// disable interrupt when it's not needed
volatile bool enableInterrupt = true;

// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
ICACHE_RAM_ATTR void setFlag(void) {
  // check if the interrupt is enabled
  if (!enableInterrupt) {
    return;
  }

  // we got a packet, set the flag
  receivedFlag = true;
}

That could bring 2 things :

  1. Interrupt works well on D0
  2. There's some kind of issue in the library (A guess ?)

What do you think ?

I'm now enabling crc in receive with interrupt example, I'll update very soon

UPDATE

Please dismiss any information given that interrupt could be attached to D0. It's not.

HamzaHajeir commented 3 years ago

Reordered pins, And works well now. If there's an issue it was the mentioned in my last comment (Enabling CRC requires setDIO0Flag()), That one can replicate easily, If not replicated, It's my incorrect setup again :) .

Regarding DIO1, Would it needs to be attached to an interruptible-pin ?

For Now I don't think there's a valid reason to let this issue opened. Closing.. Thanks for your kindly help @jgromes :)

jgromes commented 3 years ago

Enabling CRC requires setDIO0Flag()

That seems very strange - by calling setDio0Flag() in blocking mode you attach interrupt to the DIO0 pin and only break out of the blocking wait loop to execute the ISR (which does nothing), so there should be no reason why that would be required to get CRC working.

What's the other library you have used? Does this happen when RadioLib is transmitting too? And what does "doesn't receive" mean in the previous sketch? Never receives any packets, hangs, or prints CRC errors?

DIO1 doesn't need an interrupt pin, it's only used in blocking loops.

HamzaHajeir commented 3 years ago

That seems very strange - by calling setDio0Flag() in blocking mode you attach interrupt to the DIO0 pin and only break out of the blocking wait loop to execute the ISR (which does nothing), so there should be no reason why that would be required to get CRC working.

You're right, That's strange.

What's the other library you have used? Does this happen when RadioLib is transmitting too? And what does "doesn't receive" mean in the previous sketch? Never receives any packets, hangs, or prints CRC errors?

I mean by receiving : never receives any packet.

I'm exhausted trying to receive in the other end from this one, Could this library be ported to STM32CubeIDE using HAL ? and How ?

The other library is this one : https://github.com/wdomski/SX1278

HamzaHajeir commented 3 years ago

My last issue (not receiving in the other end) could be an incorrect transmitter code. Trying to use interrupt while sending and receiving.