How to Add Bluetooth Low Energy (LE) Over the Air Download (OAD) to Basic Example#

Texas Instruments

1 - 2 hours read

Introduction#

Welcome to this laboratory on adding Bluetooth Low Energy (LE) Over the Air Download (OAD) functionality to a basic example! In this lab, you will learn how to enhance your Bluetooth LE application with OAD capabilities, allowing for wireless firmware updates.

Over the Air Download is a crucial feature in modern IoT devices, enabling remote updates and maintenance without physical access to the device. This can significantly reduce costs and improve the user experience for your Bluetooth LE products.

By the end of this lab, you will be able to:

  • Understand the basic components that need to be added to a project in order to add Bluetooth LE OAD capabilities.

  • Modify an existing Bluetooth LE example to include OAD functionality

  • Test the OAD process using provided tools

Let’s get started with upgrading your Bluetooth LE application!

It is recommended to first read the Bluetooth LE Over the Air Download (OAD) Fundamentals to understand the basics behind Over the Air Download functionality.

Prerequisites#

Hardware#

For this lab, you need one Bluetooth-enabled development board. Supported devices are:

Software and Tools for Development#

Basic Components to enable Bluetooth LE OAD#

To start on this Bluetooth LE Over-the-Air Download (OAD) journey, let’s explore the essential files and building blocks you’ll need to incorporate into your project. Later on, you will see where these files are available in the SDK.

  1. Writing into the NVS:

    • flash_interface_int_rtos_NVS.c: file that contains the functions required to write data to internal flash via RTOS NVS driver.

    • flash_interface_ext_rtos_NVS.c: file that contains the functions required to write data to external flash via RTOS NVS driver.

    • flash_interface.h: file that abstracts flash operations for OAD this allows on-chip and off-chip OAD to use the same flash APIs.

    • sw_update.c and sw_update.h: file that contains function for OAD image header validation.

  2. OAD GATT Service:

    • oad_profile.c and oad_profile.h: implements the TI proprietary OAD profile.

    • oad_service.c and oad_service.h: implements the TI proprietary OAD services.

    • oad_reset_service.c and oad_reset_service.h: implements the TI proprietary OAD Reset Service.

    For further details about the function of the OAD Profile and Service, please see the Section OAD Protocol/ Bluetooth LE Profile inside Bluetooth LE Over the Air Download (OAD) Fundamentals.

  3. Command Linker File symbols, structure and flash sectors allocations: Take a look at the .cmd file of a basic_ble project for reference on the structure and values that are used when implementing one of the three different OAD types. You can see what symbols and values will be used for each type of OAD by following the defines: OAD_APP_OFFCHIP, OAD_APP_ONCHIP, OAD_PERSISTENT, and OAD_DUAL_IMAGE.

  4. Generation of binary image file through imgtool: To create the images for the mcuboot to be stored in sections in flash also known as slots, there is a post-build-step added, which calls the mcuboot imgtool. The tool adds the 0x100 byte header (which includes information such as the version, image size, etc), and the trailer (which includes the key/hash/signature). The image can also be padded (–pad) to fill the slot size. The padding also adds some copy flags and status bits which are needed for Off-Chip OAD images. This means that Off-Chip OAD Images are required to be padded to the overall slot size (0x76000 in the examples). On-Chip images do not need to be padded.

