XDK API  3.6.0
Documentation
XDK Software Startup Guide

Explains XDK Startup Procedure and how you can customize it


This simple guide is intended, for the developers who are going to develop applications for XDK, to know the basic startup procedure of the system before they start writing their application.

XDK software can be configured to start in two ways as described below. The configuration can be done using BCDS_SYSTEM_STARTUP_METHOD macro present in the application Makefile. Refer the code block below representing the change. Also Note that by default XDK is shipped with DEFAULT_STARTUP enabled.

export BCDS_SYSTEM_STARTUP_METHOD=CUSTOM_STARTUP

Default Startup:

The Main() function implemented in SystemStartUp module will be the first C function executed during power ON and it does the following,

  1. EFM32 chip is configured to a proper state with the help of library function exported by emlib.
  2. All the interrupt sources are configured to maximum priority to ensure, ISR runs at highest priority.
  3. System peripherals like GPIO,I2C and USB are initialized to a proper state.
  4. GPIO pins related to the device are configured to its default value.
  5. User page module is initialized, which is used to save configuration information like Wifi MAC address, Bluetooth MAC address, etc., in the user page area of flash.
  6. Create a default application specific initialization timer and start it.
  7. Give control to operating system by starting task scheduler of FreeRTOS.

Custom Startup:

Custom startup procedure will exclude step 3 to 5 described above in default startup procedure, to give flexibility to users, in order to have their own way of initializing system peripherals. The user can choose to initialize and configure the peripherals which he wants to use in his application. If, Custom startup procedure is configured, the user has to ensure the GPIO pins that they are using are initialized to a proper default state. In both of the above configurations XDK's SystemStartUp module will schedule a default application specific initialization timer "appInitSystem", which will run in the timer task context with task priority 2.

Note
While creating the OS task inside place holder "appInitSystem" the priority of OS tasks created shall be preferably less than or equal to 2. Because assigning priority greater than 2 may block all the timer task having lesser priority in this case. So, all the user applications are expected to have the implementation of the task "appInitSystem" and this will be the place holder for application specific initialization function. Application specific initialization function can further create either "timers" or "OS tasks" as suitable for its purpose (refer FreeRTOS.h for API reference).

Task creation and its priority:

Users can find configuration related to FreeRTOS in a file called, FreeRTOSConfig.h and it is present in path "xdk110\Common\config\AmazonFreeRTOS". This contains information like maximum task priority, stack size, heap size, software timer configurations, CPU clock and interrupt priority configurations. As explained, the user can create "Timer" or "OS Task" for its application use. Since, the creation of OS task requires the user to specify the task priority and stack size, we expect the user, to understand the task priorities of FreeRTOS, if, they prefer to create and use OS task for their application (see FreeRTOS documentation). The maximum priority of a task in XDK software is presently configured to 5, which is controlled by the macro configMAX_PRIORITIES. Considering the fact that the interrupt routines should run in the highest task priority, XDK assigns maximum priority to its interrupt sources. So, any task running in XDK should have the priority less than the configMAX_PRIORITIES that is 5. For a user who does not want to get into the complexities of handling independent OS tasks, we suggest to use timers to realize their use cases.

Hardware Interrupt Priority:

All hardware interrupts are configured to SYSCALL_INTERRUPT_PRIORITY_MAX.If user want to change the priority of any peripheral interrupts then it can be changed from 0 to SYSCALL_INTERRUPT_PRIORITY_MAX.Priority 0 means highest priority and SYSCALL_INTERRUPT_PRIORITY_MAX means least priority, within this priority range the ISR routine can call freeRTOS ISR safe API's(like xSemaphoreGiveFromISR)

Note: If the priority is set greater than SYSCALL_INTERRUPT_PRIORITY_MAX then freeRTOS ISR safe API's(like xSemaphoreGiveFromISR) must not be called in that particular peripheral ISR,violating this may have undesired behavior

Startup code for v3.4.0 and above

