eLooM for STM32 application  v3.3.0
A framework for multitasking low power embedded applications powerd by STM32
Loading...
Searching...
No Matches
Getting Started

Introduction

This section aims to be a step by step guide to explain how to build an application using the eLooM framework. As example we will reuse the simple demo application delivered with the framework.

Folder organization

Let's start giving a look at the folder organization of the framework and how it is integrated in a typical STM32 application. Fig.19 display on the left the eLooM folder structure and on the right an example of a complete STM32 application.

Fig.19 - Folder organization

The folder organization respects the application design, that is a soft real time and event driven system designed in multiple layers. So, if we think to a managed task as a tip of a subsystem that uses services and drivers, then Fig.24 is easy to understand, and it displays the relationship between the system layer.

Fig.24 - layers of the system

The map between folders and layer is displayed in the following table:

Layer Folders
App Application/Inc, Application/Src
3 eLooM/xxx/services, Application/xxx/services
2 eLooM/xxx/drivers, Application/xxx/drivers
1 Application/Drivers/cmsis, Application/Middlewares/freertos, Application/Drivers/stm32-hal

The application can provides services and low level drives to extend the framework.

On the side side of the layers (see Fig.1) there are few common components used across all system layers (Event and Error). These export some interfaces and implement common design patterns in order to decouple the application code from the algorithms implemented in the framework.

Application mandatory files

The application must provide few files expected by the framework. It is also possible to modify and reuse the ones provided with the simple demo. Basically these are configuration header files. The following list gives a short description of these files. For more details look at the file documentation:

  • Application/Inc/apperror.h - application specific error code.
  • Application/Inc/sysconfig.h - global system preferences file.
  • Application/Inc/sysdebug_config.h - configuration file for the debug resources.
  • Depending on the RTOS:
    • Application/Inc/FreeRTOSConfig.h - FreeRTOS configuration file. For more information see this web page.
    • Application/Inc/tx_user.h - ThreadX configuration file. For more information see this web page.
  • Application/Inc/stm32_assert.h - file generated by CubeMX.
  • Application/Inc/stm32xxxx_hal_conf.h - STM32 HAL configuration file for the specific MCU. It is generated by CubeMX.
  • Application/Src/App.c - define the application. This file defines the main entry points:
  • Application/Src/stm32_assert.c - file generated by CubeMX.
  • Application/Src/stm32xxxx_hal_timebase_TIM.c - HAL tick definition. File generated by CubeMX.
  • Application/Src/stm32xxxx_it.c - global interrupt service routine definition file. It is generated by CubeMX.
  • mx/Src/sysinit_mx.c - adeveloper must define here the SystemClock_Config(), SystemPower_Config(), the HAL_MspInit() and other functions generated by CubeMX.
  • mx/Inc and mx/Src - contain the HAL driver generated by CubeMX.

The CubeMX project used for the simple demo can be downloaded from this link.

The App.c file

In an eLooM based application the main() function and main.c file are provided by the framework and they are not intended to be modified by the developer. The developer needs another file where to define the application entry points in order to integrate the application code with the framework. In the simple demo this is done in the App.c file. In this file are defined two functions.

The first one, SysLoadApplicationContext(), is called by the INIT task after the basic hardware resources (except the ones used by the managed tasks) have been initialized, as well as the AED [2] and APMH [3] objects have been allocated and initialized. We use this function to instantiate the managed tasks, and to add them to the ApplicationContext object passed as a parameter. To add a managed task to the ApplicationContext we use the ACAddTask() function. In this way the INIT task is aware of all the application managed tasks.

The second function redefined in the App.c file is the SysOnStartApplication(). This function is used to connect the managed tasks. In the sample demo case, both managed tasks use the same driver object of type NucleoDriver. This function is called by the INIT task after all managed task have been initialized, so it is safe to assume that the driver has been allocated. Note that to share the driver it is used a pointer to the the base interface IDriver, but we know that actual type of that object is NucleoDriver.

Other optional stuff for the App.c file

If you remember Fig.21 the INIT task works with two other objects in order to implement the features of a real application. The simple demo does not use any error management strategy, so it does not need to implement the IApplicationErrorDelegate interface. For this reason the demo uses the default NullErrorDelegate. A more complex application, on the other side, has to deal with error. In this case the App.c file is a good place to redefine the SysGetErrorDelegate() function in order to provide an application specific implementation of the AED.

In the same way, it is possible to redefine the SysGetPowerModeHelper() function and provide an application specific APMH object.

How to implement the first Managed Task

The simple demo implements two Managed tasks in order to blink the LED and detect the push button events. At the beginning of the App.c file we can see how the task are declared and added to the ApplicationContext:

 // Application managed task.
 static AManagedTask *s_pxHelloWorldObj = NULL;

 // Application managed task.
 static AManagedTaskEx *s_pxPushButtonObj = NULL;


 sys_error_code_t SysLoadApplicationContext(ApplicationContext *pAppContext) {
   assert_param(pAppContext);
   sys_error_code_t xRes = SYS_NO_ERROR_CODE;


   // Allocate the task objects
   s_pxHelloWorldObj = HelloWorldTaskAlloc();
   s_pxPushButtonObj = PushButtonTaskAlloc();

   // Add the task object to the context.
   xRes = ACAddTask(pAppContext, s_pxHelloWorldObj);
   xRes = ACAddTask(pAppContext, (AManagedTask*)s_pxPushButtonObj);

   return xRes;
 }

Let's give a look to the HelloWorldTask to see how it is implemented. The framework takes some concept from the OO programming [4]. In particular it is widely used the inheritance implemented with the composition of the data structure and the polymorphism implemented with the virtual table.

To implement a Managed task we need three files:

  • HelloWorldTask.h: the normal header file
  • HelloWorldTask_vtbl.h: this header declares the redefined functions of the virtual table of the object class.
  • HelloWorldTask.c: the source code.

It is possible to use the eLooM template to generate the skeleton for these files.

Fig.25 - eLooM template

TO BE CONTINUED ...


[1] xxx stands for src or include.

[2] AED is the Application Error Delegate. For more information see the section Advanced support.

[3] APMH is the Application Power Mode Helper. For more information see the section Power Management.

[4] OO stands for Object-oriented programming.