A demo using Nim to program Microchip SAM D21 series microcontrollers.
Specifically, it is focused on the SAMD21G18A variant, found on many popular development boards such as the Arduino MKR Zero and Adafruit Metro M0 / Feather M0. Modifications required for other SAM D21 variants are listed below. It should also be possible to use a similar structure to run Nim on other ARM Cortex-M devices (STM32, etc).
svd2nim was used to generate the
device/atsamd21g18a.nim
module, which provides a fast, type-safe, idiomatic
Nim interface to the SAM D21's full set of peripheral registers.
-
GPIO (port) driver leveraging Nim's macro system for zero-cost abstraction
-
DFLL clock used to run the MCU at it's maximum frequency of 48 MHz, thanks to Thea Flower's code, translated to pure Nim.
-
UART driver in pure Nim, also leveraging macros for compile-time setup.
-
stdin and stdout (native
echo
) redirected to UART.
https://nim-lang.org/install.html
On Arch Linux, install following packages:
arm-none-eabi-binutils
arm-none-eabi-gcc
arm-none-eabi-newlib
I assume similar packages are available for other distributions but their exact name may vary.
For Windows or macOS, see Arm GNU Toolchain Downloads. Download and install the "AArch32 bare-metal target (arm-none-eabi)" toolchain. Note: compiling this project on macOS was not tested, but let me know if it works for you.
nim bin
This will run nim c
followed by arm-none-eabi-objcopy
to create the .bin
file. Build output will be in the ./build
directory. The code size will also
be printed.
Assuming the following:
-
The device to be flashed has a BOSSA-compatible bootloader installed. This is the case of the default bootloader on SAMD21-based Arduino and Adafruit boards, as well as the UF2 bootloader and Microchip's SAM-BA bootloader.
-
The bootloader takes up 8 kb, therefore flash space for the application starts at
0x2000
(this is defined in the linker script as well). -
BOSSA is installed on the system and
bossac
is available on the path. -
The device is in bootloader mode (double-tap reset, pulsating LED) and the corresponding serial port is
/dev/ttyACMO
(modify as needed.) User must also have read/write permissions to the port, on Arch Linux this probably means adding the user to theuucp
group.
Then run the following command to flash the main.bin
program to the device:
bossac -o 0x2000 -p /dev/ttyACM0 -e -w -v build/main.bin
Instructions for flashing via SWD/OpenOCD are left as an exercise to the reader (PRs welcome).
By default, this project sets up the main CPU clock to 48 MHz via the DFLL clock
by using an external 32 kHz oscillator as source (XOSC32K
). If your board
does not have an external oscillator, it should be possible to modify the code
to use one of the SAMD21's internal 32k oscillators instead (PRs welcome to add
this as a configuration option). Or, remove the call to initDfll48m
and use
the default 1 MHz clock (make sure that SystemCoreClock
is set
correspondingly).
The linker script used by this project assumes an 8 kb bootloader. Some compatible options are:
- Microchip SAM-BA
- Arduino MKR Zero bootloader
- Adafruit's fork of the Arduino bootloader
- UF2 bootloader
If you want use this project without a bootloader, or with a different bootloader (such as this 1 kb DFU bootloader), you will need to modify the linker script (see link below in "Adapting to other SAM D21 variants").
-
Generate the device module (so called because it is the analog to what ARM CMSIS refers to as the device.h header file), here
atsamd21g18a21.nim
, for your variant, using svd2nim -
You might need to modify the linker script under the
lib/linker
directory, for example, if the device has a different flash or SRAM size. Thankfully, Thea Flowers' great blog post should help with that. -
Change the import and export in the
device/device.nim
file. -
Change the
SAMD21_Family
andSAMD21_Variant
constants inconfig.nims
. This is used to setup the correct startup file and header include paths.
Note: for families other than samd21a
, you will need to get the device support
pack from https://packs.download.microchip.com/ and extract the include
and
gcc
directories for your family under ./lib/atmel/{family}/
.
Released under the terms of the MIT license, see the LICENSE
file for details.
The lib
directory contains copies of works by other authors and distributed here
per the terms of their own license. Refer to each subdirectory or file for more
information.
(and suggested reading)
-
Thea Flowers' blog, in particular her linker script which is used directly in this repository. Her blog contains many more great articles on the SAM D21, check it out!
-
Zero to main() series of posts by François Baldassari.
-
The Best and Worst GCC Compiler Flags For Embedded by Chris Coleman. Unless you're up for reading the gcc man page, this is probably as good a place to start as any.
-
Alex Taradov's bare metal MCU starter projects.
-
PMunch's badger, which sparked my inspiration to make this and from which many build flags were lifted.