----------------------------------------------------Main.c--------------------------------------
/* own header files */
#include "XdkAppInfo.h"
#undef BCDS_MODULE_ID /* Module ID define before including Basics package*/
#define BCDS_MODULE_ID XDK_APP_MODULE_ID_MAIN
/* system header files */
#include <stdio.h>
#include "BCDS_Basics.h"
/* additional interface header files */
#include "BCDS_Assert.h"
#include "AppController.h"
#include "FreeRTOS.h"
#include "task.h"
/* own header files */
/* global variables ********************************************************* */
/* functions */
int main(void)
{
/* Mapping Default Error Handling function */
if (RETCODE_OK == retcode)
{
retcode = systemStartup();
}
if (RETCODE_OK == retcode)
{
}
if (RETCODE_OK == retcode)
{
/* Here we enqueue the application initialization into the command
* processor, such that the initialization function will be invoked
* once the RTOS scheduler is started below.
*/
retcode = CmdProcessor_Enqueue(&MainCmdProcessor, AppController_Init, &MainCmdProcessor, UINT32_C(0));
}
if (RETCODE_OK == retcode)
{
/* start scheduler */
/* Code must not reach here since the OS must take control. If not, we will assert. */
}
else
{
printf("main : XDK System Startup failed.\r\n");
}
assert(false);
}
----------------------------------------------------End of application------------------------------------

As per the Application Common Control Flow Changes by using CommandProcessor in XDK-3.4.0 & above:

Example : The following is the sample application to write a application using xdk modules.

  1. Application should follow the below three steps :
    • Setup - Here necessary modules required for the application like WLAN, BLE ,Sensors etc from the common are defined
    • Enable - Here necessary modules required for the application are enabled
    • Fire - After the setup and enable is done , fire is responsible for controlling application control flow. Any application logic which is blocking in nature or fixed time dependent can be placed in this API.
  2. Command processor should be used for all event based operation
  3. Tasks should be used for polling based operation
  4. Try to avoid Software timer usage
  5. All reusable components/modules should be placed in common repo. Application Features should be independent from BCDS shared package/3rd party library.
  6. Common repository :
    • Feature control should be based on run time configurable Ex. security enable/disable
    • Feature enable/disable should be controlled from config macro. Ex. #define XDK_BLE_FEATURE 1
    • Features should be RTOS and ServalStack independent
    • Each module/components should support Setup, Enable APIs.
      • These Setup, Enable apis should be a blocking call and must be command processor independent
      • Optionally modules should support Disable, Close apis.
      • All used resources properly initialized and de-initialized incluing static variables.
    • Variable naming for function return value
      • retcode - Retcode_T
      • rc - retcode_t
      • result - any other result value
      • status - any other status value
    ----------------------------------------------------Application.c--------------------------------------
    /* own header files */
    #include "XdkAppInfo.h"
    #undef BCDS_MODULE_ID /* Module ID define before including Basics package*/
    #define BCDS_MODULE_ID XDK_APP_MODULE_ID_APP_CONTROLLER
    /* own header files */
    #include "AppController.h"
    /* system header files */
    #include <stdio.h>
    /* additional interface header files */
    #include "FreeRTOS.h"
    #include "task.h"
    /* constant definitions ***************************************************** */
    /* local variables ********************************************************** */
    /* global variables ********************************************************* */
    /* inline functions ********************************************************* */
    /* local functions ********************************************************** */
    static void AppControllerFire(void* pvParameters)
    {
    BCDS_UNUSED(pvParameters);
    /* A function that implements a task must not exit or attempt to return to
    its caller function as there is nothing to return to. */
    while (1)
    {
    /* code to implement application control flow */
    ;
    }
    }
    static void AppControllerEnable(void * param1, uint32_t param2)
    {
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);
    Retcode_T retcode = RETCODE_OK;
    /* @todo - Enable necessary modules for the application and check their return values */
    if (RETCODE_OK == retcode)
    {
    if (pdPASS != xTaskCreate(AppControllerFire, (const char * const ) "AppController", TASK_STACK_SIZE_APP_CONTROLLER, NULL, TASK_PRIO_APP_CONTROLLER, &AppControllerHandle))
    {
    }
    }
    if (RETCODE_OK != retcode)
    {
    printf("AppControllerEnable : Failed \r\n");
    }
    }
    static void AppControllerSetup(void * param1, uint32_t param2)
    {
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);
    Retcode_T retcode = RETCODE_OK;
    /* @todo - Setup the necessary modules required for the application */
    retcode = CmdProcessor_Enqueue(AppCmdProcessor, AppControllerEnable, NULL, UINT32_C(0));
    if (RETCODE_OK != retcode)
    {
    printf("AppControllerSetup : Failed \r\n");
    }
    }
    /* global functions ********************************************************* */
    void AppController_Init(void * cmdProcessorHandle, uint32_t param2)
    {
    BCDS_UNUSED(param2);
    Retcode_T retcode = RETCODE_OK;
    if (cmdProcessorHandle == NULL)
    {
    printf("AppController_Run : Command processor handle is NULL \r\n");
    }
    else
    {
    AppCmdProcessor = (CmdProcessor_T *) cmdProcessorHandle;
    retcode = CmdProcessor_Enqueue(AppCmdProcessor, AppControllerSetup, NULL, UINT32_C(0));
    }
    if (RETCODE_OK != retcode)
    {
    }
    }
    ----------------------------------------------------End of application------------------------------------

