jgromes/RadioLib

radio.startReceive() not working after a radio.startTransmit() with a Spreadingfactor of 10, 11 or 12

goedzo opened this issue · 3 comments

I am implementing the non-blocking functions for sending and receiving and I wanted to allow receiving immediately after sending (as with the ping-pong example).

I use this logic:

radio.setDio1Action(setFlag);
radio.startTransmit(
-- Wait until flag is set for succesfull completion (via setFlag)
-- After transmit is done ->
radio.startReceive(
-- Handle new incoming messages

This went fine, until I noticed that in some cases, after sending a message, it was impossible to receive any new messages. I was only able to get this going (in some case) by calling setupLoRa() and wait for a couple of seconds for everything to be reinitialized.

After a lot of debugging I found out that when I use a lower spreadingfacter then 10, all went good. So 10, 11 or 12, causes the error that startReveice does not receive anything anymore. I did notice that sometimes an SF of 10 works intermittently, so I except there is some kind of timing issue where sending a message with a bigger spreadingfactor takes too much time for the module to switch to receiving (or something like that).

I tried a lot of ways to make it work again, and my best workaround is now:
radio.sleep(true);
radio.standby();
radio.startReceive(); //Start after processing, otherwise the packet is cleared before reading

Which also doesn't work, but it does avoid that receiving stops completely when I switch modes.

To Reproduce
Minimal Arduino sketch to reproduce the behavior. Please use Markdown to style the code to make it readable (see Markdown Cheatsheet).

void checkLoraPacketComplete(){
    if(operationDone) {
        //Serial.println("checkLoraPacketComplete - Lora Action complete");
        // reset flag
        operationDone = false;
        if(transmitFlag) {
            transmitFlag = false;        

            Serial.println("SENT COMPLETE");
            uint16_t irqStatus = radio.getIrqStatus();
            if (irqStatus & RADIOLIB_SX126X_IRQ_TX_DONE) {
              //Serial.println(F("Transmission successful!"));
            }
            else {
              Serial.println(F("Transmission not done!!"));
            }


            int state = radio.finishTransmit();

            if (state == RADIOLIB_ERR_NONE) {
                // We have sent a package, so listen again
            } 
            else {
              Serial.print(F("Sent failed, code "));
              char buf[50];
              snprintf(buf, sizeof(buf), "Sent Err: %d", state);
              showError(buf);
              Serial.println(state);
            }

            /* THE ERROR HAPPENS HERE WHEN SPREADING FACTOR IS 11 or 12 */
            radio.sleep(true);
            radio.standby();
            radio.startReceive(); //Start after processing, otherwise the packet is cleared before reading

        }
        else {
            Serial.println("RECEIVE COMPLETE");
            handlePacket();
            radio.startReceive(); //Start after processing, otherwise the packet is cleared before reading
        }
    }
}
Sketch that is causing the module fail

#include "delay.h"
#include "utilities.h"
#include <SPI.h>
#include <GxEPD.h>
#include <GxDEPG0150BN/GxDEPG0150BN.h>  // 1.54" b/w
#include <RadioLib.h>

#include <stdint.h>
#include "settings.h"  // Include settings.h to use global variables
#include "display.h"
#include "app_modes.h"  // Include settings.h to use global variables
#include "lora.h"

SX1262 radio = nullptr;       //SX1262
SPIClass        *rfPort    = nullptr;

// flag to indicate that a packet was sent or received
volatile bool operationDone = false;
// flag to indicate transmission or reception state
bool transmitFlag = false;

void setFlag(void) {
  // we sent or received a packet, set the flag
  operationDone = true;
  //Serial.println("setFlag - Lora Action complete");
}

void checkLoraPacketComplete(){
    if(operationDone) {
        //Serial.println("checkLoraPacketComplete - Lora Action complete");
        // reset flag
        operationDone = false;
        if(transmitFlag) {
            transmitFlag = false;        

            Serial.println("SENT COMPLETE");
            uint16_t irqStatus = radio.getIrqStatus();
            if (irqStatus & RADIOLIB_SX126X_IRQ_TX_DONE) {
              //Serial.println(F("Transmission successful!"));
            }
            else {
              Serial.println(F("Transmission not done!!"));
            }


            int state = radio.finishTransmit();

            if (state == RADIOLIB_ERR_NONE) {
                // We have sent a package, so listen again
            } 
            else {
              Serial.print(F("Sent failed, code "));
              char buf[50];
              snprintf(buf, sizeof(buf), "Sent Err: %d", state);
              showError(buf);
              Serial.println(state);
            }

            //Let's reset lora to get receiving again
            radio.sleep(true);
            radio.standby();
            radio.startReceive(); //Start after processing, otherwise the packet is cleared before reading

        }
        else {
            Serial.println("RECEIVE COMPLETE");
            handlePacket();
            radio.startReceive(); //Start after processing, otherwise the packet is cleared before reading
        }
    }
}

bool setupLoRa() {
    rfPort = new SPIClass(
        /*SPIPORT*/NRF_SPIM3,
        /*MISO*/ LoRa_Miso,
        /*SCLK*/LoRa_Sclk,
        /*MOSI*/LoRa_Mosi);
    rfPort->begin();

    SPISettings spiSettings;

    radio = new Module(LoRa_Cs, LoRa_Dio1, LoRa_Rst, LoRa_Busy, *rfPort, spiSettings);

    SerialMon.print("[SX1262] Initializing ...  ");
    // carrier frequency:           868.0 MHz
    // bandwidth:                   125.0 kHz
    // spreading factor:            9
    // coding rate:                 7
    // sync word:                   0x12 (private network)
    // output power:                14 dBm
    // current limit:               60 mA
    // preamble length:             8 symbols
    // TCXO voltage:                1.6 V (set to 0 to not use TCXO)
    // regulator:                   DC-DC (set to true to use LDO)
    // CRC:                         enabled
    int state = radio.begin(868.0);
    if (state != ERROR_NONE) {
        SerialMon.print(("failed, code "));
        SerialMon.println(state);

        char buf[30];
        snprintf(buf, sizeof(buf), "Lora failed to init: %d", state);
        showError(buf);
        return false;
    }

    // set the function that will be called
    // when new packet is received
    operationDone=false;
    radio.setDio1Action(setFlag);



    // Stel de spreading factor in met de opgegeven waarde
    state = radio.setSpreadingFactor(deviceSettings.spreading_factor);
    if (state == RADIOLIB_ERR_NONE) {
        Serial.print(F("Spreading factor set to SF"));
        Serial.println(deviceSettings.spreading_factor);
    } else {
        Serial.print(F("Failed to set spreading factor, code "));
        Serial.println(state);
    }

    // Stel het zendvermogen in (tussen -17 en 22 dBm)
    if (radio.setOutputPower(22) == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
        Serial.println(F("Selected output power is invalid for this module!"));
        return false;
    }

    // Stel de stroomlimiet in (tussen 45 en 240 mA)
    if (radio.setCurrentLimit(80) == RADIOLIB_ERR_INVALID_CURRENT_LIMIT) {
        Serial.println(F("Selected current limit is invalid for this module!"));
        return false;
    }


    // Start non-blocking receive
    radio.startReceive();

    Serial.println(F("LoRa setup completed successfully!"));
    return true;
}


void sendPacket(uint8_t* pkt_buf, uint16_t len) {
    // Start non-blocking transmission
    int state = radio.startTransmit(pkt_buf, len);
    transmitFlag = true;

    if (state != RADIOLIB_ERR_NONE) {
        Serial.print(F("Transmission start failed, code "));
        Serial.println(state);
        char buf[50];
        snprintf(buf, sizeof(buf), "Lora Strt Trnsmt Err: %d", state);
        showError(buf);
        //Let's reinitialize the radio
        setupLoRa();
        return;
    }
}



int receivePacket(uint8_t* pkt_buf, uint16_t max_len) {

    // Get the length of the received packet
    uint16_t packet_len = radio.getPacketLength(false);
    
    if(packet_len==0) {
        return 0;
    }

    if (packet_len > max_len) {
        // Prevent buffer overflow if the packet is larger than the provided buffer
        packet_len = max_len;
    }

    //Let's check the IRQ status to make sure all data is actually received
    uint16_t irqStatus = radio.getIrqStatus();
    if (irqStatus & RADIOLIB_SX126X_IRQ_RX_DONE) {
        // Read the data into the buffer
        int state = radio.readData(pkt_buf, packet_len);

        if (state == RADIOLIB_ERR_NONE) {
            return packet_len;  // Of de werkelijke grootte van het ontvangen pakket
        } else {
            if (state == RADIOLIB_ERR_RX_TIMEOUT ) {
                //This is OK, no data was received
            }
            else {
                Serial.print(F("Receive failed, code "));
                char buf[50];
                snprintf(buf, sizeof(buf), "Receive Err: %d", state);
                showError(buf);
                Serial.println(state);
            }
            return 0;
        }
    }
    else {
      return 0;
    }
}

void sleepLoRa() {
    // Put the LoRa module into sleep mode using RadioLib's sleep function
    int state = radio.sleep();
    if (state == RADIOLIB_ERR_NONE) {
        Serial.println(F("LoRa module is now in sleep mode."));
    } else {
        char buf[50];
        snprintf(buf, sizeof(buf), "LoRa Sleep Error: %d", state);
        showError(buf);  // Show error for LoRa sleep failure
    }
}

Expected behavior
radio.startReceive() should be receiving messages again after sending a message with a SPF of 10,11 or 12

Additional info (please complete):

I was not able to reproduce this behavior using the stock PingPong example - I got reliable transmissions from both devices even at SF12, as can be seen in the waterfall below. Could you try to run the default example with minimum modifications (i.e. just your pinout and the spreading factor)?

Screenshot_102

Thanks for the test. I did the same and you are right, that the ping-pong example does work. I even removed the 1 second delay, and it still works.

So I have no idea why my original code stops receiving. Could it be the case that other stuff takes too long? The T-echo uses an e-paper display that needs quite some time (half a second) to update the screen. Maybe that can cause the issue? I will do some testing by removing the printing on screen when sending. But any suggestions or tips would be very welcome.

p.s. I did had to change some of the settings, and init to work on the t-echo. For reference my updated ping-pong code.

/*
   RadioLib SX126x Ping-Pong Example

   For default module settings, see the wiki page
   https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem

   For full API reference, see the GitHub Pages
   https://jgromes.github.io/RadioLib/
*/

// include the library
#include <RadioLib.h>
#include <SPI.h>

#ifndef _PINNUM
#define _PINNUM(port, pin)    ((port)*32 + (pin))
#endif


// uncomment the following only on one
// of the nodes to initiate the pings
#define INITIATING_NODE

SX1262 radio = nullptr;       //SX1262
SPIClass        *rfPort    = nullptr;





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

// or using CubeCell
//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);

// save transmission states between loops
int transmissionState = RADIOLIB_ERR_NONE;

// flag to indicate transmission or reception state
bool transmitFlag = false;

// flag to indicate that a packet was sent or received
volatile bool operationDone = false;

// this function is called when a complete packet
// is transmitted or received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
#if defined(ESP8266) || defined(ESP32)
  ICACHE_RAM_ATTR
#endif
void setFlag(void) {
  // we sent or received a packet, set the flag
  operationDone = true;
}

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.flush();
  // initialize SX1262 with default settings
  Serial.print(F("[SX1262] Initializing ... "));
  
  SPIClass        *rfPort    = nullptr;
  rfPort = new SPIClass(
      /*SPIPORT*/NRF_SPIM3,
      /*MISO*/ _PINNUM(0,23),
      /*SCLK*/_PINNUM(0,19),
      /*MOSI*/_PINNUM(0,22));
  rfPort->begin();

  SPISettings spiSettings;

  // SX1262 has the following connections:
  // NSS pin:   10
  // DIO1 pin:  2
  // NRST pin:  3
  // BUSY pin:  9
  radio = new Module(_PINNUM(0,24),  _PINNUM(0,20), _PINNUM(0,25) , _PINNUM(0,17),*rfPort,spiSettings);


  
  int state = radio.begin();
  if (state == RADIOLIB_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.setDio1Action(setFlag);
  radio.setSpreadingFactor(12);

  #if defined(INITIATING_NODE)
    // send the first packet on this node
    Serial.print(F("[SX1262] Sending first packet ... "));
    transmissionState = radio.startTransmit("Hello World!");
    transmitFlag = true;
  #else
    // start listening for LoRa packets on this node
    Serial.print(F("[SX1262] Starting to listen ... "));
    state = radio.startReceive();
    if (state == RADIOLIB_ERR_NONE) {
      Serial.println(F("success!"));
    } else {
      Serial.print(F("failed, code "));
      Serial.println(state);
      while (true);
    }
  #endif
}

void loop() {
  // check if the previous operation finished
  if(operationDone) {
    // reset flag
    operationDone = false;

    if(transmitFlag) {
      // the previous operation was transmission, listen for response
      // print the result
      if (transmissionState == RADIOLIB_ERR_NONE) {
        // packet was successfully sent
        Serial.println(F("transmission finished!"));

      } else {
        Serial.print(F("failed, code "));
        Serial.println(transmissionState);

      }

      // listen for response
      radio.startReceive();
      transmitFlag = false;

    } else {
      // the previous operation was reception
      // print data and send another packet
      String str;
      int state = radio.readData(str);

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

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

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

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

      }

      // wait a second before transmitting again
      //delay(1000);

      // send another one
      Serial.print(F("[SX1262] Sending another packet ... "));
      transmissionState = radio.startTransmit("Hello World!");
      transmitFlag = true;
    }
  
  }
}

I haven't seen the rest of your code, so I can't really comment whether the display updates could be causing some issues. Though it it does really take that long, then it would make sense to have a dedicated low-priority thread for it.

Since it is not an issue in the library, I will convert this into a discussion instead.