nRF5 SDK for Thread v0.10.0
Adding dynamic multiprotocol Thread support to BLE examples

Applications demonstrating the Bluetooth peripheral functionality may be extended by adding Thread protocol support to them. In this way, dynamic multiprotocol functionality can be achieved.

For reference, see <InstallFolder>\examples\multiprotocol\experimental\ble_thread_dynamic_mtd_coap_client, which is a modified version of the ble_app_uart example.

Modification in sdk_config.h

Add the following settings to sdk_config.h in order to configure the Thread stack:

// <h> openthread
//==========================================================
// <h> openthread - OpenThread stack
//==========================================================
// <o> THREAD_PANID - 802.15.4 PAN ID used by Thread <0-65535>
// <i> 802.15.4 PAN ID used by Thread. Defaults to 0xABCD.
#ifndef THREAD_PANID
#define THREAD_PANID 43981
#endif
// <o> THREAD_CHANNEL - 802.15.4 channel used by Thread <11-26>
// <i> 802.15.4 channel used by Thread. Defaults to 11.
#ifndef THREAD_CHANNEL
#define THREAD_CHANNEL 11
#endif
// </h>
//==========================================================
// </h>
//==========================================================

Modify these settings if they appear in sdk_config.h:

#define APP_UART_DRIVER_INSTANCE 1
#define UART0_ENABLED 0
#define UART1_ENABLED 1

Libraries

nRF5 SDK for Thread provides precompiled OpenThread libraries which must be added to the project.

The default set of libraries for an FTD Thread device which uses CLI is:

Note that you may need to use another set of libraries, depending on the Thread use case that you aim for. See OpenThread libraries.

Modification in GCC Makefile

Add the below snippet to the Makefile of a BLE application:

# Libraries common to all targets
LIB_FILES += \
$(SDK_ROOT)/external/openthread/lib/gcc/libopenthread-cli-ftd.a \
$(SDK_ROOT)/external/openthread/lib/gcc/libopenthread-ftd.a \
$(SDK_ROOT)/external/openthread/lib/gcc/libopenthread-nrf52840-softdevice-sdk.a \
$(SDK_ROOT)/external/openthread/lib/gcc/libopenthread-diag.a \
$(SDK_ROOT)/external/openthread/lib/gcc/libmbedcrypto.a \
$(SDK_ROOT)/external/nrf_cc310/lib/libcc310_gcc_0.9.0.a \

In order to use the Thread API, you need to add headers include paths. To do that, add the following line inside of the INC_FOLDERS section:

$(SDK_ROOT)/external/openthread/include \

For reference, see this Makefile that is already ported: <InstallFolder>\examples\multiprotocol\experimental\ble_thread_dynamic_mtd_coap_client\pca10056\s140\armgcc\Makefile

Modification in IAR project

In order to add libraries under the IAR compiler, click Project -> Add Files. Then, choose the file type of Library/Object Files and navigate to \external\openthread\lib\iar.

Select all needed libraries according to the above section.

In order to use the Thread API, you need to add headers include paths. To do that, click Project -> Options and choose the C/C++ Compiler section. In the Preprocessor tab, navigate to the Additional include directory section. Add the path to the \external\openthread\include folder.

After the folder path is added, depending on your project location, the following record should be visible.

$PROJ_DIR$\..\..\..\..\..\..\external\openthread\include

For reference, see the IAR project that is already ported: <InstallFolder>\examples\multiprotocol\experimental\ble_thread_dynamic_mtd_coap_client\ble_thread_dynamic_mtd_coap_client.eww

Modification in the linker script

Thread requires a special block in the flash memory to store protocol-specific data, such as Active and Pending Dataset or Parent/Child information. This data is necessary for synchronization after reset. In addition, to ensure that the radio buffer is accessible for EasyDMA, it is recommended to allocate it at the beginning of the RAM.

Modification in GCC linker script

It is recommended to use the example linker script that is already ported: <InstallFolder>\external\openthread\linker_scripts\openthread_nrf52840_multiprotocol.ld

Note that it may be possible to adjust the RAM start of the application, which depends on the SoftDevice configuration. To ensure that the RAM start is set correctly, set the ORIGIN and LENGTH variables of the RAM section to what is set in the original example.

For example:

RAM (rwx) : ORIGIN = 0x20002088, LENGTH = 0x3df78

Modification in IAR linker script

It is recommended to use the example linker script that is already ported: <InstallFolder>\external\openthread\linker_scripts\openthread_nrf52840_multiprotocol.icf

