This knowledge-base post discusses the three current methods for programming a BT121 module with a .bin firmware image file.
The firmware image files can be either 1] one of your own files with your own customized firmware obtained by running the bgbuild.exe free compiler found inside the Smart Ready SDK (this is the typical case), or 2] one of the pre-compiled images available in the SDK within the example project directories.
The three methods are exposed below, but before getting into that you might want to take a moment and read about the module’s factory default firmware here.
- This method allows the MCU in a host system to re-program the BT121 over the UART interface using BGAPI commands which are similar to the rest of the commands used for controlling and configuring the module in its normal operations.
- The best way to understand how this method works is to read through the source code of the host example program found under the directory \host_example\dfu\ of the SDK (since version 1.1.0 build 154.)
- With the first release of the firmware (version 1.0.0 build 97) the guidelines were as follows:
when the BGAPI-based bootloader is ready for the DFU upgrade, for example after soft rebooting into DFU mode using the BGAPI/BGScript command system_reset(1) without raising the BOOT0 pin, the first command to enter over the UART host interface is the dfu_flash_set_address(...) with address of 0x00000000.
Next step is to issue as many dfu_flash_upload(...) commands as there is data to extract from the whole .bin firmware image file. These multiple commands are issued to upload to module the full firmware file. Pointer to the next intended flash memory address to write to is automatically updated by the bootloader code after each command.
When all raw binary data from the .bin image is sent to module, finalize the process by issuing the dfu_flash_upload_finish() followed by the dfu_reset(0) to restart the module in normal mode with the new firmware.
- With BGAPI-based DFU the UART configuration depends on the hardware.xml project file that defined the whole hardware configuration at the time the firmware currently running in the module was built. This means for example that the UART configuration of the BGAPI-based bootloader in a module still running the default factory firmware is 115200, 8N1, with flow control.
- Starting from the version 1.1.0 build 154 a new bootloader is officially in use, which is 4KB in size instead of 8KB. This requires a BGAPI-based DFU re-flash to take this into account when upgrading from any earlier release.
In this case, a BT121 firmware upgrade consists then of two parts: updating the bootloader first, and updating the firmware itself thereafter.
The bootloader version is given by the dfu_boot event that follows a system_reset(1). Currently it is 1 for builds 97-138 and 2 for builds 139 onward.
Notice that the Smart Ready software in the module depends on its specific companion version of the bootloader: in fact, the Smart Ready stack will not start if the bootloader version does not match, in which case the module will keep on rebooting into the DFU mode.
The bootloader cannot be downgraded to the older version using BGAPI-based DFU. To return to build 138 or older, one of the ST-based re-flashing methods must be used instead (see methods 2 and 3 below.)
The C source code example under the directory \host_example\dfu\ of the SDK (since build 154) was indeed introduced to show how to perform the bootloader and firmware update using BGAPI, and it works fine for old to new firmware upgrades and also for new to new firmware upgrades (for old to old firmware upgrades, you might need to edit the code to discard the new firmware check in the example from SDK 154, or simply refer to the improved version found in SDK build 168 or later.)
- The new procedure to update the firmware using BGAPI-based DFU is as follows:
1) Reset to DFU mode
a) Send system_reset(1) to reboot the module into DFU mode.
b) Wait for dfu_boot event. Check the version parameter. If it is 2, then proceed to section 3,
otherwise proceed to section 2.
2) Bootloader update
a) Send dfu_flash_set_address(...) using address of 0x2000
b) Upload all except the last 2KB (2048 bytes) of the .bootdfu temporary image file
generated by the bgbuild.exe using dfu_flash_upload(...)
c) Send dfu_flash_set_address(...) using address of 0x1e800
d) Upload the last 2KB of the .bootdfu file using dfu_flash_upload(...)
e) Send dfu_flash_upload_finish()
f) Send dfu_reset(0)
g) Wait for dfu_boot event. Check version. If it is 2, then proceed to section 3.
Otherwise there was an error, thus go back to 2a and repeat the steps.
3) Firmware update
a) Send dfu_flash_set_address(...) using address of 0x0
b) Upload the whole .bin firmware image using dfu_flash_upload(...)
c) Send dfu_flash_upload_finish()
d) Send dfu_reset(0)
e1) system_boot event is received. Firmware has been successfully updated
and module is ready to use...
e2) ...or dfu_boot event is received, meaning that there was an error updating
the firmware. Go back to 3a and repeat the steps
- Below is a screenshot of the dfu.exe in action. The executable was built with Visual Studio Community 2015 directly from the sources at the directory \host_example\dfu\ of the new SDK. Again, this source example provides the principal mean to understand (and use) the BGAPI-based re-flashing.
- This method can be carried on among others by using either the bgupdate.exe found inside the \bin\ directory of the SDK, or via the "Upload tool" section of the BGTool Windows demo program (which actually uses the same code as the bgupdate.exe)
This is the preferred method if you have the DKBT development kit, because our tools will recognize the Prolific USB-serial chip in the main board and will use this chip to assert the BOOT0 pin and reset the module.
Only starting from the SDK version 1.1.0 build 154 the tools work also without the Prolific chip, but you will have yourself to first reset the module while asserting the BOOT0 pin. More on this below.
- Details about this method:
when you keep the BOOT0 pin high while resetting the module, the ST bootloader will not launch the Smart Ready software's own bootloader (which implements the BGAPI-based DFU functionality seen above) which in turn will then not launch the Bluetooth Smart Ready stack. In that case, the ST bootloader will remain waiting for the host system to start communicating using the ST protocol to re-flash the module over the UART.
As for the UART configuration in use by the ST bootloader, notice that RTS/CTS flow control is not required, 8E1 is in place, and baudrate is auto-sensed, however the host is recommended to use half a MBaud or less.
This is actually what our bgupdate.exe tool mainly does under the hood. In particular, starting from the version found in SDK build 154, the bgupdate.exe (and the re-flashing functionality in the BGTool) has been improved so to recognize if the Prolific chip is in use. If not, then just the ST-based re-flash will be carried on, otherwise the chip is used to reset the module while asserting the BOOT0 pin, before starting the ST-based re-flash.
In other words, if the Prolific chip is recognized to be present, then it will be used to assert the BOOT0 line and to reset the module before proceeding with the ST-based re-flash. And if the Prolific chip is recognized to not exist instead in between, then the bgupdate.exe will not get stuck like with the previous release, but will immediately talk the ST protocol for the re-flash, meaning that the utility should be launched only after the module has been reset, with the BOOT0 asserted, by some other mean that is up to the customer to define.
- Below you will find some screenshots showing the usage of bgbuild.exe (for building your custom firmware image based on your own firmware project files) and of bgupdate.exe (for uploading your firmware to module) and you will find as well the corresponding screenshots when BGTool is used instead:
- With this method it is possible to re-program the BT121 over its ARM Serial Wire Debug interface
- SWD pins are PA13=SWDIO and PA14=SWCLK
- As an example, the CLI version of the STM32 ST-LINK Utility could be used and typically the following command would be used:
"C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe -c UR SWD SWCLK=0 -P BT121_BGAPI_UART115k.bin 0x08000000 -V -Rst"
See the command in action in the screenshot below. This command should be launched while the module is under reset, and the process will start after the reset is released. Notice also the address of 0x08000000 in use here: according to the memory map of the microcontroller inside the module, the Flash memory boundary addresses are 0x08000000 - 0x0801FFFF (as a side note, address of 0x0 used by the dfu_flash_set_address in our BGAPI in fact corresponds to the 0x08000000 boundary address.)
MAC address considerations
There are cases when the current MAC address in use will go lost during a re-flash. Please see more in the knowledge-base article here.
As for the Over-the-Air (OTA) upgrade, contrary to the BGM and BLE products unfortunately the bootloader of the BT121 does not support it at the moment.
With that being said, you could still make OTA upgrades if you would arrange to first send the firmware image over a Bluetooth link to the host system, and then let the host system to locally upgrade the module over UART using for example the BGAPI-based DFU.
I could not find any dfu.exe file in the SDK, so where can I find such executable?
The dfu.exe is not included in the SDK, but must be created by the customer from the sources in the SDK under the directory \host_example\dfu\ for a specific platform. The one shown in the first screenshot of this article was created using the Microsoft Visual Studio for testing in a Windows PC.
What are the reasons to change the bootloader from v1 to v2? Bug fixes or implementation of a better protocol?
The only reason was to free 4KB of Flash memory. Remember here that, because of memory remapping the bootloader v2 is needed to launch the Smart Ready software created with build 154 and above.
What will it happen if the BGAPI-based bootloader update procedure is failed or interrupted or mis-handled? Will the bootloader die?
You will have no other option than to recover the module using the ST-based re-flash over UART (or SWD re-flash). This to say that it is impossible to brick a module, since it will always be recoverable over the last two methods mentioned above. In other words, it is always possible to recover a module with the ST-based DFU over UART or via the SWD interface if there is no hardware failure.
Does a *.bin image file contain the BGAPI-based bootloader?
Yes, all .bin firmware image files contain the appropriate Smart Ready software’s own BGAPI-based bootloader. The ST-based re-flash methods always write also such bootloader, which is included in the .bin file, on top of the existing one. On the other hand, the BGAPI-based bootloader is designed not to overwrite itself during the BGAPI-based DFU re-flash (when for instance you are performing a normal re-flash after sending the dfu_flash_set_address(...) using address of 0x0), and in fact when you think you are writing the sectors containing the bootloader code, these very bytes are silently discarded.
Each dfu_flash_upload(...) command writes 128 bytes to the flash. The filesize of .bootdfu is 12,288 (0x3000) bytes. For step 2b, it needs (12288-2048)/128 = 80 of dfu_flash_upload(...). For step 2d, 2048/128 = 16 of dfu_flash_upload(...). Are these figures correct?
Yes, they are correct.
For step 2c, the starting address is 0x1e800 (or 0x0001e800). If BGAPI binary code is used, is it 0x20 04 00 01 00 01 e8 00 ?
The binary string is actually 0x20 0x04 0x00 0x01 0x00 0xe8 0x01 0x00 (remember little endian – and, well, you should not worry about this as the BGLib-based code under the directory \host_example\dfu\ should automatically take care of creating the right binary sequence.)
Is the .bootdfu that is generated with the SDK build 154 (or newer) fixed, or does it change always when building a project? Can we just build it once and use that version of the .bootdfu regardless of changes to the project files?
The .bootdfu file changes only if the hardware.xml is changed, because the bootloader will get the UART configuration from the hardware.xml
You can keep on using the same .bootdfu file, provided that 1] you keep into account its UART configuration at the time it was built (bootloader's UART configuration might not match the UART configuration of the Smart Ready software if the latter was changed in the meantime via a new different hardware.xml) and 2] you are not going to program an older Smart Ready software which would be incompatible with the bootloader v2
Every time I load a new firmware image, I can no longer connect to the BT121 from my Windows PC, using SPP, unless I delete the bonding and re-create it.
The bonding information stored in the Flash memory of the BT121 is preserved if re-programming of the module happens via the BGAPI-based DFU. Bonding information is instead deleted with any other re-flashing method. So, depending on the re-programming method of your choice, and depending on the Bluetooth stack running at the remote side, you might have to remove the BT121 from the bonded devices listed at the remote side after a module's update.
Could you tell us more about CRC checksums, if any is used within a firmware image?
Please have a look at the second half of the article here.
My module does not reset into BGAPI-DFU mode (it does not send the dfu_boot event and there is no way to proceed with re-programming) even though I am verifying with a logic analyzer that the system_reset(1) or the dfu_reset(1) command is correctly sent over UART. Note that during runtime I can send the system_hello command and I obtain the expected response from the module.
Please consider the Reset chapter in the datasheet from where we read that "On an internal reset, the RESET pin will be briefly pulled low internally. It is recommended that an external reset source is of an open drain type." In other words, you need to allow the module's reset line to be internally pulled low for the module to reboot successfully.