LoRa Duplex SAMD21G

Updated on 23 September 2022
dev board RobotDyn M0 Mini
chip SAMD21G
features lora duplex SPI
This tutorial is more than 1 year old. If the steps below do not work, then please check the latest versions and the documentations of the individual tools used.

Before starting

Dependancies

Ensure the following dependancies are downloaded and available:

Pre-requisites

Try these simpler or similar examples:

Code

Download code lora-duplex-samd21g.ino
#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

Prototype

A photo of the actual setup.

LoRa Duplex SAMD21G prototype

Schematic

Wire up the hardware accordingly

LoRa Duplex SAMD21G schematic

Serial console

Serial output from the firmware.

LoRa Duplex SAMD21G serial console

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

![]https://hutscape.com/assets/images/tutorials/lora-duplex-samd21g-pin-mux.png)

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.

References

Watch