Creating a custom SAMD bootloader and Arduino board

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.

  1. 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).
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.

  1. 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!

2 Likes

Thanks for taking the time to describe the process for your custom setup.

I've got a Microchip Curiosity Nano SAMD21 board which has the ATSAMD21G17D chip fitted and i'm working in a Win10 environment.

I cloned the Arduino Zero bootloader files and had to identify my chip as a SAMD21G17A in order to be able to build the bootloader. I did the memory size tweaks (half the FLASH, half the RAM & move the double tap address) and got the bootloader to build. I used Microchip Studio to load the bootloader and have a board with the on-board LED fading in & out, a COM port and a USB drive.

At this point my progress took a nose dive. I tried the basic blink sketch but it seems that bossac.exe doesn't support the chip:

Set binary mode
Send auto-baud
Set binary mode
version()=v2.0 [Arduino:XYZP] Feb 26 2023 15:36:54
Connected at 115200 baud
readWord(addr=0)=0x20003ffc
readWord(addr=0xe000ed00)=0x410cc601
readWord(addr=0x41002018)=0x10012693

Device unsupported

Now i'm wondering whether to (a) try and tweak the latest version of bossa to support my SAMD21 variant, or (b) look into the bootloader source code to see if I can force out a chip signature that is supported, or (c) look to see if somebody else has already tweaked bossa.

Interesting, this isn't one I've come across yet. From the datasheet the only real difference looks to be an extra TCC instance. It looks like the chip identifier for the 17D is not recognised by bossa, if you have a look at the bossa git repository here - BOSSA/Device.cpp at master · shumatech/BOSSA · GitHub line 455, it has the device ID for the 17A but not the 17D. It might be a case of adding the 17D with device ID 0x10012693, recompiling and replacing your bossa executable so that it can see the 17D... Or it might be a bit more complicated than that :sweat_smile:

The easy part was adding in the device ID. The device ID gets masked with 0xFFFF00FF, so the actual value in the case is 0x10010093.

The part that took an eon to figure was how to rebuild bossac on a Windows 10 machine! After a lot of digging, I succeeded in rebuilding bossac.exe using MSYS2 and the GCC tools.

I made a bunch of notes and a step-by-step guide to rebuilding bossac.exe on a Windows 10 machine as I could not find anything on the wider web. If you think it will fit in here with the the current discussion, then I can post it for the benefit of others.

Yes absolutely! I got it to compile easily in Ubuntu but I tried using MSYS2 in Win10 and failed, I couldn't get it to see the wxwidgets or other dependencies, ran out of time and gave up. Either here or linked here to a new thread?

Ah, on one of my journeys down many rabbit holes over the weekend, I discovered that if you are wanting to build bossac (i.e. the command line version of the tool), then it suggested that you don't need any of the wxWidgets libraries.

1 Like

What follows is my idiot's guide to recompiling bossac on a Windows 10 desktop PC. Note that this is for bossac, not bossa (which is the GUI tool).

Step 1 - Install MSYS2

Go to msys2.org and download the Windows installer - as of the date of this post, it's called msys2-x86_64-20230127.exe. Once downloaded, double click the installer and choose a folder for it. I chose d:\msys64.

Step 2 - Update MSYS2

Go the MSYS2 installation folder and run mingw32.exe. In the shell window that appears, type:

Pacman –Syu

This should update MSYS2 to the lasted version.

After this finishes (let it close the bash shell), open bash again (i.e. run mingw32.exe again) and type the same command again to finish the updates. The same procedure is used for regular updates of the MSYS2 installation.

Step 3 – Install compiler toolchains

I installed both the 32bit and 64bit toolchains. In the mingw32 shell window, type:

pacman -S mingw-w64-x86_64-toolchain
pacman -S mingw-w64-i686-toolchain

In each case, when asked to enter a selection, just hit enter (i.e. all) and then Y to proceed with the installation.

Then install the make utility by typing:

pacman -S make

Step 4 – Grab the latest BOSSA source code

