nRF5 IoT SDK  v0.9.0
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
Create DFU images

Tools

The firmware image has to be in a binary format, so Intel HEX files must be converted to the correct format.

One alternative is to use the hex2bin available from SourceForge. In addition, each part of the firmware has to be correctly aligned, which is detailed in the sections below.

SoftDevice

We provide SoftDevice HEX files that are compiled. In order to prepare a SoftDevice to be upgraded, removing the MBR part of it is necessary. This part has several calls that are used by the bootloader to copy the new firmware (like a new SoftDevice or bootloader), and cannot be overwritten.

MBR for nRF52 consists of 0x3000 bytes. To convert softdevice.hex to softdevice.bin use the following commands:

For nRF52:

hex2bin -s 0x3000 softdevice.hex


Note
If the device has an existing application when performing a SoftDevice update, the application is erased. Because IoT DFU is triggered from an application context, the SoftDevice cannot be swapped as a single firmware without the application part. For more information about merging two binaries into one with a SoftDevice and application, see Merge binaries.

Application

The application is usually aligned with the size of the SoftDevice. A simple conversion will result in huge padding (equal to the size of the SoftDevice) inside the binary file. To avoid that, removing the SoftDevice's memory space is needed. The actual size of the SoftDevice where the application runs can be found in related documentation, project settings, linker scripts, or retrieved from the HEX file.

Addressing field inside Intel HEX (informative)

Lines in Intel HEX have the following format:

:AABBBBCCDDD....DDDEE

where:

  • ":" is the character which marks the start of a line
  • AA is the number of data bytes inside a single line
  • BBBB is an address field
  • CC is a command type code
  • DD..DD are data bytes
  • EE is a checksum of a single line

Each application (compiled to use a SoftDevice) starts with an address command.

:02000004XXXXF9

Where XXXX is a starting point of addressing inside following HEX lines. To read it, multiply this value with 2^16:

:020000040001F9

is:

0x10000

The next step is to get the start address (BBBB) from the first line with data and add the previous value to it. For example:

:020000040001F9
:10F00000007D002005F501000DF501000FF5010060

Which finally gives an address:

0x10000 + F000 = 0x1F000

Conversion

After obtaining the start address, the HEX file can be converted into binary form using the following command:

hex2bin -s START_ADDRESS nrf5xxxTARGET_CODE.hex

For the examples above this will be:

hex2bin -s 0x1F000 nrf52832_xxaa_s1xx_iot.hex

Bootloader

Bootloader conversion is similar to application conversion. After obtaining the correct start address, the following procedure works.

Conversion commands

hex2bin -s START_ADDRESS bootloader.hex

Example:

hex2bin -s 0x7D000 bootloader.hex

Merge binaries

In order to create a binary file that consists of a SoftDevice and application binary files, execute the following commands:

# On Linux.
cat SoftDevice.bin Application.bin > Merged.bin
# On Windows.
copy /b SoftDevice.bin+Application.bin Merged.bin
# Merged.bin consists of two firmware blocks.

Checksum calculation

To get the checksum of the binary file, our CRC16 library can be used. It can be found at SDK_PATH/components/libraries/crc16/crc16.c. The following code snippet shows how to use the crc16_compute function and compile it on a computer:

// File crc16_calculate.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
uint16_t crc16_compute(const uint8_t * p_data, uint32_t size, const uint16_t * p_crc)
{
uint32_t i;
uint16_t crc = (p_crc == NULL) ? 0xffff : *p_crc;
for (i = 0; i < size; i++)
{
crc = (unsigned char)(crc >> 8) | (crc << 8);
crc ^= p_data[i];
crc ^= (unsigned char)(crc & 0xff) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xff) << 4) << 1;
}
return crc;
}
int main(int argc, char *argv[])
{
FILE *f;
long fsize = 0;
uint8_t * p_data;
// Check if file path is passed
if (argc != 2)
{
return -1;
}
f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
p_data = malloc(fsize+1);
if (!p_data)
{
return -1;
}
fread(p_data, fsize, 1, f);
fclose(f);
printf("%d\n", crc16_compute(p_data, fsize, NULL));
free(p_data);
return 0;
}

The above program can be compiled using the following command:

gcc crc16_calculate.c -o crc16_calculate

The program reads an argument passed in the command line, treats it as a file path, calculates CRC16, and displays it in the standard output. Example usage:

./crc16_calculate firmware.bin