Description
This story gathers all the information and ideas about the firmware update process: strategy, support, security, tests, etc.
Related epic/story: n/a
.hex
or .bin
?
The question asked is should we send the update as a .bin
file or .hex
.
The question was asked to the community here:
ARM Mbed OS Forum - Firmware Update w/ FlashIAP - .bin or .hex?
The answers provide useful information:
.bin
is smaller than .hex
.hex
incorporate a checksum for each lines
.bin
allows for custom binary framing to provide additional information
.bin
allows for custom frame length to send more information each time
With those information, the .bin
approach seems to be better in many points.
QSPI Flash or SD Card
Following the ".hex
or .bin
?" question, we must investigate and decide if we want to use SD Memory Card or QSPI Flash.
Pros of the SD Card:
- we can use a FileSystem to store the
.bin
- we can write frames by frames, we don't have to worry about sector/page size, etc.
- we have a lot of available memory so we can store a lot of versions if roll back is necessary
- we can store config files as well
Cons of the SD Card:
- we need the FileSystem in the bootloader which can add some memory consumption
Pros of the QSPI Flash:
- we just need QSPI Flash
- memory is safe and strong
Cons of QSPI Flash:
- we must deal with sector/page size when writing to the external memory
- we can store only one previous version
- we need to use KVStore to store external info (old/new version number, checksum, size, etc.)
With those information, QSPI Flash seems to be a good candidate for simple systems with low resources and low memory available.
On the other hand, the SD Card approach gives us a higher level view of the subject and allow us to use concepts closer to those of a regular computer. The SD Card can also be flashed before and more testing can be done.
In conclusion:
- we can keep one QSPI Flash for factory firmware (we need to understand how to flash it)
- the update process can use the SD Card with a dedicated directory
Update workflow
⚠️ to do
Security
For firmware update through untrusted channels (BLE, Wifi, etc.), security is paramount! We can distinguish two types of security:
Signing means that the content of the file is signed, a hash is generated and it can be checked to make sure it comes from Leka and not from someone else. With just signing, the content of the firmware update is visible to the external world.
Encrypting means that from the original content we generate a cyphered version of the update that has to be decrypted once on the device. If someone steals the update, they won't be able to read it's content.
Both signing and encrypting must be done on the firmware sent for the update.
Useful links:
Frame structure
The .bin
approach lets us use a custom binary frame for the data we send.
Source: Specs-FOTA-Frame.gsheet
Item |
Size |
Type |
Content |
Comment |
Start bytes |
4 bytes |
array[4] {uint8_t} |
[2A 2B 2C 2D] |
Start sequence to recognize a frame |
Header |
|
|
|
|
Size |
1 byte |
uint8_t |
|
The size of the data contained in the current frame (1..256 ) |
Data type |
1 byte |
uint8_t |
- 00 - Firmware version - 01 - Firmware size - 02 - Number of frames to receive - 03 - Global CRC |
The type of data received |
CRC |
1 byte |
uint8_t |
|
CRC Checksum of the current frame's data (⚠️ to be investigated) |
Data |
|
|
|
The data contained in the current frame. It can only be of one type |
Firmware version |
3 bytes |
array[3] {uint8_t} |
major minor patch |
|
Firmware size |
4 bytes |
uint32_t |
|
Total size of the firmware to be sent |
Number of frames to receive |
4 bytes |
uint32_t |
|
Number of frames to be sent for the update |
Global CRC |
4 bytes |
uint32_t |
|
CRC Checksum of the firmware |
Stop bytes |
4 bytes |
array[4] {uint8_t} |
[2D 2C 2B 2A] |
Stop sequence at the end of a frame |
Proofs of concept
1. First Leka Bootloader
- understand how the bootloader works with mbed-config
- create a simple bootloader running in a loop
- send an application and write it to MCU Flash (w/ FlashIAP)
- send an application and write it to QSPI Flash first, then to MCU Flash (w/ FlashIAP)
♻️ Steps
Step 1.1
Hello, I'm the bootloader!
I'm waiting for 5 seconds before starting the application...
1... 2... 3... 4... 5...
Starting application now!
Hello, I'm application!
I'm running in a loop.
1
2
3
// [...]
Step 1.2
Hello, I'm the bootloader!
I'm waiting for an application to be sent to me...
1... 2... 3... 4... 5... // [...]
An application is available! I'm writing the application to MCU Flash!
// [...]
Application written to MCU Flash!
Starting the application now!
Hello, I'm application!
I'm running in a loop.
1
2
3
// [...]
Step 1.3
Hello, I'm the bootloader!
I'm waiting for an application to be sent to me...
1... 2... 3... 4... 5...
An application is available! I'm writing the application to QSPI flash!
// [...]
Application written to QSPI!
I'm writing the application to MCU Flash!
// [...]
Application written to MCU Flash!
Starting the application now!
Hello, I'm application!
I'm running in a loop.
1
2
3
// [...]
2. In application update
- start the application and have the application wait for a new version
- store the new version to QSPI Flash
- reboot and write the application to MCU Flash
♻️ Steps
Step 2.1
Hello, I'm the bootloader!
Checking if a new application is available...
No application available.
Starting current application now!
Hello, I'm application!
I'm running in a loop waiting for an new application to be sent to me...
1
2
3
// [...]
An application is available! I'm writing the application to QSPI flash!
Application written to QSPI!
Rebooting...
Hello, I'm the bootloader!
Checking if a new application is available...
New application available!
Now I'm written the application to the MCU...
Application written to MCU.
Starting new application now!
Step 2.2
to do