by George Sephton on July 18, 2017 at 8:05 am
Now that we’ve been over the functionality of the SAM-BA® Bootloader, I’m going to finish this series with the analysis of the bootloader, including a detailed look at what’s actually going on behind the scenes. Although I won’t be showing the code for my adapted bootloader, I’m hoping that there’s enough information in these posts to allow anyone to easily adapt the SAM-BA Bootloader for their own application.
We now have a complete understanding of how the SAM-BA system works. Let’s now look at exactly what happens when we connect our SAML21 to the SAM-BA PC software. We can’t begin to adapt the SAM-BA system until we know exactly what the software will be doing.
I used a serial monitoring application to see the data being transferred from PC to bootloader.
When first clicking connect in the SAM-BA software, it will load up the TCL file associated with the selected board. These can be found in the SAM-BA installation software in the tcl_lib folder. If we open the saml21_xplained_pro folder, we see the TCL file used to tell the SAM-BA software how to connect to our SAML21 bootloader, and also the .bin file of the compiled applet.
Note that when we looked at the applet source code previously, the Makefile with it tells the compiler to output the compiled flash applet to here.
The TCL file tells the software what memories are available for that chip, what device ID to expect and where the application start address is etc. The customisation of this can all be found in Atmel’s application note AT09423 (SAM-BA Overview and Customization Process). We’ll be looking at this later on.
When connecting, to the bootloader, the software first sends:
I don’t know why it sends 0x80 twice, but the # (0x23) is sent to tell the bootloader we are connecting via USART:
Once the bootloader has received that, the SAM-BA monitor is ready to go. We then need to enter it into normal mode:
Which the bootloader will respond with 0A 0D (\n\r):
Next the software queries the device ID:
77 34 31 30 30 32 30 31 38 2C 34 23 (w41002018,4#)
The w command is used to read a word from the device:
As I mentioned before, every memory location in the SAML21 has a unique address, regardless of memory type. We can look in the SAML21 datasheet to see what address is at 0x41002018.
From here we can see that address 0x41002018 is something to do with the DSU (Device Service Unit). From the datasheet:
The accepted device IDs are defined in our TCL file:
Here we can also set what memory location has to be read in order to retrieve the device ID:
set cidr_addr 0x41002018
If we now look at the data the SAML21 bootloader returns:
0F 01 81 10 (...)
We have the device ID of the SAML21J18B, which is on the accepted list. Note that if the device ID is not on the accepted list, the software will stop trying to connect:
Setting the SAM-BA GUI
Now that the SAM-BA is ready to connect, it starts to initialise the user interface required. I won’t go over everything in the TCL file, since most of it can be left the way it is, but note the following:
Here we can set our scripts that are available to the user, and we also set three vital things:
- Applet address: this is where the applet application is loaded to. Note that the SAML21’s SRAM starts at address 0x20000000 and ends at address 0x22007FFF.
- Applet mailbox address: this is the location of the mailbox used to communicate between the bootloader and the applets. I won’t go into detail about this since it’s quite complex, but essentially the linker file for our applet tells the compiler where to put the mailbox and once compiled it comes out at 0x20001040.
- Applet file name: this is the compiled output that we talk about before.
Note that these parameters are directly related to the parameters set in our linker file (found in the SAM-BA install directory under applets > saml21 > sam-ba_applets > linker_script.
There’s a lot to see in the TCL file, but I’m going to leave it there. Later on we’ll remove some of the scripts that are available to the user, but that will be the only change to this file.
Send the Applets Application
Now we’re ready to send the application to be stored in SRAM. We saw in the last section that this will sent to location 0x20001000.
The SAM-BA software starts this process by sending the S command, used to send files to the bootloader:
53 32 30 30 30 31 30 30 30 2C 30 30 30 30 30 39 31 30 23 (S20001000,00000910#)
We saw before that the first parameter sent is the location to store the file we’re going to send, and the second parameter tell the bootloader how many bytes of data are going to be sent. (Note that parameters are always sent as hex).
In this case we are going to send 2320 bytes of data to be stored starting at location 0x20001000. Once the bootloader receives this, it will call the getdata_xmd function, either usb_getdata_xmd() or usart getdata_xmd(), and wait until all the data has arrived.
The __asm(“nop”); line at the bottom of this function occurs after all the data has arrived, so we need to look inside the function usart getdata_xmd() to see how our data is handled:
Note that as data comes in, it looks at the start of each packet to see if it’s a Start of Header: SOH (0x01) or an End of Transmission: EOT (0x04). It then uses the getPacket() function to retrieve the data from the packet and place it into memory.
When I was analysing this code, it became apparent that a lot of this was unnecessarily over complicated. So instead, I primarily focused on the data being sent and used the bootloader code as a reference:
After the S command is sent, a C (0x43) is returned as a response, telling the software that the bootloader is ready to start receiving the data. Remember that up until now we have been dealing with commands that always end in a #. Packets don’t follow this trend, and instead are always the same length: 0x85 (133) bytes long. Packets are arranged as follows:
|0||This is always 0x01 – Start of Header, this is how the bootloader knows that this is a packet and not an EOT, or ESC etc.|
|1||This is our packet counter starting at 1 and, in this instance, ending at 19 – I’ll explain where 19 comes from in a bit.|
|2||This is the inverse of the packet counter, so the inverse of 0x01 is 0xFF, 0x02 is 0xFE etc.|
|3-130||This the data we are sending (128 bytes)|
|131-132||This is a checksum of the data we have just sent|
Note that packets have to be 133 bytes and thus data has to be sent in multiples of 128. In our case, we are sending 2320 bytes of data; if we divide this by 128, we get 18 remainder 16. That means we will send 18 full packets of 128 bytes of data and 1 final packet of 16 bytes of data. Let’s look at the final packet:
The highlighted bytes are our final 16 bytes of data. We saw before that the bootloader keeps count of how many bytes of data to expect, so although it will receive this whole packet, it will disregard the remaining 112 bytes.
Once all the data has been sent, the bootloader will send an End of Transmission byte (EOT):
Which the software will acknowledge:
Initializing the Applets
Once we have our application in SRAM, we need to initialise it. If we look at the structure of the mailbox our application uses:
We can see the first thing in the structure is the command, following by the status and then we have a union which defines the input variables depending on the operation. Since we want to be initialising the application, we’ll only focus on the initialisation input.
Let’s take a look at the command sent to the bootloader at this point:
Here we are writing some data to locations in SRAM:
- 0x00000000 at location 0x20001040
- 0x00000001 at location 0x20001048
- 0x00000001 at location 0x2000104C
- 0x00000000 at location 0x20001050
If we remember that the mailbox starts at 0x20001040, and each variable in the mailbox is a 32-bit integer (as per screen above), this translates to:
- 0x00000000 into command
- 0x00000001 into comType
- 0x00000001 into traceLevel
- 0x00000000 into bank
The commands are broken down in applets > saml21 > sam-ba_applets > common > applet.h
The command we are sending is APPLET_CMD_INIT, ie initialise the application. The COM types are broken down at the bottom of the applet.h file:
We don’t have to worry about traceLevel and bank.
The final command that the software sends is:
47 32 30 30 30 31 30 30 30 23 (G20001000#)
The G command is used to start the applet:
Just like at the start of the bootloader when we move to run the program in application memory, this too will tell the processor to start executing the program in SRAM:
Once the applet has finished, the processor will return to this point and come out of the call_applet() function and continue in the bootloader.
Now that everything is ready for the SAM-BA software to run, the only thing left to do is to fill the Memory Display in the SAM-BA window. By default, this shows the SRAM (0x20000000) when loaded:
Once done our SAM-BA Software is up and running.
Writing a Program
We are now ready to write a program to the bootloader. Fortunately, there is nothing different from what we’ve just done when connecting. When the SAM-BA software writes a new program to application memory, it sends the program as packets of data to SRAM, calls an applet which copies that program from SRAM into Flash. It does this repeatedly until the entire program has been sent:
As I mentioned at the start of this post, I shan’t go into detail about my adapted bootloader as I hope there’s been enough information here to give you a thorough understanding of how the SAM BA Bootloader works. The adapted bootloader I use in my application uses the SAM-BA PC software but has a modified version of the SAML21 program that we’ve been looking at. I personally think this is the easiest way to go about working with bootloaders as it’s much easier to adapt an already working bootloader to suit your own needs rather than try to write one from scratch along with the PC software to accompany it.