Firmware Programming Guide

Introduction

This programming guide describes the steps necessary to create firmware update images for the Bluetooth 5 co-processor embedded inside the IG60-BL654.

It includes a detailed memory map of the Bluetooth co-processor, how to acquire and flash images, and more.

Memory Map

The IG60's onboard BL654 features a Nordic nRF52840 Cortex M4 MCU which stores the bootloader code and user application. Some of the space in the processor is reserved and cannot be used by the user application. Additionally, an external 2MB flash memory part with a QSPI interface is used for intermediate storage.

Available memory areas are shown in Table 1: Memory map.

Table 1: Memory map

The bootloader may (at any time) use this space and erase or alter its contents. User applications can therefore use this as temporary storage, which, if erased, does not impact the user application. A header and checksum should be used to ensure that data stored in this area is valid. |
Start End (Non-inclusive) Size Purpose For Customer Use Description
0x000000 0x001000 0x001000 Nordic MBR (Master boot record) NO Nordic library for setting up the module and loading the bootloader.
0x001000 0x0D7000 0x0D6000 User application YES The user application is stored here.
0x0D7000 0x0EA000 0x013000 Bootloader scratch area YES / NO The bootloader may (at any time) use this space and erase or alter its contents. User applications can therefore use this as temporary storage, which, if erased, does not impact the user application. A header and checksum should be used to ensure that data stored in this area is valid.
0x0EA000 0x100000 0x016000 Bootloader NO This contains the bootloader.
0x12000000 0x12200000 0x200000 Bootloader Storage (via QSPI) NO This area maps to the QSPI chip and is used for storing bootloader images. It can be used (via the included API) to store update images only.

Size Notes:

  • Total size of nRF52840 – 0x100000 (1 MB)
  • Total size of overheads (including MBR, bootloader and scratch area) – 0x02A000 (168 KB), 16%
  • Total size of space available for user application: 0x0D6000 (856 KB), 84%
  • Total size of QSPI: 0x200000 (2 MB)

Figure 1 – BL654 memory map

figure1

Figure 2 – External QSPI flash memory map

figure2

Software Required

BL654 Firmware Loader

The Laird Connectivity Sentrius IG60 firmware contains a command-line utility that can be used to upload a firmware image update file (.UBU) to the embedded BL654, then reset the BL654 to trigger the firmware update. The command line to run the firmware loader (e.g., from a shell, or from a Lambda function running in AWS Greengrass):

btpa_firmware_loader.py /dev/ttyS2 115200 <path to UBU file> BL654

The script will then parse and upload the bootloader update to the embedded BL654, and then trigger a reboot to apply the update. Upon success, the script will return 0 (zero), otherwise, a Linux error code (e.g., EPERM) will be returned.

UBUtil

UBUtil is used to generate key pairs and firmware update images. For the BL654, v0.28e is required. It is available in Windows, Linux and Mac formats.

ARM GCC tools

If the Nordic Softdevice is being used, then the ARM GCC utilities are required in order to separate the Nordic MBR and Softdevice. The utilities can be downloaded from the ARM site for windows, linux and mac. The arm-none-eabi-objcopy utility is required from this package.

Hex editor

If the Nordic Softdevice is being used, then a hex editor utility is required in order to separate the Nordic MBR and Softdevice. For this guide, HxD for Windows is used which can be downloaded from mh-nexus.

Generating Firmware Updates

Firmware update files are generated using the UBUtil application.

It is passed hex or binary files, a private key and command line arguments. A single UBU file (.ubu file extension) is generated from these inputs. The UBU file is used to update single, or multiple images on a target, dependent upon the number of hex or binary files passed during its creation.

Generating a key pair

A private key is required to sign firmware images. For security purposes, all projects should have unique private keys. These should be stored on a secure server or system, ideally one that has no internet access.

Similarly, a public key is required to validate content signed with the private key. As its name suggests, the public key can be freely distributed, whereas the private key must be kept secret.

