by George Sephton on June 30, 2017 at 7:45 am
Over the next few blog posts, I am going to talk through how I reversed-engineered the SAM-BA® Bootloader to work on the SAML21 chip using IR as an interface, rather than USART or USB, which SAM-BA normally uses. I needed a way to be able to remotely update the firmware of the SAML21 without having physical access to the device or the pins on it. To do this I decided to use IR as a transmission medium, since the device I was using was already making use of an IR sensor.
However, since we are communicating wirelessly with the bootloader, it will be common for packets of data to get lost, so I needed to implement a check to ensure this didn’t happen. The SAM-BA bootloader does not implement such a check and so I had to adapt it to suit my needs. Ultimately, I could have written my own bootloader, however it was quicker and easier to simply adapt the SAM-BA bootloader code and use the existing SAM-BA PC software instead.
The Atmel SAM-BA Bootloader is a bootloader designed by Atmel for use in the SAM processors. Most of the SAM chips comes with the SAM-BA bootloader pre-programmed in ROM, however, some of the lower range chips don’t, but they can still support it being programmed with it.
The SAMC, SAMD and SAML chips (ARM Cortex-M0+) don’t come with SAM-BA pre-programmed. This is due to these chips not having a Read Only Memory (ROM), which the bootloader is usually programmed onto.
Ultimately a bootloader can be programmed into any chip, and so regardless of support, I hope to be able to display how the SAM-BA bootloader can be used in any chip.
Atmel SAM Processors with SAM-BA in ROM
|Cortex-M0+||SAMC, SAMD, SAML||No|
|Cortex-M3||SAM3N, SAM3S, SAM3U, SAM3A, SAM3X||Yes|
|Cortex-M4||SAM4E, SAM4N, SAM4S||Yes|
|Cortex-M7||SAM7S, SAM7SE, SAM7X, SAM7XE, SAMV, SAME, SAMS||Yes|
|ARM926||SAM9XE, SAM9N, SAM9CN, SAM9R, SAM9G, SAM9X, SAM9M||Yes|
Note that the:
- SAMS specifies that the on-board ROM has SAM-BA already programmed, however there does not seem to be support for the chip in the SAM-BA software. However, this does not mean it cannot be programmed into the software.
- SAMG does not mention support for the SAM-BA bootloader in the datasheet, despite having an on-board ROM. Note that the on-board ROM is “reserved for future use”.
Before we start, let’s go over what a bootloader actually is. A bootloader is a piece of software that runs when a microprocessor is powered up. MPUs with bootloaders programmed into their ROM are designed to boot from ROM first whereas MPUs with only one form of program memory have the bootloader programmed at the start of the memory so that they run first.
Since the bootloader runs first, it acts as a sort of controller of the chip. They are typically designed to tell the chip where the program is to be run and can also act as a programming interface.
Let’s take a simple Microchip PIC16F84A chip with 1.75KB of Flash Program memory. When the PIC is powered on, the program counter points to 0 in EEPROM and starts processing commands. This is the simplest way for a program to run.
Now let’s take the Atmel SAMA5D3, a powerful ARM-A5 processor. The SAMA5D3 has no internal memory aside from the Read Only Memory (ROM) with the SAM-BA bootloader programmed on it. Memories are connected to the processor via external memory buses and can be Flash, EEPROM, an SD card, etc. Similar to how your computer can boot from its hard drive, DVD drive, USB ports etc, the SAMA5D3 can boot from any of its memories. The bootloader on the SAMA5D3 is designed to check where it can boot from on power-up, based on the external data buses that it uses:
Once the SAMA5D3 has found which memory contains a program to run, it copies this program into its internal SRAM and begins executing.
But, let’s focus on the bottom of the flow chart above.
If no program is found, the SAMA5D3 boots into the SAM-BA monitor (this is another section of the SAM-BA bootloader). This allows the processor to connect to the SAM-BA software on your PC. Once loaded the software allows you to program directly to the memories attached to the SAMA5D3, which is does by talking to the SAM-BA monitor. This means we could then write our program into NAND flash and when we reset the chip, the SAMA5D3 will see our program in NAND flash and begin executing.
We are going to look at programming the SAML21 with the SAM-BA bootloader. Since this only has a single internal Flash memory, and is a significantly less complicated chip than the SAMA5D3, we’ll briefly look at why using a bootloader is useful in this situation.
SAM-BA on the SAML21
The SAML21 only has a single memory, and on power-up the processor will go to the first memory location and begin executing. When we looked at the SAMA5D3 example, the bootloader was used to tell the processor where the program is to be executed. In this situation, our bootloader is not needed for this. However, that’s not to say we couldn’t store two programs in our internal memory. Maybe if the user is holding down a button when the bootloader starts we go to memory location 0x2000 and start executing there, and if not then we go to memory location 0xF000 and start executing there.
Or perhaps, when the bootloader starts, we check to see if there is any data at memory location 0x6000 and if so we begin executing there, and if not then we continue executing the bootloader. This simple concept is exactly what we’re going to do. If the bootloader decides to continue past its initial check, it will load the SAM-BA monitor, allowing the user to connect to it via a PC.
Before we jump into coding our bootloader, let’s first look at the memory layout of the SAML21 and where our bootloader will fit in.
When writing your program in C, we begin in the main() function since this is the first bit of code the processor jumps too. However, this isn’t actually the first bit of code the processor runs. When we compile our project, Atmel Studio uses the GCC compiler to compile our code into machine code that the SAML21 can understand. The first program it runs is actually the reset handler, which can be found in your project under:
src > ASF > sam0 > utils > cmsis > saml21 > source > gcc > startup_saml21.c
The reset handler actually prepares the processor to run your code, which it does by setting up exception vectors, initializing stacks and registers and any memory systems that may need initializing. It initializes IO devices, enables interrupts and finally prepares the processor state and calls main().
Now when GCC compiles your program, the reset handler is located at location 0x00000000. When writing a program to be stored alongside a bootloader, this needs to be adjusted to be located at another location, otherwise our program would simply overwrite our bootloader.
This is mentioned in the Application Note AT07175: SAM-BA Bootloader for SAM D21:
Of course the application start address doesn’t have to be 0x1000 or 0x2000, it can be whatever we like. But since we are limited on our memory, and the bootloader only runs at power-up, it needs to be as small as possible. Let’s look at how the internal flash memory would look like with the SAM-BA bootloader and an application programmed (also taken from Application Note AT07175):
The diagram above shows the memory of the SAML21 on the right and the application we want to load on the left. As mentioned before, we tell GCC to compile the code to a different starting address so that when it’s programmed into flash memory using the bootloader, it will still work correctly. We’ll go through all of this later on.
In the diagram above you can also see the reset handler that is called at the beginning of the bootloader and the application. When the bootloader calls the application, it must call the application reset handler so that the processor can be prepared to run your application correctly.
I hope that was a nice introduction to the SAM-BA bootloader. In the next blog post, we’ll start looking more at the functionality of the bootloader and we’ll look at how it works in a lot more detail.