Note that it may be possible to adjust the RAM start of the application, which depends on the SoftDevice configuration. To ensure that the RAM start is set correctly, set the __ICFEDIT_region_RAM_start__ and __ICFEDIT_region_RAM_end__ variables to what is set in the original example.

E.g.

define symbol __ICFEDIT_region_RAM_start__ = 0x20002088;
define symbol __ICFEDIT_region_RAM_end__ = 0x2003ffff;

Modification in main.c

1) At the top of the main.c file, add all necessary includes, depending on the Thread use case.

#include <assert.h>
#include <openthread/openthread.h>
#include <openthread/diag.h>
#include <openthread/coap.h>
#include <openthread/cli.h>
#include <openthread/platform/platform.h>
#include <openthread/platform/platform-softdevice.h>

2) After the section which contains defines and static variables, add the following line:

static otInstance *mp_ot_instance;

3) Ensure that application registers the SoftDevice’s SoC event handler (using the softdevice_sys_evt_handler_set function). If the handler is not already registered, add the following snippet inside of the BLE stack initialization function (after softdevice_ble_evt_handler_set).

// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
APP_ERROR_CHECK(err_code);

4) Inside of the sys_evt_dispatch function, add OpenThread’s SoftDevice platform handler called PlatformSoftdeviceSocEvtHandler.

/**@brief Function for dispatching a system event to interested modules.
@details This function is called from the System event interrupt handler after a system
event has been received.
@param[in] sys_evt System stack event.
*/
static void sys_evt_dispatch(uint32_t sys_evt)
{
// Dispatch the system event to the OpenThread platform.
PlatformSoftdeviceSocEvtHandler(sys_evt);
}

5) Add the function for initializing the Thread protocol. Note that it depends on your Thread use case.

/***************************************************************************************************
@section Initialization of Thread.
**************************************************************************************************/
/**@brief Function for initializing Thread protocol.
*/
static void thread_init(void)
{
otInstance *p_instance;
PlatformInit(0, NULL);
p_instance = otInstanceInit();
assert(p_instance);
otCliUartInit(p_instance);
NRF_LOG_INFO("Thread version: %s\r\n", (uint32_t)otGetVersionString());
NRF_LOG_INFO("Network name: %s\r\n", (uint32_t)otThreadGetNetworkName(p_instance));
assert(otSetStateChangedCallback(p_instance, &state_changed_callback, p_instance) == OT_ERROR_NONE);
if (!otDatasetIsCommissioned(p_instance))
{
assert(otLinkSetChannel(p_instance, THREAD_CHANNEL) == OT_ERROR_NONE);
assert(otLinkSetPanId(p_instance, THREAD_PANID) == OT_ERROR_NONE);
}
assert(otIp6SetEnabled(p_instance, true) == OT_ERROR_NONE);
assert(otThreadSetEnabled(p_instance, true) == OT_ERROR_NONE);
mp_ot_instance = p_instance;
}

For reference on how to add the CoAP functionality (for example), or use the low power mode, see: <InstallFolder>\examples\multiprotocol\experimental\ble_thread_dynamic_mtd_coap_client\main.c

6) Call the thread_init function inside of the application main function.

Important! This function must be called after the SoftDevice has been initialized.

7) Add the following snippet inside the main loop of your application:

// Enter main loop.
for (;;)
{
otTaskletsProcess(m_app.p_ot_instance);
PlatformProcessDrivers(m_app.p_ot_instance);
}

In case the application enters the power_manage function, which calls the sd_app_evt_wait SoftDevice API function, modify the above snippet to:

// Enter main loop.
for (;;)
{
otTaskletsProcess(m_app.p_ot_instance);
PlatformProcessDrivers(m_app.p_ot_instance);
if (!otTaskletsArePending(m_app.p_ot_instance))
{
power_manage();
}
}

Parameters of Timeslot API

Timeslot API has been tested with a set of default parameters on the nRF52840 Development Kit. These parameters are preset when the PlatformInit function is invoked.

However, in case your application needs to use a different set of parameters for the Timeslot API, the library exposes the PlatformSoftdeviceRaalConfig function to change the default Timeslot API parameters.

One of the parameters is the crystal accuracy in PPM units, which by default is set to 25 PPM. The application may use the PlatformSoftdeviceRaalConfig function to change the PPM value of the currently used crystal.

Instructions on how to select other parameters for specific applications will be available in the subsequent releases of nRF5 SDK for Thread.

Restrictions

Note that OpenThread's hardware requirements must be met in transformed examples. Refer to the Hardware requirements page.


Documentation feedback | Developer Zone | Subscribe | Updated