The UBUtil application can be used to generate a PEM key pair file (.pem file extension). The --create-key argument followed by the output filename is used to create the key pair. For example, using the command:

UBUtil --create-key Blinky.pem

Will produce output as follows:

Laird Connectivity Universal Bootloader Update Hex Generation Utility
  v0.25
    Built Oct 18 2019
 
Successfully generated signing key file Blinky.pem.
Public key (hex): 0956845803d675ad448d4f9dec970abf06b4f64a6651661f01c9b1fc906f2760ea36eb0c43ee4305b59273cdf79bdc908aa4eb6d503c78303812040c7d3cbb9a

Outputting a Private or Public Key

UBUtil can be used to output the private key or public key from a generated PEM file. To do this, the --file-info argument is used along with --file-key to specify the type of key (0 will show the private key and 1 will show the public key).

To show the private key, the following should be used:

UBUtil --file-info Blinky.pem --file-key 0
Laird Connectivity Universal Bootloader Update Hex Generation Utility
  v0.25
    Built Oct 18 2019
 
Private Key: 82c2e8f0c2b4983bcf5a2f6b3ec20d0ace8561d369e1bb36996124e7fb4b1dfa

To show the public key, the following should be used:

UBUtil --file-info Blinky.pem --file-key 1
Laird Connectivity Universal Bootloader Update Hex Generation Utility
  v0.25
    Built Oct 18 2019
 
Public Key: 0956845803d675ad448d4f9dec970abf06b4f64a6651661f01c9b1fc906f2760ea36eb0c43ee4305b59273cdf79bdc908aa4eb6d503c78303812040c7d3cbb9a

The public key must be loaded into the bootloader on a module so it will accept the signed firmware updates. This is achieved by use of the --append-pub-key command when generating a firmware update package.

Generating a Firmware Update Package

To generate a firmware update package, an application is required which will run on the IG60's embedded BL654. Once an application is ready and a key pair has been generated as detailed in the Generating a key pair section, then a firmware update package can be generated.

UBUtil can generate a firmware update package which consists of multiple files (named ‘partitions’) which correspond to different items. For example, if an application consists of one part of executable code from 0x1000 – 0x3960, another part of executable code from 0x7000 – 0x71A0 and a static configuration area from 0x8000 – 0x9000, then this update would consist of 3 sections/partitions.

UBUtil has many command line options. Global options apply to a UBUtil execution as a whole and are summarised in Table 2 – UBUtil global options.

Table 2 – UBUtil global options

Command Purpose
--append-pub-key If specified, then will append the public key from the input key file to the output.
--application-key-file Specifies the file where the private key resides.
--arg-file Specifies an optional file which contains an argument list.
--create-key Specifies the filename of private/public keypair to generate.
--file-info PEM/hex/bin file to display information for.
--file-key 0 – 1, 0 shows private and 1 shows public key of an input PEM file.
--license Outputs third party license information.
--output Specifies the output hex file to create.
--output-headers If set, will generate header output files.
--prepend-pub-key If specified, then will prepend the public key from the input key file to the output.
--ubu-align-length For ubu files, specifies the alignment of the length. This should be set to 4.
--ubu-base-address For ubu files, specifies the base address. This should be set to 0.
--ubu-flash-size For ubu files, specifies the flash size. This should be set to 2097152.
--ubu-output Output ubu file for BL654 Firmware Loader firmware updates.
--ubu-platform For ubu files, specifies the platform. This should be set to 5ECB654F for the IG60's BL654.
--ubu-sector-size For ubu files, specifies the sector size. This should be set to 4096.
--version Outputs version information.

Command line arguments can also be applied to application sections (where X is a number between 0 and 15), with these being summarised in Table 3 – UbUtil section options.

Table 3 – UbUtil section options

