Open JRAlvarez2017 opened 4 years ago
Interesting. How long is “too long”?
What is the packet length and SF/BW?
Packets are 30 to 70 bytes. Normally, It takes between 150 ms to 500 ms to ge the IRQ_TX_DONE_MASK. SF is 8, and BW is 250E3. I am using hardware interrupt (DI0). Sometimes, I am not sure 100% why, the endPacket() loop does not see/receive the IRQ_TX_DONE_MASK, and then the code never puts back the LoRA into receive mode. Consequently, packets do not arrive anymore. When there is a low flow of packets, it is not noticeable. However, when there are many packets flowing (easier to get two packets arriving at almost the same time), and several LoRa boards, there are higher chances that a DI0 interrupt is called in between the endPacket() lines of code, and it may create the problem. I opted for enable and disable the DI0 before or after lines of critical code, and it eliminates the issue. Of course, some packets will be lost, but it is better, because at least the LoRa board keeps on communicating (sending and receiving packets).
"then the code never puts back the LoRA into receive mode. Consequently, packets do not arrive anymore."
For me, after sending, I normally set to receive mode manually.
I noticed similar issue as described by @JRAlvarez2017. I'm using Lora Ra-02 with ESP8266 to send max 10 bytes every 10 seconds. After 2-3 days of sending messages method "LoRaClass::endPacket" started execution of "while" endless loop with "yield();" method:
if (!async) {
// wait for TX done
while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
yield(); // endless loop is exdecuted all the time
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
}
As a workaround I've started to use "endPacket" method asynchronously:
LoRa.endPacket(true);
Next I've marked "isTransmitting()" method as "public".
Now in my code I can send a message and wait defined time for end of the transmission:
LoRa.beginPacket();
LoRa.println(msg);
LoRa.endPacket(true); // true = async / non-blocking mode
int sendingCounter = 0;
delay(50); // Without this delay the first isTransmitting() will return "false" and "while" is ommited
// Checking for end of transimission for maximum 1 second
while (LoRa.isTransmitting() == true) {
sendingCounter++;
Serial.print(".");
delay(10);
if(sendingCounter == 100) {
Serial.println("\nLora sending error");
break;
}
}
Please consider to add timeout for "LoRaClass::endPacket" method if it is executed synchronously.
@PrzemyslawMotyl , @JRAlvarez2017 Any idea why the while loop does not stop after TX Done?
while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
yield(); // endless loop is exdecuted all the time
}
I don't know maybe this is hardware issue.
Hi dears, I have same problem as you mentioned. I have good communication But after a while the receiver can't receive anything. I changing the code as you said but it was like before. what it the problem? I have confused about it. the code is completely correct but why it stop to receive after some hours?
Hi,
What LoRa settings do you have? I used 1 second timeout because I set LoRa to send small amount of data in a short time.
LoRa.setSpreadingFactor(12);
LoRa.setSignalBandwidth(62.5E3 );
LoRa.setCodingRate4(8);
LoRa.setTxPower(6); // Try to used low TX power also
LoRa.enableCrc();
Here you can increase this timeout. Try to use 10 seconds:
if(sendingCounter == 1000) {
Serial.println("\nLora sending error");
break;
}
I'm using strong 433 antennas and I had to decrease TX power also. Without this also I had problems. After I posted this problem and use library modification I didn't have any problems with LoRa since January 2021.
Regards, Przemek
hi @PrzemyslawMotyl . I did that but it stop to receive after 15-16 hours. how can I marked "isTransmitting()" method as "public"? Just moving it in public? Arduino say its no declare. I just put "isTransmitting()" in the LoRa.endpacket() loop. here is my library:
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
int sendingCounter = 0;
delay(50); // Without this delay the first isTransmitting() will return "false" and "while" is ommited
// Checking for end of transimission for maximum 1 second
while (LoRa.isTransmitting() == true) {
sendingCounter++;
delay(10);
if(sendingCounter == 1000) {
break;
}
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
}
return 1;
}
In LoRa.h just put "isTransmitting" in "public" section:
class LoRaClass : public Stream {
public:
LoRaClass();
int begin(long frequency);
void end();
int beginPacket(int implicitHeader = false);
int endPacket(bool async = false);
int parsePacket(int size = 0);
int packetRssi();
float packetSnr();
long packetFrequencyError();
int rssi();
// from Print
virtual size_t write(uint8_t byte);
virtual size_t write(const uint8_t *buffer, size_t size);
// from Stream
virtual int available();
virtual int read();
virtual int peek();
virtual void flush();
#ifndef ARDUINO_SAMD_MKRWAN1300
void onReceive(void(*callback)(int));
void onTxDone(void(*callback)());
void receive(int size = 0);
#endif
void idle();
void sleep();
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
void setFrequency(long frequency);
void setSpreadingFactor(int sf);
void setSignalBandwidth(long sbw);
void setCodingRate4(int denominator);
void setPreambleLength(long length);
void setSyncWord(int sw);
void enableCrc();
void disableCrc();
void enableInvertIQ();
void disableInvertIQ();
void setOCP(uint8_t mA); // Over Current Protection control
void setGain(uint8_t gain); // Set LNA gain
// deprecated
void crc() { enableCrc(); }
void noCrc() { disableCrc(); }
byte random();
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
void setSPI(SPIClass& spi);
void setSPIFrequency(uint32_t frequency);
void dumpRegisters(Stream& out);
// Mark "isTransmitting" as "public"
bool isTransmitting();
private:
void explicitHeaderMode();
void implicitHeaderMode();
...
This Issue still persists. I added some Serial.println(""); statements and i got stuck at yield too. This is my current code for the while() loop in the endPacket() function:
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();
Serial.print("REG_IRQ_FLAGS: ");
Serial.println(readRegister(REG_IRQ_FLAGS), HEX);
Serial.print("IRQ_TX_DONE_MASK: ");
Serial.println(readRegister(IRQ_TX_DONE_MASK), HEX);
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
}
return 1;
}
This is my output for the read registers:
REG_IRQ_FLAGS: 15
IRQ_TX_DONE_MASK: 0
Value 0x15 in REG_IRQ_FLAGS seems to be the reset for the IRQs. The Bits that are set in the register are: CadDetected CadDone ValidHeader
All of them say "Writing a 1 clears the IRQ." Doesnt seem to do it.
EDIT: This doesnt seem to make sense. The #define on the top of the library states that the IRQ_TX_DONE_MASK should be 0x08, while my Arduino outputs 0x0.
Update: My OP-Mode actually changes after the TX-Mode to a Non-LoRa-Mode. It unsets the upper bit in the OP-Register.
My 2nd, identical transmitter doesn't do this.
If i run the library with debug output on Arduino 1 (working one)
20:56:58.910 -> [LIB] : ENDING PACKET...
20:56:58.955 -> REG_IRQ_FLAGS & IRQ_TX_DONE_MASK: 0
20:56:59.000 -> REG_IRQ_FLAGS: 8
20:56:59.000 -> IRQ_TX_DONE_MASK: 0
20:56:59.045 -> OP-MODE:81
20:56:59.045 -> [LIB] : END PACKET DONE
On the Arduino 2 (not working) it says this:
[LIB] : ENDING PACKET...
REG_IRQ_FLAGS & IRQ_TX_DONE_MASK: 0
REG_IRQ_FLAGS: 15
IRQ_TX_DONE_MASK: 0
OP-MODE:81
REG_IRQ_FLAGS & IRQ_TX_DONE_MASK: 0
REG_IRQ_FLAGS: 15
IRQ_TX_DONE_MASK: 0
OP-MODE:9
While it not only resets OP-Mode to 0x09, it also seems to have a different REG_IRQ_FLAGS register with 0x15 instead of like Arduino 1 has (0x8). It changed from LongRangeMode = 1, Mode = 1 (Standby) to LowFrequencyModeOn = 1, Mode = 1 (Standby).
EDIT:
I just realised i used the readRegister() function for outputting the #define variable. Still, the TxDone bit it not set. If I set it manually , it does not continue to normal operation.
I noticed that sometimes , the while loop in the endPacket() function takes too long. I think there should be a time-out inside the loop to break. Here I wrote an example of just an idea of how to dodge the problem.
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 delay(10); unsigned int i = 0; while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { delay(5); if (i++ > 1000) break; } // clear IRQ's writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); }
return 1; }