LoRa Duplex SAMD21G

dev board RobotDyn M0 Mini
chip SAMD21G
features lora duplex SPI

Before starting

Dependancies

Ensure the following requirements are available:

Pre-requisites

Try these simpler examples:

Description

Send and receive at the same time from another node! Use this code with duplex b.

SPI

SPI pins used

Take note of the actual SPI pins used on SAMD21G.

{ PORTA, 12, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_12 }, // MISO: SERCOM4/PAD[0] PA12
{ PORTB, 11, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_11 }, // SCK: SERCOM4/PAD[3] PB11
{ PORTB, 10, PIO_SERCOM_ALT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_10 }, // MOSI: SERCOM4/PAD[2] PB10

Datasheet pin information

Logic Analyzer capture

Saleae Logic Analyzer capture

RobotDyn board errors

As noted in the error of the RobotDyn M0 mini board:

There is a “ICSP” header, with pin assignments that look wrong on the schematic. I suspect the MISO pin on the header is really PA12, not D12. More to explore.

Code

Download code
#include <SPI.h>
#include <LoRa.h>

const int csPin = 5;
const int resetPin = 6;
const int irqPin = 1; // alternate pin: D11

byte localAddress = 0xAA;
byte destinationAddress = 0xBB;
long lastSendTime = 0;
int interval = 2000;
int count = 0;

void setup() {
  SerialUSB.begin(9600);
  while (!SerialUSB) { }
  delay(100);

  SerialUSB.println("Start LoRa duplex");
  SerialUSB.print("Local address:");
  SerialUSB.println(String(localAddress, HEX));
  SerialUSB.print("Destination address:");
  SerialUSB.println(String(destinationAddress, HEX));

  LoRa.setPins(csPin, resetPin, irqPin);

  if (!LoRa.begin(433E6)) {
    SerialUSB.println("LoRa init failed. Check your connections.");
    while (true) {}
  }
}

void loop() {
  if (millis() - lastSendTime > interval) {
    String sensorData = String(count++);
    sendMessage(sensorData);

    SerialUSB.print("Sending data " + sensorData);
    SerialUSB.print(" from 0x" + String(localAddress, HEX));
    SerialUSB.println(" to 0x" + String(destinationAddress, HEX));

    lastSendTime = millis();
    interval = random(2000) + 1000;
  }

  receiveMessage(LoRa.parsePacket());
}

void sendMessage(String outgoing) {
  LoRa.beginPacket();
  LoRa.write(destinationAddress);
  LoRa.write(localAddress);
  LoRa.write(outgoing.length());
  LoRa.print(outgoing);
  LoRa.endPacket();
}

void receiveMessage(int packetSize) {
  if (packetSize == 0) return;

  int recipient = LoRa.read();
  byte sender = LoRa.read();
  byte incomingLength = LoRa.read();

  String incoming = "";

  while (LoRa.available()) {
    incoming += (char)LoRa.read();
  }

  if (incomingLength != incoming.length()) {
    SerialUSB.println("Error: Message length does not match length");
    return;
  }

  if (recipient != localAddress) {
    SerialUSB.println("Error: Recipient address does not match local address");
    return;
  }

  SerialUSB.print("Received data " + incoming);
  SerialUSB.print(" from 0x" + String(sender, HEX));
  SerialUSB.println(" to 0x" + String(recipient, HEX));
}

Makefile

BOARD?=arduino:samd:mzero_bl
PORT := $(shell ls /dev/cu.usbmodem*)
BUILD=build

.PHONY: default lint all flash clean

default: lint all flash clean

lint:
	cpplint --extensions=ino --filter=-legal/copyright,-readability/casting,-runtime/int,-whitespace/line_length *.ino

all:
	arduino-cli compile --fqbn $(BOARD) --output-dir $(BUILD) ./

flash:
	arduino-cli upload --fqbn $(BOARD) --port $(PORT) --input-dir $(BUILD)

clean:
	rm -r build

Serial console

Serial output from the firmware.

LoRa Duplex SAMD21G serial console

Schematic

Wire up the hardware accordingly

LoRa Duplex SAMD21G schematic

Prototype

A photo of the actual setup.

LoRa Duplex SAMD21G prototype

References

Watch