Procedure to realize 'hello world' program on XDK for version below XDK-3.0.0:

Realizing "Hello World" program in XDK is straight forward and pretty simple. All, the user has to do is, as explained, implement default application specific initialization task and print 'hello world' as below,

----------------------------------------------------Main.c--------------------------------------
#include <stdio.h>
/* system header files */
#include <BCDS_Basics.h>
#include "BCDS_Assert.h"
#include "FreeRTOS.h"
#include "task.h"
#include "BEA_bleEchoData_cc.h"
/* additional interface header files */
/* global variables ********************************************************* */
int main(void)
{
/* Mapping Default Error Handling function */
Retcode_T returnValue = Retcode_initialize(DefaultErrorHandlingFunc);
if (RETCODE_OK == returnValue)
{
returnValue = systemStartup();
}
if (RETCODE_OK == returnValue)
{
returnValue = CmdProcessor_initialize(&MainCmdProcessor, (char *) "MainCmdProcessor", TASK_PRIO_MAIN_CMD_PROCESSOR, TASK_STACK_SIZE_MAIN_CMD_PROCESSOR, TASK_Q_LEN_MAIN_CMD_PROCESSOR);
}
if (RETCODE_OK == returnValue)
{
/* Here we enqueue the application initialization into the command
* processor, such that the initialization function will be invoked
* once the RTOS scheduler is started below.
*/
returnValue = CmdProcessor_enqueue(&MainCmdProcessor, appInitSystem, &MainCmdProcessor, UINT32_C(0));
}
if (RETCODE_OK != returnValue)
{
printf("System Startup failed");
assert(false);
}
/* start scheduler */
}
----------------------------------------------------application.c--------------------------------------
/* system header files */
#include <stdio.h>
#include <BCDS_Basics.h>
/* additional interface header files */
#include "FreeRTOS.h"
xTaskHandle Application_gdt;
/*
* @brief Application to print "hello world" on serial console.
*/
void Application_init(void * pvParameters)
{
(void) pvParameters;
for (;;)
{
printf("Hello world\r\n");
}
}
/*
* @brief This is a template function where the user can write his/her custom application.
*/
void appInitSystem(void * CmdProcessorHandle, uint32_t param2)
{
BCDS_UNUSED(CmdProcessorHandle);
BCDS_UNUSED(param2);
/*Call the Application Init API*/
xTaskCreate(Application_init, (const char * const) "Application_init",
256,NULL,1,&Application_gdt);
}
----------------------------------End of application----------------------------------------------------

Message "Hello World" will be printed on the console after flashing the above implementation.

A more efficient way of doing this however would be to use a timer:

----------------------------------------------------application.c--------------------------------------
/* system header files */
#include <stdio.h>
#include <BCDS_Basics.h>
/* additional interface header files */
#include "FreeRTOS.h"
#define THREESECONDDELAY UINT32_C(1000) /* one second is represented by this macro */
#define TIMERBLOCKTIME UINT32_C(0xffff) /* Macro used to define blocktime of a timer */
#define TIMER_AUTORELOAD_ON UINT32_C(1)
/*
* @brief Print string "Hello World" on the console
* @param[in] pxTimer timer handle
*/
void printHelloWorld(xTimerHandle pxTimer)
{
BCDS_UNUSED(pxTimer);
printf("Hello world\r\n");
}
/*
* @brief Application to print "hello world" on serial console.
*/
void Application_init(void)
{
xTimerHandle timerHandle_gdt;
/* create timer task to read and print lightsensor data every three seconds*/
/* Validated for portMAX_DELAY to assist the task to wait Infinitely (without timing out) and ticks cannot be 0 in FreeRTOS timer. So ticks is assigned to 1*/
timerHandle_gdt = xTimerCreate(
(char * const) "Test Application to print Hello World", (THREESECONDDELAY/portTICK_RATE_MS),
TIMER_AUTORELOAD_ON, NULL, printHelloWorld);
/*start the timer*/
xTimerStart(timerHandle_gdt, TIMERBLOCKTIME);
}
/*
* @brief This is a template function where the user can write his/her custom application.
*/
void appInitSystem(void * CmdProcessorHandle, uint32_t param2)
{
BCDS_UNUSED(CmdProcessorHandle);
BCDS_UNUSED(param2);
Application_init();
}
----------------------------------------------------End of application------------------------------------

