I have problem, I have to find a way to update code to my arm device without removing it, for that purpose I'll use serial communication. Does anyone have idea how to do it?
I have arm lpc2378 installed in my system, and I want to change my code through serial port, more than ones (when I find bugs), I have idea to reserve in scatter file memory for two functions and then, with help of some flag to decide which one to execute. My question is how I can write code in specific place in memory? And how to force processor to do it from that location?
Thank You a lot Ben
Hi Bojana,
You need to search for "bootloader" or "in-circuit flashing" or "in-system programming".
Looking at NXP, you find application notes like "AN10759 - USB secondary ISP bootloader for LPC23xx" attached to my post.
When writing a boot-loader generally the best place to start as Alban has suggested is to start with the microcontroller vendor application note and sample code. Usually there is an example for at least one communication interface. This will get you started at least with a very fundamental and proof-of-concept boot-loader.
For a production device, usually the example code provided by the vendor is not fit for production. It may not be completely robust, cover all use cases, be able to properly recover from power outages or other unexpected events. Usually it won't completely fit requirements, require additional features and usually they don't follow good programming practices. (I'm not bashing, the point is to help get something going on their chip not provide their clients with a production solution).
In this case there are three options
1) Make all necessary updates and productionize (not sure its a word but I'm going with it) the code yourself
2) Hire a consultant to do the updates
3) Purchase an off-the-shelf production ready boot-loader
Bootloaders are exciting and can be challenging but if you have any questions please feel free to post a question and mention me and I will do my best to answer or feel free to contact me directly.
Jacob Beningo it was very useful reading your document, It was written in simple word, but you explained procedure how to do update. But I have now more questions ( the more I learn the more I realize how much I don't know ) 1. What happens if during execution of boot-loader application power off? Then I lose that chip? Because of that I had idea to have to programs old one and new one in memory, and if happens during writing new one power off, I can continue execution of old one, and then write new one in another memory location.2. You sad couple of times boot-loader image and application image did You mean hex file or similar?3. And finally how to update linker ?
2: The boot-loader image is a short program, which is started always. The application-image is the program that you design. The boot-loader image starts your application image.
1: You never erase your bootloader image, because only your application image should be changed. That means when your chip is powered on, your boot-loader is started, it checks if the application-image is OK (by verifying that the checksum / CRC for the entire application-image is OK).
3: You will need to change the linker-scripts, so that your application-image will be placed after your boot-loader. Otherwise your boot-loader would be overwritten on update (we do not want that). The boot-loader should be written, so it does not allow overwriting the boot-loader.
Imagine that you have written your boot-loader now, and the boot-loader requires a header in the application-image, plus a trailing check-word...
Header; this is what it would look like in assembler:
app_start:
b code /* assembler-instruction that jumps to the actual application code */
.word applicationLength
.word CRC
.word Adler
code:
... your application code (C-code) here.
.word 0xfeedface
end:
Now, your boot-loader first checks if the word at app_start+applicationLength contains the value 0xfeedface. If it does, it calculates both the Adler and CRC checksums for the entire block. If both CRC and Adler checksums match for the entire block, the code is valid and can be executed.
If the code is not valid, it will not be executed, thus the boot-loader will keep waiting for you to send another update.
Note: Both the CRC and the Adler checksums should be calculated when you generate the application image, before you upload the application image to your microcontroller.
Using this model, it would be possible to have the boot-loader check a flag and write the application to one of two different places in memory.
For instance: If our application-image can be placed in memory-blocks 0x00004000 ... 0x0001ffff and 0x00024000 ... 0x0003ffff, our flag may be written to address 0x00024000 and have either value 0 or value 1.
If the value of the flag is 0, then the boot-loader will prefer executing the application image at address 0x00004000. But if that code is invalid, the boot-loader will check if the application image at 0x00024000 is valid and execute that application image instead (if it's valid). If both images are invalid, the boot-loader will just wait until an application image is sent (via UART), so it can write it.
So if we're sending an application image to the boot-loader, the boot-loader will check if the flag is 0 or 1 (if the flag is any other value, the boot-loader will just pretend that the flag is 0)
If the flag is 0, and the application image at address 0x00004000 is valid, then the boot-loader will now write the new application image at address 0x00024000, in order to avoid overwriting our preferred application image, which we know works. After writing the new application image (which will have both the Adler and the CRC checked while writing), the boot-loader will write 1 to the flag if both Adler, CRC and the 0xfeedface word is valid, so that the new application image will be preferred, otherwise the flag would still be 0.
... On next update, the application image would then be written to address 0x00004000, because our flag is set to 1 (so we prefer the application image at 0x00024000), and after writing the new image, the flag is set to 0 (but only if the Adler, the CRC and the 0xfeedface words are valid, otherwise the flag would still be 1).
The above has been marked as 'advanced topic', because you would need to make the boot-loader relocate the application image somehow, because the linker would not know where the application-image ends up in Flash memory. This means your boot-loader would have to change the addresses in the application image, before writing the image to flash-memory.
That can be done by first loading the sector to write into SRAM, modifying the addresses, then re-calculating both the ADLER and CRC for this block and finally writing the sector.
The last sector you want to write, would be the sector at the starting address, because it contains the CRC and the Adler checksum.
As an alternative, it would be possible to have the CRC and Adler checksums at the end of the application image, but having them in the beginning is slightly safer.
Note: Both the old and the new CRC and Adler checksums should be calculated. The old: In order to verify that the application image sent from the computer is 100% OK, the new: n order to make the application image executable.
Thank You jensbauer. Is more clear to me now theoretically, that two application image is exactly what I wanted to do, but I'm new at controller programming and this is too abstractedly to me, does anybody has example code related with this topic?
I think that ARM should provide example code with updating, because is common and not unusual thing, and about that topic is so little information online. That is my suggestion.
Unfortunately I don't see how ARM could provide such code.
Bootloader is about:
Yes, and in addition, the vendor may choose different addresses for the Flash memory.
Some may use external memory, so it would be difficult for ARM to provide source-code that would work on all platforms.
The CRC and Adler routines would be generic, though, and the routine that performs the checks could take an address that points to SRAM and an address that points to Flash memory.
A number of routines would need to be supplied externálly, such as the routine that receives data and the routine that writes to Flash memory.
In short: Anything that contains hardware access would be vendor-specific and require a routine for each MCU type.
(I'll be off to vacation in one hour, so it might take a while before I am able to respond).
Having two application images uses the same theory that you would have with just one. Instead of having linker space carved out for bootloader and application, you now have space for boot-loader, application1 and application2. The boot-loader then needs to be more intelligent to know when application it should be updating and loading into on boot. Once again if you have managed to succeed with a single application then having the second just adds a few additional checks. Mainly
1) Which application to jump to?
2) Is this application checksum correct?
3) Which application space to erase and overwrite?
4) Should a failed update automatically revert to the other application area if checksum is valid?
One thing you need to make sure of is that you secure the flash space that the boot-loader is in. If power is removed during update the boot-loader should load and wait for instructions. I've seen poorly written boot-loaders that allow the boot-loader to be updated which in the event of power failure or other issues will brick the unit. The boot-loader needs to be extremely robust and secure or protected with an MPU (if one exists on chip).
I would recommend that instead of jumping straight to a two image system you first write a simple boot-loader, with minimal features and a single application. Get that working well and then add features to it like securing the device, adding the second application space, etc.