I have been trying to create some custom SAMD boards over the past few months, and ran into a whole lot of problems trying to get a bootloader compiled, and a board definition that would work. Part of the challenge is that right now many of the commonly used MCUs for the standard Arduino SAMD boards are out of stock everywhere, so being able to use an alternative part with more or less memory or maybe in the E or L series is really helpful. Anyway, not having a great deal of experience with makefiles and stuff, I stumbled my way through this and thought I would record it here with the aim of making someone else's life easier down the track. So here is the process I found works for me, in my case had a board with a SAMD51J18A (instead of the 19A), and a SAME51J20A.
- Creating the bootloader - I used the Adafruit fork of the Microsoft uf2 bootloader repository in github - https://github.com/adafruit/uf2-samdx1. I found this was super sensitive to the right toolchain (could not make it work in Windows or with Atmel Studio).
-
Create a virtual machine with Virtual Box or Hyper-V and use Ubuntu 18.04 desktop - https://releases.ubuntu.com/18.04/ubuntu-18.04.6-desktop-amd64.iso
-
Install necessary bits from terminal:
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt update
sudo apt install gcc-arm-embedded make git
- Clone the repository:
git clone https://github.com/adafruit/uf2-samdx1
cd uf2-samdx1
- Confirm compiling the default board bootloader works:
make
You can check if it was successful by checking the /build/board_name directory - the booloader .bin file should be there along with all the other linker files.
-
Copy a board directory that is similar to the board you are developing, in my case Metro M4 was close:
cp -r metro_m4/ my_new_board/
-
Edit the copied board.mk and board_config.h files to match your custom board requirements. Note these settings for later, also note that Arduino IDE recognises your board by it's USB vendor and product ID's, if you don't put unique IDs here then it will likely think your board is the one you have cloned - which is not unuseable but it is a pain as you have to manually change it back to your custom board each time you upload a sketch. I requested VID and PIDs from Microchip which was pretty painless and that works for me.
Also note that if your board is not using a crystal you can define that here too by adding #define CRYSTALLESS 1 to board_config.h, hopefully the rest is fairly self explanitory. -
Compile your custom bootloader (from the main uf2-samdx1 directory)
make BOARD=my_new_board
-
Copy the compiled board build/my_new_board directory to your computer using your favourite tool WinSCP or something like that).
-
Upload the booloader .bin or .elf file to your board using your programmer (I used Atmel-ICE and Atmel Studio). Test it works as expected, once uploaded and USB is connected it should show up as a USB flash drive (if you were using uf2 bootloader of course!), and if you defined a board LED it will be fading on and off.
- Adding the board to Arduino IDE - Next I found adding a new board to the existing Adafruit SAMD boards was the easiest approach, though if you update the Adafruit boards it will wipe your custom board so save a backup as well! Here is what I did (assuming you have the relevant boards package already installed):
-
Create a new bootloader directory, in my case inside: C:\Users\USER\AppData\Local\Arduino15\packages\adafruit\hardware\samd\1.7.11\bootloaders\mynewboardM4. Copy across your new bootloader files to the new directory (note - I recommend sticking with the existing naming conventions for directories, makes it easier later on).
-
Copy the variant folder of the existing board that most closely matches your custom board, this is back under the adafruit\hardware\samd\1.7.11\variants folder. Again stick with the standard naming convention here.
-
Edit the variant.h file to match your board pins, and variant.cpp if you are modifying pin functions or adding extra pins.
-
Next you will need to edit the \linker_scripts\gcc\flash_with_bootloader.ld and flash_without_bootloader.ld files - these tell the compiler where the memory is mapped. This is only necessary if you are using a chip with different SRAM or PGM data size to the one you are copying. For SRAM, 128k = 0x20000, 192k = 0x30000, 256k = 0x40000. For flash 256k = 0x40000, 512k = 0x80000 and 1024k = 0x100000
-
Now edit the boards.txt file back up a couple levels in the main samd directory, copy you existing model board config and customise it to match your new board, adding -DCRYSTALLESS if you don't have a crystal oscillator. Here is also where Arduino will try and match your board definition with your plugged in board based on the USB IDs. Also pay attention to memory size again (actual upload size is your flash size minus the 0x4000 bootloader partition. Update your MCU part number, bootloader .bin file path and anything else that needs to be changed.
-
At this point you may be able to fire up Arduino IDE and send your blinky sketch to the board, if it works great! If the sketch uploads and then the board disconnects and locks up, double check your edits to the copied board variant info and boards.txt file. This is usually because memory has not been mapped correctly so double check those bootloader scripts as well! If it fails to compile, complaining of missing register definitions yada yada then you will need to look at some more of the build headers. I found that while the header files for pretty much all of the Atmel SAM parts are there, not all of them are properly referenced in the main header files. Here are the ones I had to edit to make sure the right header file gets used by the compiler.
-
WVariant.h - this is in the \samd\1.7.11\cores\arduino\ directory and was missing any reference to my non-standard MCUs - make sure you are adding your definition alongside a pin-compatible IC as this defines the number of timer channels etc, which may be different with higher or lower pin count parts.
-
sam.h and samd.h (or whichever letter your MCU uses) - these are under C:\Users\USER\AppData\Local\Arduino15\packages\adafruit\tools\CMSIS-Atmel\1.2.2\CMSIS\Device\ATMEL
-
sam.h (a different sam this time haha), located under C:\Users\USER\AppData\Local\Arduino15\packages\adafruit\tools\CMSIS-Atmel\1.2.2\CMSIS\Device\ATMEL\samd51\include - changing the directory to match your MCUs letter again.
Once I completed all this I found sketches compile and run reliably. I hope this is helpful, please feel free to chime in with your own experiences!