Steps to add OAD components#

  1. Open the project Properties and go to BuildArm CompilerInclude Options and add the following file addresses:

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/third_party/mcuboot/boot/bootutil/include

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/third_party/mcuboot/boot/ti/source/mcuboot_app

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/ti/devices/cc23x0r5/driverlib

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/ti/drivers/nvs

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/ti/common/cc26xx/flash_interface

  2. Inside the project Properties go to BuildArm CompilerPredefined Symbols and add the following Pre-defined symbols depending on the type of OAD you are looking to implement:

    • APP_HDR_ADDR=0x32000

    • APP_HDR_ADDR=0x6000

    • APP_HDR_ADDR=0x6000

  3. Inside the project Properties go to BuildArm LinkerAdvanced OptionsCommand File Preprocessing and add the following Pre-defined preprocessor macro depending on the type of OAD you are looking to implement:

    • OAD_APP_ONCHIP=1

    • APP_HDR_ADDR=0x32000

    • OAD_APP_OFFCHIP=1

    • APP_HDR_ADDR=0x6000

    • OAD_DUAL_IMAGE=1

    • APP_HDR_ADDR=0x6000

  4. Inside the project folder, go to the common directory and create a new folder named Util and inside of this one, create another folder named SwUpdate. Then, add the following files inside:

    Inside SwUpdate, add:

    • <SDK directory>\source\ti\common\cc26xx\flash_interface\internal\flash_interface_int_rtos_NVS.c

    • <SDK directory>\source\ti\common\cc26xx\flash_interface\flash_interface.h

    • <SDK directory>\source\ti\bleapp\util\sw_update\sw_update.c

    • <SDK directory>\source\ti\bleapp\util\sw_update\sw_update.h

    Inside SwUpdate, add:

    • <SDK directory>\source\ti\common\cc26xx\flash_interface\external\flash_interface_ext_rtos_NVS.c

    • <SDK directory>\source\ti\common\cc26xx\flash_interface\flash_interface.h

    • <SDK directory>\source\ti\bleapp\util\sw_update\sw_update.c

    • <SDK directory>\source\ti\bleapp\util\sw_update\sw_update.h

    Inside SwUpdate, add:

    • <SDK directory>\source\ti\common\cc26xx\flash_interface\internal\flash_interface_int_rtos_NVS.c

    • <SDK directory>\source\ti\common\cc26xx\flash_interface\flash_interface.h

    • <SDK directory>\source\ti\bleapp\util\sw_update\sw_update.c

    • <SDK directory>\source\ti\bleapp\util\sw_update\sw_update.h

  5. Inside the project folder, go to the app directory and inside Profiles add the following file:

    • <SDK directory>\examples\rtos\LP_EM_CC2340R5\ble5stack\basic_ble_oad_dual_image\app\Profiles\app_oad.c

  6. Inside the project folder, go to the common directory and inside the Profile and Services folder individually create a new folder named oad. Then, add the following files inside each oad folder accordingly:

    Inside Profiles:

    • <SDK directory>\source\ti\bleapp\profiles\oad\oad_profile.c

    • <SDK directory>\source\ti\bleapp\profiles\oad\oad_profile.h

    Inside Services:

    • <SDK directory>\source\ti\bleapp\services\oad\oad_reset_service.c

    • <SDK directory>\source\ti\bleapp\services\oad\oad_reset_service.h

    Inside Profiles:

    • <SDK directory>\source\ti\bleapp\profiles\oad\oad_profile.c

    • <SDK directory>\source\ti\bleapp\profiles\oad\oad_profile.h

    Inside Services:

    • <SDK directory>\source\ti\bleapp\services\oad\oad_profile.c

    • <SDK directory>\source\ti\bleapp\services\oad\oad_profile.h

    Inside Profiles:

    • <SDK directory>\source\ti\bleapp\profiles\oad\oad_profile.c

    • <SDK directory>\source\ti\bleapp\profiles\oad\oad_profile.h

    Inside Services:

    • <SDK directory>\source\ti\bleapp\services\oad\oad_service.c

    • <SDK directory>\source\ti\bleapp\services\oad\oad_service.h

    • <SDK directory>\source\ti\bleapp\services\oad\oad_reset_service.c

    • <SDK directory>\source\ti\bleapp\services\oad\oad_reset_service.h

  7. Open SysConfig and search for TI-DriversNVS to add a new instance of NVS.

    Add a new NVS instance with the following configuration:

    • Name: CONFIG_NVSINTERNAL1

    • Use Hardware: None

    • NVS Type: Internal

    • Region Type: Pointer

    • Region Base: 0x32000

    • Region Size: 0x4A000

    Why do we need an extra NVS Internal instance? During the OAD process, the target device will receive segments of the OAD image through GATT writes operations. These segments need to be stored inside internal flash and this new instance is used for it. The Region Type is defined as Pointer as it uses a pointer to the memory location of a predefined internal flash region. In addition, the Region Base, where the OAD image is recaptioned, is defined as 0x32000 because it is the next memory address available in flash after the MCUBoot and persistent app images. Finally, the Region Size is set to 0x4A000 as it is the maximum space left to allocate the application image before reaching to the NVS section used for storing the Bonding information needed for some Bluetooth LE secure operations.

    Add a new NVS instance with the following configuration:

    • Name: CONFIG_NVSEXTERNAL

    • Use Hardware: MX25R8035F SPI Flash

    • NVS Type: External

    • Region Base: 0x0

    • Region Size: 0x100000

    Why do we need an external NVS instance? During the OAD process, the target device will receive segments of the OAD image through GATT writes operations. These segments need to be stored inside external flash through SPI communication and this new instance is used for it. The Region Base defines where in external flash the image will be written into, while the Region Size specifies the size of the external flash.

    Add a new NVS instance with the following configuration:

    • Name: CONFIG_NVSINTERNAL1

    • Use Hardware: None

    • NVS Type: Internal

    • Region Type: Pointer

    • Region Base: 0x41000

    • Region Size: 0x3B000

    Why do we need an extra NVS Internal instance? During the OAD process, the target device will receive segments of the OAD image through GATT writes operations. These segments need to be stored inside internal flash and this new instance is used for it. The Region Type is defined as Pointer as it uses a pointer to the memory location of a predefined internal flash region. It is important to remember that in Dual-Image OAD we need to consider saving space in internal flash for two identical size application images. Therefore, considering the MCUBoot image size and the size of the NVS section used for storing the Bonding information, the Region Base, where the OAD image is received, is defined as 0x41000 with a maximum Region Size of 0x3B000 (maximum space left to allocate the second application image before reaching to the NVS section used for storing the Bonding).

  8. Open again the project properties and go to BuildStepsPost-build steps and add the following three post build steps according to the OAD type you are implementing:

    • ${CG_TOOL_ROOT}/bin/tiarmobjcopy ${BuildArtifactFileBaseName}.out --output-target binary ${BuildArtifactFileBaseName}_noheader.bin --remove-section=.ccfg

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/tools/common/mcuboot/imgtool sign --header-size 0x100 --align 4 --slot-size 0x4A000 --version 1.0.0 --pad-header --key ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/third_party/mcuboot/root-ec-p256.pem ${BuildArtifactFileBaseName}_noheader.bin ${BuildArtifactFileBaseName}_v1.bin

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/tools/common/mcuboot/imgtool sign --header-size 0x100 --align 4 --slot-size 0x4A000 --version 2.0.0 --pad-header --key ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/third_party/mcuboot/root-ec-p256.pem ${BuildArtifactFileBaseName}_noheader.bin ${BuildArtifactFileBaseName}_v2.bin

    • ${CG_TOOL_ROOT}/bin/tiarmobjcopy ${BuildArtifactFileBaseName}.out --output-target binary ${BuildArtifactFileBaseName}_noheader.bin --remove-section=.ccfg

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SOURCE_SDK_INSTALL_DIR}/tools/common/mcuboot/imgtool sign --header-size 0x100 --align 4 --slot-size 0x76000 --version 1.0.0 --pad-header --pad --key ${COM_TI_SIMPLELINK_LOWPOWER_F3_SOURCE_SDK_INSTALL_DIR}/source/third_party/mcuboot/root-ec-p256.pem ${BuildArtifactFileBaseName}_noheader.bin ${BuildArtifactFileBaseName}_v1.bin

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SOURCE_SDK_INSTALL_DIR}/tools/common/mcuboot/imgtool sign --header-size 0x100 --align 4 --slot-size 0x76000 --version 2.0.0 --pad-header --pad --key ${COM_TI_SIMPLELINK_LOWPOWER_F3_SOURCE_SDK_INSTALL_DIR}/source/third_party/mcuboot/root-ec-p256.pem ${BuildArtifactFileBaseName}_noheader.bin ${BuildArtifactFileBaseName}_v2.bin

    • ${CG_TOOL_ROOT}/bin/tiarmobjcopy ${BuildArtifactFileBaseName}.out --output-target binary ${BuildArtifactFileBaseName}_noheader.bin --remove-section=.ccfg

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/tools/common/mcuboot/imgtool sign --header-size 0x100 --align 4 --slot-size 0x3B000 --version 1.0.0 --pad-header --pad --key ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/third_party/mcuboot/root-ec-p256.pem ${BuildArtifactFileBaseName}_noheader.bin ${BuildArtifactFileBaseName}_v1.bin

    • ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/tools/common/mcuboot/imgtool sign --header-size 0x100 --align 4 --slot-size 0x3B000 --version 2.0.0 --pad-header --pad --key ${COM_TI_SIMPLELINK_LOWPOWER_F3_SDK_INSTALL_DIR}/source/third_party/mcuboot/root-ec-p256.pem ${BuildArtifactFileBaseName}_noheader.bin ${BuildArtifactFileBaseName}_v2.bin

  9. Inside the project, go to app and inside app_main.c initialize and register the OAD profile and service, if not already done. To do this, include the following code lines to start the OAD service inside the App_StackInitDoneHandler() function where the other services are initialized.

    Start OAD service#
       App_StackInitDoneHandler() {
          //...
          status =  OAD_start();
          if(status != SUCCESS)
          {
             // TODO: Call Error Handler
          }
          //...
       }
       
    

