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:
    bluetooth_start_task(BLUETOOTH_LL_PRIORITY, BLUETOOTH_STACK_PRIORITY);
    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:
        // ....
            default:
                break;
        }
    
        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.

3 comments:

  1. Excellent post! I've done a very similar thing for the project at the company I work for. But I've been struggling with a particular and annoying bug in which the stack no longer receives the connection_closed event, only solvable by performing a reset. The project is coded in C++. Have you ever encountered such a bug? And How did you configure the project in IDE?

    ReplyDelete
    Replies
    1. Thanks for visiting!

      I can't say I've encountered the same bug. My project is based on the soc-empty template generated by Simplicity Studio. The operation of the Bluetooth stack has been very stable in my experience, and all issues so far have been related to my custom application code.

      Many of these issues result in disconnection of the Bluetooth link quickly (such as not acknowledging a write with response, or sending an acknowledgement when not requested to), so in my opinion your issue appears to be related to your application tasks. It is rather hard to assist without seeing code.

      Delete
    2. Interesting. My issue follows the same pattern you explained. Due to power consumption requirements and low data throughput, the device is programmed to send data by connecting, sending and disconnecting after. The issue is completely dynamic and can take days to occur. Once it does, no more connection, or even advertising, is possible. The characteristic we use is set in confirmation mode, so every data sent is accompanied by a acknowledge. I've never had problems with that, only on disconnection. I'll see if I can share some snippet of the code with you. This bug is really getting on my nerves.

      Delete