Closed GIPdA closed 3 years ago
I'm unable to replicate this as you've described. I modified the Sender example to send ~30 bytes
ever 2 seconds
and added a 100ms
delay to the Receiver example and I still receive every packet at around -110 RSSI
. What RSSI
levels are you seeing on the packets you do receive?
PS You should use triple ticks (```) for code blocks instead of a single
By adding LoRa.receive()
after LoRa.parsePacket()
(with the delay as above), I almost get every packet, but not reliably and the values are often wrong.
I have a RSSI around -30
with the sender 50cm away, and around -60
when 10m away (without added delay, just the Receive example).
I use a small 868MHz antenna connected to the UFL connector on the board.
I just tried with some other hardware for a receiver: STM32 with a SX1276 board. Same problem. The emitter didn't change.
What hardware are you using? And how do you get 110 RSSI
? I thought the values could only be negative...
I'm using the TTGO ESP32 board. Sorry, I meant -110
Ok, thanks. I still have the issue, I worked around it for now but I'm still looking for a solution. I reduced the blocking time to a minimum, but I'm still loosing some packets, after a while it stops receiving, and it may takes some time to start receiving (30s to 1 or 2min). Not very reliable.
The long blocking operation I have is driving an e-paper screen with the GxEPD lib. I thought the issue may be coming from a SPI conflict of some sort, but I couldn't find anything. And the simple serial feed loop for TinyGPS++ caused problems too. I'm out of ideas for now...
I will not be able to test anything for the next two weeks but I hope that a solution will arise in the meantime :P
If LoRa.parsePacket()
or LoRa.receive()
is not called periodically, the Semtec will exit receive mode from my understanding.
I would suggest you use the callback approach if you don't want to miss any packets.
Thanks for your answer. That seems to be the case indeed, but sounds strange that it works like that. Any idea how to change that?
The callback method works on interrupts, but what happens if I am in the middle of an other SPI transmission... there is no easy way to prevent concurrent access AFAIK.
Any idea how to change that?
You can change some of the code to enter continuous receive mode instead of single RX mode.
The callback method works on interrupts, but what happens if I am in the middle of an other SPI transmission... there is no easy way to prevent concurrent access AFAIK.
Good question, you'd have to do some testing to find the behaviour. There's some changes that could be made to wrap more operations in SPI transactions which block interrupts.
Another option would be to use noInterrupts()
and interrupts()
to disable them, not ideal but an option...
I'm back! :p Took some time, but I found a suitable solution.
In "packet" mode, the module is configured in RX Single: it waits for one packet or a timeout, then goes back to Standby. This timeout is what's important. On the Lora modules sx127x, the register is SymbTimeout and its value can range from 4 to 1023 symbols. The lib doesn't currently set this register.
The parsePacket() method checks if the module is in RX mode or not and put it back if not. If you can't call this method fast enough, you have "dead times" because the default receive window is only 100ms (see below). By increasing the timeout, the receive window is increased (and power consumption too) and the dead times reduced.
I tested it and it solves the original issue. What do you think about adding a method to set this timeout? I can add a pull request if you want.
Another, less ideal solution is to use the RX Continuous mode: enable it before a long blocking operation, and call idle() before parsePacket() to stop receiving (or you could receive a packet in the middle of a read and get garbage). Can be useful for very long blocking operations lasting longer than the max timeout.
The duration of a symbol is 2^SF / BW (SF: Spreading Factor, BW: Bandwidth), so with default values = 2^7 / 125kHz = 1.024ms Default RX Timeout value is 100 (0x64) symbols -> 100ms Max timeout is juste over 1sec (1023*1.024ms).
Some code I added to the lib (header & begin):
#define REG_SYMB_TIMEOUT_LSB 0x1f
// set rx timeout
uint16_t const rxTimeoutSymb = 550;
writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2)&(~0x03)) | ((rxTimeoutSymb>>8)&0x03));
writeRegister(REG_SYMB_TIMEOUT_LSB, rxTimeoutSymb);
I'm very interested by this post. I noticed the same issue and I still looking for a good solution.
I already tried interrupts but I faced this issue #379 For now I'm using a xTask running fast to pool LoRa.parsePacket(). Not ideal but it is the better thing I have for the moment.
I will try your tip about the timeout register.
I noticed a small amelioration with your tip in loop, and a more significant with my xTask.
The timeoutSymb was fixed to 255 (the second parameter of writeRegister is an uint8, not 16 so I can't use more).
The timeout value is split over 2 registers, 2 more bits are in REG_MODEM_CONFIG_2 (so a total of 10 bits).
Are you missing packets by just polling parsePacket
in your task?
Are you missing packets by just polling parsePacket in your task?
Hi! With the pooling approach it is the case, some packet are missing if there is something working hard in loop().
Your example gives to me this warning: large integer implicitly truncated to unsigned type [-Woverflow]
Nevertheless I'm trying it :)
I am using LoRa.h recommended for my Heltec V2 board, I noticed that everytime we call parsePacket() and there is a CRC error the function resets de RX mode to MODE_RX_SINGLE. As I wrote my code expecting the receiver to stay in MODE_RX_CONTINUOUS after I called receive() I was not dealing with this unexpected reset. Just replaced the SINGLE with the CONTINUOUS flag and all the problems solved, errors came down from 1% to 0.1%:
if((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0)
{
// received a packet
_packetIndex = 0;
// read packet length
if(_implicitHeaderMode)
{
packetLength = readRegister(REG_PAYLOAD_LENGTH);
} else
{
packetLength = readRegister(REG_RX_NB_BYTES);
}
// set FIFO address to current RX address
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));
// put in standby mode
idle();
}
else if(readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS)) // was MODE_RX_SINGLE
{
// not currently in RX mode
// reset FIFO address
writeRegister(REG_FIFO_ADDR_PTR, 0);
// put in single RX mode
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); // was MODE_RX_SINGLE
}
I am using LoRa.h recommended for my Heltec V2 board, I noticed that everytime we call parsePacket() and there is a CRC error the function resets de RX mode to MODE_RX_SINGLE. As I wrote my code expecting the receiver to stay in MODE_RX_CONTINUOUS after I called receive() I was not dealing with this unexpected reset. Just replaced the SINGLE with the CONTINUOUS flag and all the problems solved, errors came down from 1% to 0.1%:
AFAIK, parsePacket will set the mode to RX_SINGLE. It is correct. If you want to use RX_CONTINUOUS RX, you can use receice() and receive callback.
Well, I am doing a time critical multi stepper control and I cannot be interrupted unless I say so, then I expected de LoRa receiver to behave like a UART, receives the data silently and waits until I can read it...callback are not an option
@macedolfm The callback can just set a flag to indicate a packet is received. You can process the packet any time later based on the flag.
If you insist to use parsePacket, it is always RX_SINGLE.
@IoTThinks Thanks !!! Will go with ISR & flag....
Just an update, the ISR routine flag messes up with the OLED.display() from SSD1306Wire.h as it is really picky and dos not like to be interrupted or it messes up with the display data, Being so I falled back into a mixed approach of using parsePacket() and when it results in greater than ZERO I read the buffer data and put it back on MODE_RX_CONTINUOUS calling receive();
uint16_t loraRead(uint8_t* data, uint16_t max_len)
{
if(LoRa.parsePacket() == 0 || max_len == 0)
{
return 0;
}
LoRa.idle();
int16_t rssi = LoRa.packetRssi();
int16_t snr = LoRa.packetSnr();
// CLEAR BUFFER
memset(data, 0, max_len);
// LORA RX
uint16_t count = 0;
while(LoRa.available())
{
if(count < max_len)
{
data[count++] = LoRa.read();
}
else
{
LoRa.read();
}
}
LoRa.receive();
return count;
}
Hi,
I experience a strange issue with the library: if I put a delay in the loop(), the LoRa module fails to receive almost all packets. I use the delay to simulate some long blocking operations. I send 30 bytes packets every 2 seconds.
From the example LoRaReceiver, just added the delay and I get maybe 1 packet out of 10. Without the delay, I receive every packet. Why is that?
Hardware: LoRa32u4 II board (https://bsfrance.fr/lora-long-range/1345-LoRa32u4-II-Lora-LiPo-Atmega32u4-SX1276-HPD13-868MHZ-EU-Antenna.html)
Thanks, Best regards, Benjamin