Migration Guide: sl_system to sl_main for RTOS Applications#

Table of Contents#

  1. Overview

  2. Key Differences Between sl_main and sl_system

  3. Initialization Order Changes

  4. Migration Process

  5. Troubleshooting Common Issues

Overview#

The Silicon Labs platform service sl_main represents a significant evolution of the system initialization architecture previously provided by sl_system. This migration was driven by several key factors:

  • Enhanced RTOS support with earlier kernel initialization for better resource management

  • Improved memory placement to optimize RAM usage and power consumption in em2

  • Improved modularity with clearer separation between initialization stages

  • More flexible initialization hooks allowing for greater application customization

This guide will help you migrate your RTOS-based applications from sl_system to the new sl_main architecture.

If your application is bare-metal, you do not need to update your application as sl_system is compatible with sl_main, no actions are needed.

Key Differences Between sl_main and sl_system#

Feature

sl_system

sl_main

API

sl_system_init(), sl_system_process_action()

sl_main_init(), sl_main_second_stage_init(), app_init_early(), app_init()

RTOS Initialization

RTOS initialized late in the process

RTOS initialized early, after hardware setup

main() RTOS Integration

RTOS is started from the main() function

RTOS is started before the main() function and the main() function executes in its own task

start task configurability

No start task

Start task can be configured (stack size, priority and self deletion)

Extensibility

Limited hooks for application code

Multiple weak functions for application integration at various stages

Initialization Order Changes#

RTOS Initialization Timing#

One of the most significant changes in sl_main is the earlier initialization of the RTOS kernel:

sl_system initialization order:#

  1. Hardware initialization

  2. Internal services and drivers initialization

  3. Application initialization

  4. RTOS kernel start

  5. Task processing begins

sl_main initialization order:#

  1. Hardware initialization

  2. RTOS kernel start

  3. Internal services and drivers initialization (now running in the context of RTOS tasks)

  4. Application initialization (in RTOS task context)

  5. Task scheduling and processing continues

The most impactful changes of this new initialization sequence are that the application initialization occurs after the RTOS is started and that the main() function runs in its own task.

Consequences of Earlier RTOS Initialization#

  • Resource availability: Services are initialized with RTOS primitives already available

  • Task prioritization: Stacks and application tasks can be properly prioritized from the start

  • Synchronization: RTOS synchronization primitives can be used throughout initialization

  • main() task: The main() function is run in a separate task at maximum priority during the initialization process.

Migration Process#

Step 1: Update Project Configuration#

If using Simplicity Studio, update your .slcp file to replace the sl_system component with the new sl_main component.

If using the slc cli, update your .slcp file to replace the sl_system component with the new sl_main component and re-generate your project.

If you use a custom build automation tool such as cmake, first re-generate the project with either Simplicity Studio or slc cli once. Then remove all inclusions of sl_system files and add all files under the gsdk/platform/service/sl_main repo except for the files under gsdk/platform/service/sl_main/sl_system_compatibility and gsdk/platform/service/sl_main/legacy. The files under those repositories are for bare-metal applications only.

Step 2: Update Main Function#

  • With sl_main, the sl_system_init() function no longer exists and needs to be replaced by sl_main_second_stage_init() to finish the initialization process.

  • Since the kernel is already started, the call to start the kernel needs to be removed from the main() function.

Before (sl_system)#

#include "sl_system_init.h"
#include "sl_system_kernel.h"

int main(void)
{
  // Initialize Silicon Labs device, system, service(s) and protocol stack(s).
  sl_system_init();
  
  // Application-specific initialization
  app_init();
  
  // Start the kernel. Task(s) created in app_init() will start running.
  sl_system_kernel_start();
}

After (sl_main)#

#include "sl_main_init.h"

int main(void)
{
  // Initialize Silicon Labs device, system, service(s) and protocol stack(s).
  // Note that if the kernel is present, the start task will be started and software component
  // configuration will take place there.
  sl_main_second_stage_init();

  app_init();
}

Step 3: Update Application Initialization Functions#

  • Application tasks initialization functions typically don't need to change but need to account for the fact that the app_init() function is now called after the RTOS is started

  • In the unlikely situation where you need to initialize something before the kernel starts, you can leverage the new app_init_early().

