Hardware Design
Microchip/Atmel makes a SAMD21 chip and there are several variants. Most designs use the ‘G’ variant, but I wanted to use the simpler ‘E’ variant because it comes in a TQFP-32 package that I can very easily solder in my reflow oven without any trouble, or even by hand if I have to.
The GPS module is a cheap Quectel L80 with a MTK3339 chipset. It is easy to use but the backup power circuit requires a charging circuit, so I don’t have battery backup for quick startup. I mainly chose this module because it has big soldering pads with 2.54mm spacing for easier prototyping.
The LoRa radio module is a HopeRF module soldered to the bottom of the board.
Burning a Bootloader
To make this board work with Arduino, I had to burn the Arduino bootloader onto the chip using an Atmel-ICE programmer. My board has 5 test points on the bottom for this purpose. The Atmel-ICE needs connections for VTG (3.3V), SWDIO, SWCLK, RESET, and GND. The board has to be powered over USB during the programming procedure. In the Arduino IDE, I selected Tools->Board = Arduino/Genuino Zero (Programming Port), Tools->Programmer = Atmel-ICE, and then just clicked Tools->Burn Bootloader. In a few seconds, my board had a bootloader and is now programmable as an Arduino Zero!
Programming the Board
I was careful in my design to allow this board to be used as an ordinary Arduino Zero even though it uses a different variant of the SAMD21 chip. The downside of this is that the default SPI pins defined for the Arduino Zero board use pins that are not present in the ‘E’ variant of the SAMD21. Luckily the design of the Arduino system is flexible enough that we can define a different SPI interface on different pins. There is a great article by Adafruit on this topic but it may be pretty hard to understand. The bottom line is that by using these lines in your Arduino sketch:
SPIClass SPI1(&sercom1, 12, 13, 11, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_3);
pinPeripheral(11, PIO_SERCOM);
pinPeripheral(12, PIO_SERCOM);
pinPeripheral(13, PIO_SERCOM);
You can now use interface SPI1 to communicate with the LoRa module. I wrote a simple test sketch that reads the GPS module and broadcasts the GPS coordinates on the radio every 15 seconds. See the samd21-lora-gps GitHub repo.
This test code uses the RadioHead library to control the LoRa radio. The RadioHead library is flexible so I was able to use the SPI1 interface by defining a couple of new files, RHHardwareSPI1.[cpp,h].