While trying to debug a deadlock in my RFM69 library I noticed in the logging that I was getting a receive interrupt while putting bytes in the FIFO for transmission.
Register 0x49 - Value 0X00 - Bits 00000000 Register 0x4a - Value 0X00 - Bits 00000000 Register 0x4b - Value 0X00 - Bits 00000000 Register 0x4c - Value 0X00 - Bits 00000000 Register 0x4d - Value 0X00 - Bits 00000000 ... 22:58:47.192 Received To 0X22 a 33 byte message hello world RFM69-915-02 10-58-47 CRC Ok True The thread 0x6a8 has exited with code 0 (0x0). 22:58:48.334 Send-hello world RFM69-915-01 10-58-48 22:58:48.351 Send-Done 22:58:48.388 Received To 0X22 a 33 byte message hello world RFM69-915-02 10-58-52 CRC Ok True 22:58:48.462 Transmit-Done The thread 0xde4 has exited with code 0 (0x0). 22:58:53.427 Send-hello world RFM69-915-01 10-58-53 22:58:53.445 Send-Done 22:58:53.556 Transmit-Done 22:58:57.382 Received To 0X22 a 33 byte message hello world RFM69-915-02 10-58-57 CRC Ok True The thread 0x17c has exited with code 0 (0x0).
After re-reading the RFM69CW/RFM69HCW module datasheet (based on the Semtech SX1231/SX1231H) I realised my code for loading the FIFO could be more efficient.

Based on the timing diagram I could remove the loop which loads bytes in the FIFO for transmission.

The changes in my RFM69 library weren’t huge but I think they are also applicable to the RFM9X LoRa library as well
public void SendMessage(byte address, byte[] messageBytes) { #region Guard conditions #endregion lock (Rfm9XRegFifoLock) { SetMode(RegOpModeMode.StandBy); if (PacketFormat == RegPacketConfig1PacketFormat.VariableLength) { RegisterManager.WriteByte((byte)Registers.RegFifo, (byte)(messageBytes.Length + 1)); // Additional byte for address } RegisterManager.WriteByte((byte)Registers.RegFifo, address); foreach (byte b in messageBytes) { this.RegisterManager.WriteByte((byte)Registers.RegFifo, b); } SetMode(RegOpModeMode.Transmit); } }
After modifications
public void SendMessage(byte address, byte[] messageBytes) { #region Guard conditions ... #endregion SetDioPinMapping(dio0Mapping: Dio0Mapping.TransmitPacketSent); lock (Rfm9XRegFifoLock) { SetMode(RegOpModeMode.StandBy); if (PacketFormat == RegPacketConfig1PacketFormat.VariableLength) { RegisterManager.WriteByte((byte)Registers.RegFifo, (byte)(messageBytes.Length + 1)); // Additional byte for address } RegisterManager.WriteByte((byte)Registers.RegFifo, address); this.RegisterManager.Write((byte)Registers.RegFifo, messageBytes); } SetMode(RegOpModeMode.Transmit); }
After stress testing with several client devices this appears to have reduced the scope of a receive interrupt to occur while a packet was being loaded into the FIFO for transmission. I now need to dig deeper into the timing around entering different operational modes and selectively enabling event interrupts.