Verify OAD functionality#

  1. Build the modified project.

  2. Once the project is built, use the <Project_Name>_v1.bin from the Release folder to flash the device following the steps mentioned in Bluetooth LE Over the Air Download (OAD) Fundamentals, section: OAD Target Setup. Make sure you follow the steps for the type of OAD you are implementing.

  3. Go back to the project and generate a second version of the image. For testing purposes, you can just modify the device name (BLEGeneral ConfigurationDevice Name) so that you can recognize that the new image has booted correctly when looking at the advertisement report data.

  4. Get the <Project_Name>_v2.bin file from the Release folder and transfer it to your phone (for example via cloud, email, etc).

  5. If you have not use Simple Link Connect mobile application before, you can take a look at TI SimpleLink™ Connect App for more details on how to use it.

  6. Open the Simple Link Connect mobile application, connect to the cc23xx device, select the OAD service, and select Add local file to load the <Project_Name>_v2.bin file you just transferred and click on Start the OAD process.

  7. Once the OAD update process has finished, click on Done and after the device resets itself, it should be using the new image (<Project_Name>_v2.bin), which can be identified by looking at the advertising data with the new device name you configured before (sometimes reconnecting and connecting again is needed to erase the previous name the mobile application might have cached).

Congrats! You have been able to add and test the OAD capabilities of your project!

References#

TI BLE5-Stack User’s Guide

TI CC2340R5 - Technical Reference Manual

Bluetooth Core Specification Version 5.3

TI SimpleLink™ Connect App

Bluetooth LE 5 Fundamentals

Bluetooth LE Scanning and Advertising

Bluetooth LE Over the Air Download (OAD) Fundamentals

Bluetooth LE - Security Fundamentals