To test the nanoFramework transmit and receive with interrupts implementation I used three Dragino LoRa Shields, a Seeeduino V4.2 and a pair of Netduino 3 Wifi devices.
I started with transmit as I was confident my Netduino 3 Wifi & Seeeduino + Dragino LoRa Shields could receive messages.
The TransmitInterrupt application loads the message to be sent into the First In First Out(FIFO) buffer, RegDioMapping1 is set to interrupt onTxDone(PacketSent-00), then RegRegOpMode-Mode is set to Transmit. When the message has been sent InterruptGpioPin_ValueChanged is called, and the TxDone(0b00001000) flag is set in the RegIrqFlags register.
The ReceiveInterrupt application sets the RegDioMapping1 to interrupt on RxDone(PacketReady-00), then the RegRegOpMode-Mode is set to Receive(TX-101). When a message is received InterruptGpioPin_ValueChanged is called, with the RxDone(0b00001000) flag set in the RegIrqFlags register, and then the message is read from First In First Out(FIFO) buffer.
namespace devMobile.IoT.SX127x.ReceiveTransmitInterrupt
{
...
public sealed class SX127XDevice
{
...
public SX127XDevice(int busId, int chipSelectLine, int interruptPin, int resetPin)
{
var settings = new SpiConnectionSettings(busId, chipSelectLine)
{
ClockFrequency = 1000000,
Mode = SpiMode.Mode0,// From SemTech docs pg 80 CPOL=0, CPHA=0
SharingMode = SpiSharingMode.Shared
};
SX127XTransceiver = new SpiDevice(settings);
GpioController gpioController = new GpioController();
// Factory reset pin configuration
gpioController.OpenPin(resetPin, PinMode.Output);
gpioController.Write(resetPin, PinValue.Low);
Thread.Sleep(20);
gpioController.Write(resetPin, PinValue.High);
Thread.Sleep(20);
// Interrupt pin for RX message & TX done notification
gpioController.OpenPin(interruptPin, PinMode.InputPullDown);
gpioController.RegisterCallbackForPinValueChangedEvent(interruptPin, PinEventTypes.Rising, InterruptGpioPin_ValueChanged);
}
...
}
private void InterruptGpioPin_ValueChanged(object sender, PinValueChangedEventArgs e)
{
byte irqFlags = this.ReadByte(0x12); // RegIrqFlags
Debug.WriteLine($"RegIrqFlags 0X{irqFlags:x2}");
if ((irqFlags & 0b01000000) == 0b01000000) // RxDone
{
Debug.WriteLine("Receive-Message");
byte currentFifoAddress = this.ReadByte(0x10); // RegFifiRxCurrent
this.WriteByte(0x0d, currentFifoAddress); // RegFifoAddrPtr
byte numberOfBytes = this.ReadByte(0x13); // RegRxNbBytes
// Allocate buffer for message
byte[] messageBytes = this.ReadBytes(0X0, numberOfBytes);
// Remove unprintable characters from messages
for (int index = 0; index < messageBytes.Length; index++)
{
if ((messageBytes[index] < 0x20) || (messageBytes[index] > 0x7E))
{
messageBytes[index] = 0x20;
}
}
string messageText = UTF8Encoding.UTF8.GetString(messageBytes, 0, messageBytes.Length);
Debug.WriteLine($"Received {messageBytes.Length} byte message {messageText}");
}
if ((irqFlags & 0b00001000) == 0b00001000) // TxDone
{
this.WriteByte(0x01, 0b10000101); // RegOpMode set LoRa & RxContinuous
Debug.WriteLine("Transmit-Done");
}
this.WriteByte(0x40, 0b00000000); // RegDioMapping1 0b00000000 DI0 RxReady & TxReady
this.WriteByte(0x12, 0xff);// RegIrqFlags
}
public class Program
{
...
#if NETDUINO3_WIFI
private const int SpiBusId = 2;
#endif
...
public static void Main()
{
int SendCount = 0;
...
#if NETDUINO3_WIFI
// Arduino D10->PB10
int chipSelectLine = PinNumber('B', 10);
// Arduino D9->PE5
int resetPinNumber = PinNumber('E', 5);
// Arduino D2 -PA3
int interruptPinNumber = PinNumber('A', 3);
#endif
...
Debug.WriteLine("devMobile.IoT.SX127x.ReceiveTransmitInterrupt starting");
try
{
...
#if NETDUINO3_WIFI || ST_STM32F769I_DISCOVERY
SX127XDevice sx127XDevice = new SX127XDevice(SpiBusId, chipSelectLine, interruptPinNumber, resetPinNumber);
#endif
Thread.Sleep(500);
// Put device into LoRa + Sleep mode
sx127XDevice.WriteByte(0x01, 0b10000000); // RegOpMode
// Set the frequency to 915MHz
byte[] frequencyWriteBytes = { 0xE4, 0xC0, 0x00 }; // RegFrMsb, RegFrMid, RegFrLsb
sx127XDevice.WriteBytes(0x06, frequencyWriteBytes);
// More power PA Boost
sx127XDevice.WriteByte(0x09, 0b10000000); // RegPaConfig
sx127XDevice.WriteByte(0x01, 0b10000101); // RegOpMode set LoRa & RxContinuous
while (true)
{
// Set the Register Fifo address pointer
sx127XDevice.WriteByte(0x0E, 0x00); // RegFifoTxBaseAddress
// Set the Register Fifo address pointer
sx127XDevice.WriteByte(0x0D, 0x0); // RegFifoAddrPtr
string messageText = $"Hello LoRa {SendCount += 1}!";
// load the message into the fifo
byte[] messageBytes = UTF8Encoding.UTF8.GetBytes(messageText);
sx127XDevice.WriteBytes(0x0, messageBytes); // RegFifo
// Set the length of the message in the fifo
sx127XDevice.WriteByte(0x22, (byte)messageBytes.Length); // RegPayloadLength
sx127XDevice.WriteByte(0x40, 0b01000000); // RegDioMapping1 0b00000000 DI0 RxReady & TxReady
sx127XDevice.WriteByte(0x01, 0b10000011); // RegOpMode
Debug.WriteLine($"Sending {messageBytes.Length} bytes message {messageText}");
Thread.Sleep(10000);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
...
}
}
The ReceiveTransmitInterrupt application combines the functionality TransmitInterrupt and ReceiveInterrupt programs. The key differences are the RegDioMapping1 setup and in InterruptGpioPin_ValueChanged where the TxDone & RxDone flags in the RegIrqFlags register specify how the interrupt is handled.