Gecko Bootloader can load application images into the application area from different sources.
It can load from host controller via UART/SPI.
It can load from a remote device OTA (over-the-air) via Bluetooth connection with the help of the Apploader.
It can load from internal flash (if the internal flash is big enough to accomodate both the application code and an upgrade image).
It can load from external flash.
What it cannot do is uploading the application image to a temporary storage slot of the internal/external flash before loading it from there into the application area. This article helps you implement the missing step: uploading the image to the internal/external flash via a Bluetooth connection.
To make the OTA uploader compatible with Silicon Labs Bluetooth OTA Apploader that loads the image directly to the application area, first we have to understand how the standard OTA DFU method works.
The standard OTA DFU sequence (implemented in the OTA Apploader) looks like this:
App is running.
Device is reset into DFU mode. In this mode the bootloader will start the Apploader instead of the Application. The Apploader is a simple application with a minimal Bluetooth stack, that handles the upload process. The Apploader uses the API of the Gecko Bootloader to decode the GBL files and to store the application image in the flash. (Note: before Bluetooth SDK v2.7 the Apploader was built into the stack binary and was referenced as supervisor code. To learn more about the legacy OTA update process please refer to AN1045: Bluetooth ® Over-the-Air Device Firmware Update for EFR32xG1 and BGM11x Series Products. Standalone Apploader is used only since Bluetooth SDK v2.7)
The Apploader advertises and waits for a Bluetooth connection
The Apploader waits for the OTA start command (using OTA control characteristic)
The Apploader starts receiving the GBL file (using OTA data characteristic)
The headers of the GBL file are stored in Slot 0 to be parsed
After parsing the headers, the rest of the GBL file is decoded on-the-fly, and the application is copied right to the application area, overwriting the old application
The Apploader receives the OTA end command and restarts the device in normal mode.
The OTA uploader uses a similar process:
App is running (device is not reset, since the uploader is implemented in the user application)
If there are multiple slots, the remote device chooses which slot to upload to, using a custom characteristic (e.g. slot0. Slot0 can be either in the internal or in the external flash. The application do not have to know this, flash is handled by the bootloader API)
The uploader waits for the OTA start command (using OTA control characteristic)
The uploader starts receiving the GBL file (using OTA data characteristic)
the GBL file is saved into slot0/slot1 as it is using the bootloader API (the application does not have to know where Slot0/Slot1 is located, bootloader API handles the writing)
The uploader receives the OTA end command
If there are multiple slots, the remote device may upload a new image to the other slot(s)
The remote device chooses which slot to bootload from using a custom characteristic
The device is reset in bootloader mode
The bootloader parses the given slot, retrieves the Application code from the GBLfile and copies the code to the application area from the internal/external flash
The bootloader starts the new Application
Implementation
The attached code implements image uploading to the slots using the standard OTA process. It is also extended with the possibility to select a slot to upload to, and to select a slot to boot from. You are free to modify this example according to your needs.
To create a project with multislot OTA DFU follow these steps:
Create an Internal Storage Bootloader (multiple images) or a SPI Flash Storage Bootloader (multiple images) project in Simplicity Studio
Check the Storage Slot configuration in AppBuilder and modify it according to your needs.
Generate and build the project
Create a SoC – Empty project
Remove the Silicon Labs OTA service from your GATT database if it is present
Add the Silicon Labs OTA service in Visual GATT Editor (BLE GATT Configurator)
On the left plane select Services
Find Silicon Labs OTA services
Drag and drop it to the right pane
Select the Silicon Labs OTA Data characteristic
Set its type to user (the content will not be stored to database but processed by the application)
Set its length to 244
Set Write and Write Without Response properties to true
Select the Silicon Labs OTA control characteristic
set its type the user
Set Write and Write Without Response properties to true
Add Slot Manager service in Visual GATT Editor (only needed if you want to manage multiple slots)
Add a new service, named e.g. Slot Manager Service
Add a new characteristic within this service called e.g. Upload Slot (this will be used to select a slot to upload data to)
Set its ID to upload_slot (needed for reference in the code)
Set its type to hex
Set its length to 1
Add Read and Write properties
Add a new characteristic within this service called e.g. Bootload Slot (this will be used to trigger bootload from the given slot)
Set its ID to boot_slot (needed for reference in the code)
Set its type to hex
Set its length to 1
Add Write property
Now your GATT database should look like this:
Click Generate to build the GATT database
Copy the attached ota_dfu_multislot.c and ota_dfu_multislot.h files into the project
Copy btl_interface.c and btl_interface_storage.c from C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\v1.1\platform\bootloader\api to your project
Go to Project Properties > C/C++ Build > Settings and add the following folders to the Includes:
"${StudioSdkPath}/platform/bootloader"
"${StudioSdkPath}/platform/bootloader/api"
or copy the .h files from these folders to your project
Remove apploader from the project as we won't need it anymore:
Go to Project Properties > C/C++ Build > Settings
Go to GNU ARM C Linker > Miscellaneous or IAR Linker for ARM > Library
Remove binapploader.o from the list
Add the followings to main.c
Add #include “ota_dfu_multislot.h” to the beginning of main.c
Add ota_dfu_handle_event(evt); after evt = gecko_wait_event();
Remove the code that triggers DFU reset upon writing into ota_control characteristic
(Note: setting gecko_bootloader=true in the .isc file will copy btl_interface.c and btl_interface_storage.c into your project again. Remove the instances you copied before to avoid duplicated definitions)
Flash the image to your device
Usage
Create full.gbl file from the application you want to upload. (Note: since the uploader is implemented in the user application, and not in the Apploader, you should implement the uploader in the application to be uploaded, as well!!) E.g.
Make a copy of your multislot OTA DFU project
Change the Device Name from “Empty Example” to “Updated app” in the Visual GATT Editor
Press Generate
Build the project
Run create_bl_files.bat
Find the .gbl files in output_gbl folder
Copy full.gbl to your smartphone (in case of Android copy it to SiliconLabs_BGApp/OTAFiles/myproject, in case of iOS upload it to iCloud)
Open Blue Gecko app on your smartphone
Find your device with Bluetooth browser (advertising as Empty Example) and connect to it
Find the unknown service and open it (this is your custom service including Upload slot and Bootload slot characteristics)
Open the first characteristic (this is the upload characteristic) and write the slot number in it, you want to upload to
In the local menu select OTA
Select the partial OTA tab
Select the folder and the full.gbl file you want to upload
Click OTA. The file will be uploaded to the selected slot.
Now open the second characteristic in the unknown service (Bootload slot) and write the slot number in it, you want to load the application from. The device will be reset and the application will be loaded.
Disconnect and find your device advertising itself as “Updated app”
The external signal mechanism in the BLE SDK, gives you the ability to handle external events, such as GPIO interrupts.
Discussion
Up to 32 separate signals can be sent from the user application to the Bluetooth stack through a call to the API function gecko_external_signal(). This API takes a 32 bit parameter which is interpreted as a set of 32 flags, one for each channel. The use for each channel can be set by the user. A call to this API causes the stack to send a system_external_signal event to the application. This event has a 32 bit value to indicate which signals have been sent since the last event. Sending the same signal multiple times will only result in multiple events once the signal has been cleared.
Example
The example attached to this article is written for an EFR32BG1P device but can be easily ported to other devices. This application uses the external signal mechanism to signal the Bluetooth stack when a button on the WSTK board is pressed. The first step is to set up the GPIO lines for interrupts. This is done at the system_boot event (gecko_evt_system_boot_id) by calling setup_external_interrupts(). This function sets up the GPIO lines as inputs, configures them to generate interrupts and registers a callback to process the interrupts. When a button is pressed, the callback function ButtonHandler() is called. This function receives a single parameter to indicate which interrupts are active, gecko_external_signal() is then called to indicate to the stack which button was pressed. The system_external_signal event handler (gecko_system_external_signal_id) processes these signals. When this event is handled all of the signals are cleared.
Conclusion
The external signal mechanism is a convenient way for the application to allow the Bluetooth stack to schedule handling of non-Bluetooth tasks required by the application such as interrupt servicing.
This article discusses the lazy soft timer and how you can use it to optimize your application's current consumption.
Why is it lazy?
Lazy is perhaps a misleading term. No need to “re-invent" the wheel, let’s see what the API Reference Guide has to say.
“This command can be used to start a software timer with some slack. Slack parameter allows stack to optimize wake ups and save power. Timer event is triggered between time and time + slack.”
What this means is that if the device wakes up for any other reason (e.g. radio wake-up, GPIO) between time and time+slack then the stack will also raise a soft timer event. If no other interrupt comes between time and time+slack then the soft timer event will wake-up the device at time+slack.
How does this approach save energy?
The reason why this saves energy is that there is fixed overhead for each wake-up. Looking at the EFR32BG1 datasheet we can see that wake-up from Deep Sleep (EM2) takes 10.7 us (table 4.9) and HFXO startup time is 300 us (table 4.32). This translates into energy that is being consumed without executing any code and on every single wake-up.
The idea behind the lazy soft timer is to pack more code execution into each wake-up period and reduce the overall need for additional wake-ups, thus reducing the overall energy consumption.
This is especially useful when used with radio wake-ups. During TX/RX the SoC is most of the time in EM1 (CPU not running) and waiting for the radio TX/RX operation to be finalized. While doing this the HFXO is running at 38.4 MHz and that alone cost 49 uA or 65 uA per MHz (a total of 1.88 mA or 2.49 mA) depending on whether the DC/DC is being used or not (tables 4.5, 4.6 and 4.7, EM1 current specs). When the stack raises a soft timer event right after a radio wake-up it allows a more efficient usage of the CPU which can execute application code instead of simply idling in EM1.
Setting up the project
This example is based on the Thermometer example with EFR32 internal temperature sensor but using a smaller sampling interval of 100 ms. We then connect from a master device with a connection interval of 100 ms (a second WSTK+BGTool or BLED112 as master gives control over the connection parameters) and subscribe to indications from the temperature measurement characteristic which starts the soft timer or lazy soft timer.
Start by creating an SoC - Empty sample app for your chosen hardware.
In the project menu select new | Silicon Labs appBuilder project.
Select Bluetooth SDK and click next
Select the latest Bluetooth SDK and click next
Select SOC – Empty and click next
Enter a name for the project and click next
Replace existing app.c with the app.c attached to this article
Copy em_adc.c and em_adc.h from the SDK to the project folder if they aren't already in the platform->emlib->inc/src folders.
Import the attached gatt.xml file in the GATT Configurator sidebar (.isc file, "Import GATT from .bgproj file"). This will add the Health Thermometer service and Temperature Measurement characteristic and change Device Name to "IntTemp".
Press Save and Generate
Build and flash
Using BGTool you can now read the temperature sampled from the internal temperature sensor and change the connection parameters as needed.
The difference compared to the original internal temperature sensor is just one API call on line 202 in app.c shown below:
Because the sensor readout doesn’t need to be extremely accurate, we’re giving it a slack which equals the timeout of 100 ms so that the stack should always be able to sync this up to a radio wake-up on one of the connection intervals.
Soft timer vs. Lazy soft timer
Using the "traditional" soft timer we can see 3 peaks in the current consumption.
The smallest peaks are the DC/DC refreshing. The tallest peak is the radio activity on a connection interval. The other 2 peaks are the soft timer wake-ups which trigger the ADC sensor readout. Let’s take a closer look at the sensor readout.
The sensor readout phase takes just under 1 ms with an average current consumption of 4.34 mA. For finalizing the metrics to compare against the lazy soft timer usage let’s see what the overall average current consumption looks like.
So on average we are using 155 uA, with 100 ms sampling rate of the ADC temperature sensor triggered by a soft timer and a connection to a master device with 100 ms connection interval.
When using the lazy soft timer the first thing that’s noticeable is that the sensor readout peaks are gone.
And the biggest different comes on the average current consumption where we go from the original 155 uA to 115 uA, which represents an improvement of 25%.
If this would be a battery powered application it would translate into 25% more battery life. The difference between the average energy consumption can also be observed using the Energy Profiler tool built in to Simplicity Studio as shown below.
What is happening now is that the ADC sensor readout is done at the same time as the RX/TX radio operations when the CPU would otherwise be idling on top of a running (and power hungry) HFXO. Looking at the connection intervals we can see a small increase in the current consumption between using the soft timer and the lazy soft timer (upper and lower figure respectively).
Conclusion
The lazy soft timer offers the opportunity to sync up timer wake ups with other system wake ups, which allows you to further optimize your system’s energy consumption when timer accuracy is not a requirement.
Bluetooth Knowledge Base
KBA_BT_0802: Uploading images to internal/external flash using OTA DFU
Gecko Bootloader can load application images into the application area from different sources.
What it cannot do is uploading the application image to a temporary storage slot of the internal/external flash before loading it from there into the application area. This article helps you implement the missing step: uploading the image to the internal/external flash via a Bluetooth connection.
This article guides you through how to upload images to storage slots using the standard OTA DFU process (used by the OTA Apploader). To learn how to load the uploaded images from the slots into the application area please read this article: https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2017/07/19/switching_betweenfi-GnNI
To make the OTA uploader compatible with Silicon Labs Bluetooth OTA Apploader that loads the image directly to the application area, first we have to understand how the standard OTA DFU method works.
The standard OTA DFU sequence (implemented in the OTA Apploader) looks like this:
The OTA uploader uses a similar process:
Implementation
The attached code implements image uploading to the slots using the standard OTA process. It is also extended with the possibility to select a slot to upload to, and to select a slot to boot from. You are free to modify this example according to your needs.
To create a project with multislot OTA DFU follow these steps:
"${StudioSdkPath}/platform/bootloader"
"${StudioSdkPath}/platform/bootloader/api"
or copy the .h files from these folders to your project
http://community.silabs.com/t5/Bluetooth-Wi-Fi-Knowledge-Base/Adding-Gecko-Bootloader-to-Bluetooth-projects/ta-p/195432
(Note: setting gecko_bootloader=true in the .isc file will copy btl_interface.c and btl_interface_storage.c into your project again. Remove the instances you copied before to avoid duplicated definitions)
Usage
KBA_BT_0305: Handling GPIO Interrupts using External Signals
Introduction
The external signal mechanism in the BLE SDK, gives you the ability to handle external events, such as GPIO interrupts.
Discussion
Up to 32 separate signals can be sent from the user application to the Bluetooth stack through a call to the API function gecko_external_signal(). This API takes a 32 bit parameter which is interpreted as a set of 32 flags, one for each channel. The use for each channel can be set by the user. A call to this API causes the stack to send a system_external_signal event to the application. This event has a 32 bit value to indicate which signals have been sent since the last event. Sending the same signal multiple times will only result in multiple events once the signal has been cleared.
Example
The example attached to this article is written for an EFR32BG1P device but can be easily ported to other devices. This application uses the external signal mechanism to signal the Bluetooth stack when a button on the WSTK board is pressed. The first step is to set up the GPIO lines for interrupts. This is done at the system_boot event (gecko_evt_system_boot_id) by calling setup_external_interrupts(). This function sets up the GPIO lines as inputs, configures them to generate interrupts and registers a callback to process the interrupts. When a button is pressed, the callback function ButtonHandler() is called. This function receives a single parameter to indicate which interrupts are active, gecko_external_signal() is then called to indicate to the stack which button was pressed. The system_external_signal event handler (gecko_system_external_signal_id) processes these signals. When this event is handled all of the signals are cleared.
Conclusion
The external signal mechanism is a convenient way for the application to allow the Bluetooth stack to schedule handling of non-Bluetooth tasks required by the application such as interrupt servicing.
[Deprecated] KBA_BT_0306: Using the lazy soft timer
Note: This KBA has been marked as deprecated. A more updated KBA can be found here:
Using the Lazy Soft Timer
Introduction
This article discusses the lazy soft timer and how you can use it to optimize your application's current consumption.
Why is it lazy?
Lazy is perhaps a misleading term. No need to “re-invent" the wheel, let’s see what the API Reference Guide has to say.
What this means is that if the device wakes up for any other reason (e.g. radio wake-up, GPIO) between time and time+slack then the stack will also raise a soft timer event. If no other interrupt comes between time and time+slack then the soft timer event will wake-up the device at time+slack.
How does this approach save energy?
The reason why this saves energy is that there is fixed overhead for each wake-up. Looking at the EFR32BG1 datasheet we can see that wake-up from Deep Sleep (EM2) takes 10.7 us (table 4.9) and HFXO startup time is 300 us (table 4.32). This translates into energy that is being consumed without executing any code and on every single wake-up.
The idea behind the lazy soft timer is to pack more code execution into each wake-up period and reduce the overall need for additional wake-ups, thus reducing the overall energy consumption.
This is especially useful when used with radio wake-ups. During TX/RX the SoC is most of the time in EM1 (CPU not running) and waiting for the radio TX/RX operation to be finalized. While doing this the HFXO is running at 38.4 MHz and that alone cost 49 uA or 65 uA per MHz (a total of 1.88 mA or 2.49 mA) depending on whether the DC/DC is being used or not (tables 4.5, 4.6 and 4.7, EM1 current specs). When the stack raises a soft timer event right after a radio wake-up it allows a more efficient usage of the CPU which can execute application code instead of simply idling in EM1.
Setting up the project
This example is based on the Thermometer example with EFR32 internal temperature sensor but using a smaller sampling interval of 100 ms. We then connect from a master device with a connection interval of 100 ms (a second WSTK+BGTool or BLED112 as master gives control over the connection parameters) and subscribe to indications from the temperature measurement characteristic which starts the soft timer or lazy soft timer.
Start by creating an SoC - Empty sample app for your chosen hardware.
Using BGTool you can now read the temperature sampled from the internal temperature sensor and change the connection parameters as needed.
The difference compared to the original internal temperature sensor is just one API call on line 202 in app.c shown below:
Because the sensor readout doesn’t need to be extremely accurate, we’re giving it a slack which equals the timeout of 100 ms so that the stack should always be able to sync this up to a radio wake-up on one of the connection intervals.
Soft timer vs. Lazy soft timer
Using the "traditional" soft timer we can see 3 peaks in the current consumption.
The smallest peaks are the DC/DC refreshing. The tallest peak is the radio activity on a connection interval. The other 2 peaks are the soft timer wake-ups which trigger the ADC sensor readout. Let’s take a closer look at the sensor readout.
The sensor readout phase takes just under 1 ms with an average current consumption of 4.34 mA. For finalizing the metrics to compare against the lazy soft timer usage let’s see what the overall average current consumption looks like.
So on average we are using 155 uA, with 100 ms sampling rate of the ADC temperature sensor triggered by a soft timer and a connection to a master device with 100 ms connection interval.
When using the lazy soft timer the first thing that’s noticeable is that the sensor readout peaks are gone.
And the biggest different comes on the average current consumption where we go from the original 155 uA to 115 uA, which represents an improvement of 25%.
If this would be a battery powered application it would translate into 25% more battery life. The difference between the average energy consumption can also be observed using the Energy Profiler tool built in to Simplicity Studio as shown below.
What is happening now is that the ADC sensor readout is done at the same time as the RX/TX radio operations when the CPU would otherwise be idling on top of a running (and power hungry) HFXO. Looking at the connection intervals we can see a small increase in the current consumption between using the soft timer and the lazy soft timer (upper and lower figure respectively).
Conclusion
The lazy soft timer offers the opportunity to sync up timer wake ups with other system wake ups, which allows you to further optimize your system’s energy consumption when timer accuracy is not a requirement.