radio.startReceive() not working after a radio.startTransmit() with a Spreadingfactor of 10, 11 or 12 #1210
-
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:
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: Which also doesn't work, but it does avoid that receiving stops completely when I switch modes. To Reproduce 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 Additional info (please complete):
|
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 24 replies
-
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)? |
Beta Was this translation helpful? Give feedback.
-
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;
}
}
}
|
Beta Was this translation helpful? Give feedback.
-
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. |
Beta Was this translation helpful? Give feedback.
-
I have implemented ping-pong in my code now, and that also seems to work. But looking at the results of my own tranmission vs the pingp0ng transmissions it seems my own signal is a lot weaker (while the devices are 10 cm's apart) Ping Pong: My own: I suspect it has something to do with how I init the radio:
So I will migrate the ping-pong init to my own init to see if that improves the signal strength. The reason why I set this is actually because of the lilygo-documentation: https://github.com/Xinyuan-LilyGO/T-Echo
|
Beta Was this translation helpful? Give feedback.
-
Well I did some testing and it seems that it is related to time it takes my code (or the library) to switch from sending to receiving. When I transmit a message each 2 seconds (in my own code, not with ping-pong) with a spf of 12. The receiving end does miss the package. So as a test I switched my code to send a message each 5 seconds and then listen again, and then it works. So is there anyway for my code in RADIOLIB to know when radio->startReceive() is actually completed with the switch? I suspect that ping-pong works, because the two devices are actually waiting on eachother before sending, thus implicitly this switching time it taken care off. |
Beta Was this translation helpful? Give feedback.
-
I played around with various settings to reduce the time-on-air and now I am able to switch from send / receive if the time it takes is larger then the time-on-air.
This also means that I am not sure if this is an actual-bug in radio-lib or if it is as designed. What I can deduce from this experience is this: startTransmit() If the TimeOnAir exceeds the actual time it takes before startReceive() is called, no messages is received. If the TimeOnAir is quick enough, it works without issues. |
Beta Was this translation helpful? Give feedback.
Then please tell us, what is the time-on-air of your small packet at SF12?