As per the Application Common Control Flow Changes by using CommandProcessor in XDK-3.0.0 to XDK-3.3.1:

Example : Message "Hello World" will be printed on the console after flashing the above implementation.

A more efficient way of doing this however would be to use a timer and CommandProcessor:

----------------------------------------------------application.c--------------------------------------
/* system header files */
#include <stdio.h>
#include <BCDS_Basics.h>
/* additional interface header files */
#include "FreeRTOS.h"
#define THREESECONDDELAY UINT32_C(1000) /* one second is represented by this macro */
#define TIMERBLOCKTIME UINT32_C(0xffff) /* Macro used to define blocktime of a timer */
#define TIMER_AUTORELOAD_ON UINT32_C(1)
/*Application Command Processor Instance */
static void printHelloWorld(void * param1, uint32_t param2)
{
BCDS_UNUSED(param1);
BCDS_UNUSED(param2);
printf("Hello world\r\n");
}
/*
* @brief Print string "Hello World" on the console
* @param[in] pxTimer timer handle
*/
void processUsbPrintMsg(xTimerHandle pxTimer)
{
BCDS_UNUSED(pxTimer); /* suppressing warning message */
Retcode_T returnValue = RETCODE_OK;
returnValue = CmdProcessor_enqueue(AppCmdProcessor, printHelloWorld, NULL, UINT32_C(0));
if (RETCODE_OK != returnValue)
{
printf("Enqueuing for PrintHelloWorld callback failed\n\r");
}
}
/*
* @brief Application to print "hello world" on serial console.
*/
void Application_init(void)
{
xTimerHandle timerHandle_gdt;
* Return value for Timer start */
int8_t retValPerSwTimer = TIMER_NOT_ENOUGH_MEMORY;
/* create timer task to read and print lightsensor data every three seconds*/
/* Validated for portMAX_DELAY to assist the task to wait Infinitely (without timing out) and ticks cannot be 0 in FreeRTOS timer. So ticks is assigned to 1*/
timerHandle_gdt = xTimerCreate(
(char * const) "Test Application to print Hello World", (THREESECONDDELAY/portTICK_RATE_MS),
TIMER_AUTORELOAD_ON, NULL, processUsbPrintMsg);
/* timer create fail case */
if (NULL == timerHandle_gdt)
{
/* Assertion Reason: "This software timer was not Created, Due to Insufficient heap memory" */
assert(false);
}
/*start the timer*/
retValPerSwTimer = xTimerStart(timerHandle_gdt, TIMERBLOCKTIME);
/* Timer start fail case */
if (TIMER_NOT_ENOUGH_MEMORY == retValPerSwTimer)
{
/* Assertion Reason: "This software timer was not started, Due to Insufficient heap memory" */
assert(false);
}
}
/*
* @brief This is a template function where the user can write his/her custom application.
*/
void appInitSystem(void * CmdProcessorHandle, uint32_t param2)
{
if (CmdProcessorHandle == NULL)
{
printf("Command processor handle is null \n\r");
assert(false);
}
AppCmdProcessor = (CmdProcessor_T *)CmdProcessorHandle;
BCDS_UNUSED(param2);
Application_init();
}
----------------------------------------------------End of application------------------------------------

All rights reserved. The use is subject to the XDK SDK EULA by Bosch Connected Devices and Solutions GmbH.
This documentation file has been automatically generated on Thu Mar 14 2019 19:12:49 by doxygen 1.8.8