I sat down and read the Semtech SX1276 datasheet paying close attention to any references to CRCs and headers. Then to test some ideas I modified my Receive Basic test harness to see if I could reliably reproduce the problem with my stress test harness.
public sealed class StartupTask : IBackgroundTask { private const int ChipSelectLine = 25; private const int ResetLine = 17; private Rfm9XDevice rfm9XDevice = new Rfm9XDevice(ChipSelectLine, ResetLine); public void Run(IBackgroundTaskInstance taskInstance) { // Put device into LoRa + Sleep mode rfm9XDevice.RegisterWriteByte(0x01, 0b10000000); // RegOpMode // Set the frequency to 915MHz byte[] frequencyWriteBytes = { 0xE4, 0xC0, 0x00 }; // RegFrMsb, RegFrMid, RegFrLsb rfm9XDevice.RegisterWrite(0x06, frequencyWriteBytes); rfm9XDevice.RegisterWriteByte(0x0F, 0x0); // RegFifoRxBaseAddress rfm9XDevice.RegisterWriteByte(0x01, 0b10000101); // RegOpMode set LoRa & RxContinuous while (true) { // Wait until a packet is received, no timeouts in PoC Debug.WriteLine("Receive-Wait"); byte IrqFlags = rfm9XDevice.RegisterReadByte(0x12); // RegIrqFlags while ((IrqFlags & 0b01000000) == 0) // wait until RxDone cleared { Task.Delay(20).Wait(); IrqFlags = rfm9XDevice.RegisterReadByte(0x12); // RegIrqFlags Debug.Write("."); } Debug.WriteLine(""); if ((IrqFlags & 0b00100000) == 0b00100000) { Debug.WriteLine("Payload CRC error"); } byte regHopChannel = rfm9XDevice.RegisterReadByte(0x1C); Debug.WriteLine(string.Format("regHopChannel {0}", Convert.ToString((byte)regHopChannel, 2).PadLeft(8, '0'))); byte currentFifoAddress = rfm9XDevice.RegisterReadByte(0x10); // RegFifiRxCurrent rfm9XDevice.RegisterWriteByte(0x0d, currentFifoAddress); // RegFifoAddrPtr* byte numberOfBytes = rfm9XDevice.RegisterReadByte(0x13); // RegRxNbBytes // Allocate buffer for message byte[] messageBytes = new byte[numberOfBytes]; for (int i = 0; i < numberOfBytes; i++) { messageBytes[i] = rfm9XDevice.RegisterReadByte(0x00); // RegFifo } rfm9XDevice.RegisterWriteByte(0x12, 0xff); // RegIrqFlags clear all the bits string messageText = UTF8Encoding.UTF8.GetString(messageBytes); Debug.WriteLine("Received {0} byte message {1}", messageBytes.Length, messageText); Debug.WriteLine(string.Format("RegIrqFlags {0}", Convert.ToString((byte)IrqFlags, 2).PadLeft(8, '0'))); Debug.WriteLine("Receive-Done"); } } }
The RegHopChannel register has a flag indicating whether there was a CRC extracted from the packet header.
regHopChannel 00000000
Received 23 byte message 1 Hello Arduino LoRa! 1
RegIrqFlags 01010000
Receive-Done
Receive-Wait
…………………………..
regHopChannel 00000000
Received 23 byte message 1 Hello Arduino LoRa! 2
RegIrqFlags 01010000
Receive-Done
Receive-Wait
……………………………
regHopChannel 00000000
Received 23 byte message 1 Hello Arduino LoRa! 3
RegIrqFlags 01010000
Receive-Done
Receive-Wait
I then modified my Arduino-LoRa library based client to include a CRC
void setup() { Serial.begin(9600); // initialize serial while (!Serial); Serial.println("LoRa Duplex - Set sync word"); // override the default CS, reset, and IRQ pins (optional) LoRa.setPins(csPin, resetPin, irqPin);// set CS, reset, IRQ pin if (!LoRa.begin(915E6)) { // initialize ratio at 915 MHz Serial.println("LoRa init failed. Check your connections."); while (true); // if failed, do nothing } LoRa.enableCrc(); // BHL This was my change LoRa.setSyncWord(0x12); // ranges from 0-0xFF, default 0x34, see API docs LoRa.dumpRegisters(Serial); Serial.println("LoRa init succeeded."); } void loop() { if (millis() - lastSendTime > interval) { String message = "5 Hello Arduino LoRa! "; // send a message message += msgCount; sendMessage(message); Serial.println("Sending " + message); lastSendTime = millis(); // timestamp the message //interval = random(2000) + 1000; // 2-3 seconds interval = 1000; } // parse for a packet, and call onReceive with the result: onReceive(LoRa.parsePacket()); } void sendMessage(String outgoing) { LoRa.beginPacket(); // start packet LoRa.print(outgoing); // add payload LoRa.endPacket(); // finish packet and send it msgCount++; // increment message ID } void onReceive(int packetSize) { if (packetSize == 0) return; // if there's no packet, return // read packet header bytes: String incoming = ""; while (LoRa.available()) { incoming += (char)LoRa.read(); } Serial.println("Message: " + incoming); Serial.println("RSSI: " + String(LoRa.packetRssi())); Serial.println("Snr: " + String(LoRa.packetSnr())); Serial.println(); }
When I powered up a single client and the payload had a CRC
............................... regHopChannel 01000000 Received 23 byte message 6 Hello Arduino LoRa! 6 RegIrqFlags 01010000 Receive-Done Receive-Wait ................................. regHopChannel 01000000 Received 23 byte message 6 Hello Arduino LoRa! 7 RegIrqFlags 01010000 Receive-Done Receive-Wait ................................. regHopChannel 01000000 Received 23 byte message 6 Hello Arduino LoRa! 8 RegIrqFlags 01010000 Receive-Done Receive-Wait ...............................
Then when I increased the number of clients I started getting corrupted messages with CRC errors.
Received 24 byte message 6 Hello Arduino LoRa! 32 RegIrqFlags 01010000 Receive-Done Receive-Wait ............... regHopChannel 01000001 Received 25 byte message 8 Hello Arduino LoRa! 114 RegIrqFlags 01010000 Receive-Done Receive-Wait Payload CRC error regHopChannel 01000000 Received 24 byte message s��=��(��p�^j�\ʏ����� RegIrqFlags 01100000 Receive-Done Receive-Wait ............. regHopChannel 01000000 Received 24 byte message 6 Hello Arduino LoRa! 33 RegIrqFlags 01010000 Receive-Done Receive-Wait ............... regHopChannel 01000001 Received 25 byte message 8 Hello Arduino LoRa! 115 RegIrqFlags 01010000 Receive-Done Receive-Wait
I need to do some more testing but now I think the problem was the RegIrqFlags PayloadCRCError flag was never going to get set because there was no CRC on the payload.