Go to the BOSSA website and download the zip of the BOSSA source code.

Using a Windows tool of your choice, unzip the BOSSA source code into your MSYS2 home folder. For me the path is D:\msys64\home\Mark. Remember to keep the folder structure. You should now have a folder called BOSSA-master in your MSYS2 home folder.

Step 5 – Test compile the unmodified BOSSA source code

In the mingw32 shell, navigate to the root of the BOSSA folder by typing:

cd BOSSA-master

And issue the build command to build the command line version of BOSSA – i.e. BOSSAC by typing:

make bossac

There will likely be a lot of complaining about git like this:

make: git: No such file or directory

I think this is make trying to get a version number from git. I changed the version section of the makefile so it read:

#
# Version
#
#VERSION?=$(shell git describe --tags --dirty)
VERSION="1.9.1-md"
WXVERSION=3.0

You should now have a new bossac executable (called bossac.exe) in the bin subfolder of BOSSA-master.

1 Like

Now, how to modify bossac.exe to support the a Microchip Curiosity Nano SAMD21 board which has the ATSAMD21G17D chip fitted.

Firstly run the existing bossac.exe by trying to upload the basic blink sketch. It should produce an error as shown in my post #2 above. Make a note of the value in the last readWord output. That is the chip ID.

Next edit the device.cpp file in the BOSSA-master\src folder and locate the lines:

        case 0x10010001: // J17A
        case 0x10010006: // G17A
        case 0x1001000b: // E17A
        case 0x10010010: // G17A WLCSP
            _family = FAMILY_SAMD21;
            flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x17", 2048, 64, 0x20002000, 0x20004000) ;
            break;

It's at line 454 onwards in my source code. Add in a new line to support the ATSAMD21G17D chip:

        case 0x10010001: // J17A
        case 0x10010006: // G17A
        case 0x1001000b: // E17A
        case 0x10010010: // G17A WLCSP
        case 0x10010093: // G17D - MJD Mod
            _family = FAMILY_SAMD21;
            flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x17", 2048, 64, 0x20002000, 0x20004000) ;
            break;

The number in the case statement you need is the value from the readWord above (0x10012693) but it needs to ANDed with 0xFFFF00FF, so you get the value 0x10010093.

Now rebuild bossac as described above and you should have a new exe that supports you specific chip.

You will need to replace (keeping a copy of the original!) the existing bossac.exe.

1 Like

Awesome thank-you for sharing! This looks like what I tried but I may have confused it by downloading too many libraries in my shotgun approach haha. I'm sure this will be useful for people to reference when trying to do the same thing!

I just tried this now and initially I couldn't get it to work, worked out I was using the wrong MSYS2 console duh :man_facepalming:
For anyone else confused use this one (from the Windows start menu):
image

After trying to compile in the wrong environment, it wouldn't work in the correct one either. I found running make clean fixed that though:

make clean
make bossac

Also, to avoid the git warnings or modifying the makefile:

pacman -S git
git clone https://github.com/shumatech/BOSSA
cd BOSSA/
make bossac

I almost forgot about the start menu as I rarely use it myself, instead preferring to go direct to the application via explorer.

I wonder if I just got lucky with choosing the 32bit environment to start with?

Glad that you were able to rebuild bossac, as it verifies the idiots guide!

I'm not familiar with the use of git so I'm guessing that by installing git, that sorts out the complaining during the build process. Does that line in the makefile that populates the version actually pull the latest version number (in this case I think it's 1.9.1) from the repository.

Is there a way to tag on to that version, maybe by adding my initials or similar, so that at a future date I will know that the new exe has been tweeked, and isn't actually the original master?

I'm also a bit of a noob when it comes to git, but I think the right approach might be to fork the repository to your own github repository, modify it there and then you can manage changes at that level.

Hello. First of all, I received a lot of help with the detailed explanation. However, I left a question on the link below because I couldn't upload it for some reason in the process of following. Can you help me with this? It would be a great help if you could help me. Thank you.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.