SX1276 misses received LoRa packets


Hardware: I am using two “ST B-L072Z-LRWAN1” boards, each one with a “Murata CMWX1ZZABZ-091” module, and each module including one “ST STM32L072CZ” MCU and one “Semtech SX1276” transceiver.

Firmware/software: I don’t use any library at all. Not even the HAL libraries. I write my own source code for everything, optimized for speed. I use DMA for everything I can (SPI/UART/etc). I routinely use a logic analyzer to check that everything does what I want, and to trim for speed. All that works fine.

I have read the SX1276/77/78/79 datasheet (Rev. 7 - May 2020) many times, so I am fairly familiar with most of the SX1276 registers, the way the transceiver works (especially the LoRa modem option), the state machines to receive and to transmit, etc.

LoRa modem
Single frequency, around 868 MHz.
Bandwidth=125 kHz
CR=4/8 (yes)
Preamble=8 symbols
Implicit header mode
Payload length=9 bytes (fixed)
CRC on
AFC on
AGC on
PA output pin=RFO pin (Not PA_BOOST pin).
Output power=6 dBm (4 mW).
Let’s call my boards: board L (left) and board R (right). They are next to each other, with antennas around 12 cm apart.

I have noticed a very curious behavior. I’ll try to describe it, using two similar tests:


Board R: It sends a packet every T seconds. T is clearly longer than the packet duration. Each payload has a sequence (SEQ) field. That SEQ field is incremented on each packet sent. Each payload also includes a CRC16 field (in addition to the CRC16 managed by the LoRa modem). My CRC16 field is initialized with a certain seed that is unique to me. That means that I only process packets that for sure belong to me. Board R never listens. It only sends packets.

Board L: It is always in RXCONTINUOUS mode. Every time it receives a packet, it checks my CRC16, and then looks at the SEQ field. If my CRC16 is OK, it outputs a pulse on line “L RX OK” (shown on Figure 1, but not on Figure 2). If the SEQ field is not equal to the previous one plus one, it outputs a pulse on line “L RX SEQ error” (shown on Figure 2, but not on Figure 1. I did not spare output lines). That means that (at least) a packet has been lost (not received by L).

If, as I say in this Test 1, I keep board L always in RXCONTINUOUS mode, it loses almost zero packets. It depends on the conditions, and how much interference there is during the experiment, but I recorded zero packets lost out of 9680 packets sent, which is very good.

However, if…


Board R: Doing exactly the same as in Test 1.

Board L: Not always in RXCONTINUOUS mode. Every time it receives a packet, I make it leave RXCONTINUOUS mode, go to STDBY mode, stay there for 20 ms, and then go back to RXCONTINUOUS mode (the reason why I am doing this is that this is just an intermediate step, to make board L to acknowledge the packets received from R). Clearly (as you can see in the pictures), board L is already in RXCONTINUOUS mode before board R sends out the following packet. Board R sends a packet while “R mode” is “3h”.
Mode 0h = SLEEP
Mode 1h = STDBY
Mode 3h = TX
The mode output lines are updated not only every 10 ms, but also every time I (on purpose) change the mode.

(I have put both images together, because I am new and the page does not let me to embed two images, but the one at the top is Figure 1, and the one at the bottom is Figure 2.)

The curious thing is that, doing this, board L loses MANY more packets than in Test 1. It loses one in about 100 packets (than number being very very variable) sent by board R. The performance is way way worse than in Test 1. However, the distance between the boards, the output power, and the whole configuration of each one of the transceivers is exactly the same. The only thing that spoils the very low missed packet rate is bringing the receiver out of RXCONTINUOUS, keeping it in STDBY for any amount of time, and putting it again in RXCONTINUOUS mode (before the next packet arrives).

I have checked, and re-checked, and played with every single piece of configuration (AFC, AGC, output power, preamble length, coding rate, CrcAutoClearOff, DcFree method, PreamblePolarity, AutoRestartRxMode, PreambleDetectorTol, AfcAutoClearOn, RestartRxOnCollision, RxTrigger…), devoting several days into this, and I have been unable to get “zero packets lost out of 9680 packets sent” making the receiver temporarily leave the RXCONTINUOUS mode.

Does anyone know why this could be happening?

I know that the reason has nothing to do with (external) interference, because I can swap from Test 1 to Test 2, and vice versa, instantly, via UART, from my PC, and the missed packet rate changes instantly. If it was due to interference, that interference would be there for both tests, but it is not. Test 2 always yields a much worse missed packet rate.

Some part of the internal state machine of the LoRa receiver of the SX1276 does NOT like being “restarted”, contrary to what it would seem, which is sad, because I need to acknowledge packets. I am tempted to say there is a design flaw, and even say that it is a silly one, but I can’t assure. The errata sheet does not say anything.

Thank you.