Before (sl_system)#

#include "app_init.h"

void app_init(void)
{
  // Initialize application resources
  initialize_app_resources();
  
  // Create application task
  xTaskCreate(app_task_function, "App Task", APP_TASK_STACK_SIZE,
              NULL, APP_TASK_PRIORITY, NULL);
}

After (sl_main)#

#include "sl_main_init.h"

// Same app_init() from the sl_system implementation
void app_init(void)
{
  // Initialize application resources
  initialize_app_resources();
  
  // Create application task
  xTaskCreate(app_task_function, "App Task", APP_TASK_STACK_SIZE,
              NULL, APP_TASK_PRIORITY, NULL);
}

// Optional: Early initialization before RTOS is initialized
void app_init_early(void)
{
  // Any pre-RTOS initialization specific to application
}

// Optional: Typically unused in RTOS applications, but can be implemented if needed
void app_process_action(void)
{
  // No action required for RTOS applications
}

Step 4: Configure Start Task#

The main function is now executed in its own task. By default, the main stack size is 4096 and the task deletes itself after the initialization process is done. When deleting itself no memory is leaked and its deleted stack is repurposed to general purpose heap.

You can change the stack size in sl_main_start_task_config.h with SL_MAIN_START_TASK_STACK_SIZE_BYTES to a different size if needed either by changing the value manually in the file or by using Simplicity Studio's configuration tool with the sl_main component. If you changed SL_STACK_SIZE in your application, you should consider changing SL_MAIN_START_TASK_STACK_SIZE_BYTES to the same value.

You can also change the priority of the start task in sl_main_start_task_config.h by enabling SL_MAIN_ENABLE_START_TASK_PRIORITY_CHANGE and changing the priority of SL_MAIN_START_TASK_PRIORITY. This can be done either by changing the value manually in the file or by using Simplicity Studio's configuration tool with the sl_main component. The start task will always be at maximum priority (osPriorityRealtime7) when it starts. The priority set in SL_MAIN_START_TASK_PRIORITY will take effect just before the call to app_init(). Be mindful about the priority you set as other tasks may preempt app_init() if SL_MAIN_START_TASK_PRIORITY is too low. By default, SL_MAIN_ENABLE_START_TASK_PRIORITY_CHANGE is disabled to ensure that app_init() completes without getting preempted by other tasks.

Troubleshooting Common Issues#

Initialization Order Issues#

Problem: Components are being initialized in an unexpected order leading to dependency failures.

Solution:

  • Review the sl_main_second_stage_init() sequence

  • Review tasks' priorities

    • Keep in mind that the start task executes at maximum priority during the initialization process

  • Move hardware-dependent initialization to app_init_early() Called before RTOS is initialized

  • Move RTOS-dependent initialization to app_init() Called after RTOS is initialized and started

Missing Functionality#

Problem: Functions previously available in sl_system are not found in sl_main.

Solution:

  • Check the new function naming in sl_main_init.h

    • Make sure you are calling sl_main_second_stage_init() instead of sl_system_init() in your main() function

    • Make sure you removed the call to sl_system_kernel_start() from your main() function

  • Use the "weak" function overrides in sl_main to implement custom behavior

    • Available functions are:

      • app_init_early() Called before RTOS is initialized

      • app_init() Called after RTOS is initialized and started

RTOS Task Creation Timing#

Problem: Tasks created during initialization are starting too early or too late.

Solution:

  • Review tasks priorities

  • Tasks should be created in app_init() to ensure they start after all system components are initialized

Resource Availability#

Problem: RTOS resources (semaphores, queues, etc.) are being accessed before they're initialized.

Solution:

  • Ensure all RTOS resource creation happens in app_init() or later

  • Hardware-specific resources that must be configured before the RTOS is initialized should be initialized in app_init_early()

Tasks Starving#

Problem: Stack and application tasks are starving after initialization.

Solution:

  • Review tasks priorities

app_init() is never reached#

Problem: The app_init() function is never reached.

Solution:

  • Review SL_MAIN_START_TASK_PRIORITY in sl_main_start_task_config.h versus other task priorities, and make sure the start task is not getting preempted