Command Purpose
--aX-compressed If used, will compress the data in this section.
--aX-endaddress End address, this is only used for special sections.
--aX-extradata Extra data section, this is only used for special sections.
--aX-filename Input file to use for section.
--aX-filetype Specifies the file type. Refer to section File Types.
--aX-header Pre-generated header, this should only used when including bootloader updates.
--aX-keytype 0 – 1, always specify 1 for this parameter.
--aX-size Size of section, this is only used for special sections.
--aX-startaddress Start address.
--aX-target Always specify 0 for this parameter.
--aX-version 0 – 65535, version of application

The following will create a firmware update for an application named Blinky.hex, with version number 1, which will be compressed, using a private key named Blinky.pem which includes the public key in the output.

UBUtil --application-key-file Blinky.pem --a0-version 1 --a0-compressed --a0-target 0 --a0-startaddress 0x1000 --a0-filetype 1 --a0-filename Blinky.hex --a0-keytype 1 --append-pub-key --output BlinkyPackage.hex --ubu-output BlinkyPackage.ubu --ubu-platform 5ECB654F --ubu-flash-size 2097152 --ubu-sector-size 4096 --ubu-base-address 0 --ubu-align-length 4

The output will be similar to the following:

Laird Connectivity Universal Bootloader Update Hex Generation Utility
  v0.25
    Built Oct 18 2019
 
Using application Blinky.hex (8192 bytes)...

Section 0:
        Section Start: 0x4000
        Section End: 0x4539
        Section Size: 0x539
        Target: 0
        Target Start: 0x1000
        Target End: 0x3000
        Target Size: 0x2000
        Compressed: 1
        Version: 1
        Force: 1
        Checksum Type: 3
        Image Checksum: 0x1f03ebea
        Target Checksum: 0xaaaac22b
        Signature Type: 1
        Application Type: 0
        Filename: Blinky.hex
        Extra data:
        Signature (hex): 7d6ebb8058a39d9dd8ed6dd02faa17fffb74b8f8030e1fbc7fac76d
a9554c2481fab22ff3cef024bd8a7d67f045d933e6dc7c868a453e227d1b2b5fbbe9f116b
 
Total uncompressed section size: 8192
Total compressed section size: 1337
Section compression: 84%
 
51000 bytes written to BlinkyPackage.hex successfully.
17268 bytes written to BlinkyPackage.ubu successfully.

Flashing a Firmware Update Package

Flashing a firmware first requires an update package to be generated. The instructions in Generating a Firmware Update Package should be followed before continuing.

Once you have generated a firmware update package, you can use one of the following methods to upload and flash the update.

Performing a firmware update interactively in a shell

Once you create the firmware update, copy the UBU file to the IG60 (e.g., using a method such as 'scp' to remote copy, or transfer via removeable storage such as an SD card). You can then use the firmware upload utility in the IG60 firmware as described in the BL654 Firmware Loader to upload the file; e.g.:

btpa_firmware_loader.py /dev/ttyS2 115200 myFirmware.ubu IG60

Performing a firmware update via AWS Greengrass Lambda

Refer to the fwloader sample in the IGSDK for details on how to package a firmware update into a Lambda, then update the firmware by deploying the Lambda to the IG60 via AWS Greengrass.

File Types

The following table lists the types of files, their corresponding ID and any restrictions on them. The ID is the file type which is passed to the UBUtil executable when generating firmware update packages.

ID Type Restrictions Purpose
1 Main Application Must be between addresses 0x1000 – 0xD7000. Refer to section Appendix A – Setting the Application Start Address for further details. Executable main application code.
3 Soft-device Must not contain the MBR, must be between addresses 0x1000 – 0xB0000. Refer to section Appendix A – Setting the Application Start Address for further details. A Nordic Softdevice based protocol stack.
4 User configuration A Must be at address 0x2000 or greater. Static non-executable user configuration data.
5 User configuration B Must be at address 0x3000 or greater. Static non-executable user configuration data.
12 Public key Public key of the private key which was used to sign firmware updates.