Thursday 6 June 2019

FreeRTOS support for Silicon Labs EFR32BG/MG Bluetooth Stack

tl;dr Click here to go to GitHub.

This post provides usage information on AndrewLabs' FreeRTOS support library for the Silicon Labs' Bluetooth SDK.

The Silicon Labs' Bluetooth SDK for the Blue Gecko and Mighty Gecko wireless SoCs officially supports Micrium RTOS. The costs involved with using Micrium RTOS may be prohibitive with small commercial projects. Here at AndrewLabs we are more familiar with FreeRTOS, having used the kernel in many of our projects.

Using FreeRTOS is possible by porting over the Micrium RTOS code provided in the SDK.

We have made our source code for using FreeRTOS with the SiLabs Bluetooth SDK available on GitHub. Version 2.11.5 of the Bluetooth SDK used for this article. The compiler used was GNU ARM Embedded Toolchain 7-2017-Q4 installed in Simplicity Studio SV4.1.10.0.

While porting over to FreeRTOS, an attempt was made to follow the documents "UG136: Silicon Labs Bluetooth C Application Developer's Guide" and "AN1114: Integrating Silicon Labs Bluetooth Applications with the Micrium RTOS" as closely as possible. This includes maintaining the names of global variables and functions.

The following describe the steps required to use the Bluetooth Stack in FreeRTOS starting from the Silicon Labs soc-empty template project:
  1. Ensure you have FreeRTOS and the Bluetooth SDK properly functioning on your device.
  2. Remove references to native_gecko.h from your project.
  3. Include freertos_bluetooth.c and freertos_bluetooth.h in your project.
  4. Make sure the Bluetooth stack config_flags configuration has the GECKO_CONFIG_FLAG_RTOS flag set:
    static gecko_configuration_t config = {
        .config_flags = GECKO_CONFIG_FLAG_RTOS,
        // ...
  5. Configure interrupts in your MCU initialization function, since specifying the GECKO_CONFIG_FLAG_RTOS flag turns off interrupt configuration in the Bluetooth stack:
    // Radio interrupts.
    NVIC_SetPriority(FRC_PRI_IRQn, 1);
    NVIC_SetPriority(FRC_IRQn, 1);
    NVIC_SetPriority(MODEM_IRQn, 1);
    NVIC_SetPriority(RAC_SEQ_IRQn, 1);
    NVIC_SetPriority(RAC_RSM_IRQn, 1);
    NVIC_SetPriority(BUFC_IRQn, 1);
    NVIC_SetPriority(AGC_IRQn, 1);
    NVIC_SetPriority(PROTIMER_IRQn, 1);
    NVIC_SetPriority(RTCC_IRQn, 4);      // Required for EFR32BG1 and EFR32BG12 only.
    Other interrupts should be configured as required.
  6. Start the Bluetooth link-layer and stack tasks in your main function or equivalent:
    app_bluetooth_start_task();     // Your application's Bluetooth task.
    vTaskStartScheduler();          // Start the FreeRTOS scheduler.
    BLUETOOTH_LL_PRIORITY must be the highest priority task in your system and BLUETOOTH_STACK_PRIORITY should be set according to your application needs.
  7. In your application's Bluetooth task, wait for the BLUETOOTH_EVENT_FLAG_EVT_WAITING flag in the bluetooth_event_flags event group, indicating an event from the stack is waiting to be handled by the user application:
    for (;;)
        xEventGroupWaitBits(bluetooth_event_flags, BLUETOOTH_EVENT_FLAG_EVT_WAITING, pdTRUE, pdTRUE, portMAX_DELAY);
        // ...
  8. Handle the event appropriately by examining bluetooth_evt:
        switch (BGLIB_MSG_ID(bluetooth_evt->header))
            case gecko_evt_system_boot_id:
    // ...
  9. After handling the event, flag it as handled by setting BLUETOOTH_EVENT_FLAG_EVT_HANDLED in the bluetooth_event_flags event group:
        // ....
        xEventGroupSetBits(bluetooth_event_flags, BLUETOOTH_EVENT_FLAG_EVT_HANDLED);
The Bluetooth stack sets a block on the EM3 energy mode if SLEEP_FLAGS_DEEP_SLEEP_ENABLE is specified in the configuration struct, allowing the SoC to enter the EM2 energy mode. Otherwise, it sets a block on the EM2 energy mode, only allowing EM1 to be entered. The sleep driver must be manually initialized when using an RTOS.

Note that as the HFXO clock is not available in EM2, the SysTick timer will not operate. FreeRTOS will need to be configured for tickless idle mode.