Skip to main content

Run eTrice on a Custom Target

eTrice can be customized to run on a variety of targets, from high-level operating systems to bare-metal microcontrollers with limited resource. This document outlines the necessary changes to the eTrice runtime library.

To get started, you need the minimal eTrice setup with an application project (e.g. org.eclipse.etrice.template.c) and the runtime library org.eclipse.etrice.runtime.c. If you have finished one of the Getting Started, then you are already set up.
To run eTrice on your OS and microcontroller, you can follow these steps

  1. Call eTrice main function
  2. Provide a OSAL implementation
  3. Configure logging

In this document you will also find two examples for an embedded system

  • Single-threaded bare metal without OS
  • Multi-threaded with FreeRTOS

The Main Function

By default, the eTrice generated code contains the standard C main function. Therefore, an eTrice desktop application for Windows or Linux compiles to an executable out-of-the-box.

For embedded targets which already define the main function, you can call the eTrice function manually. The function signature can be configured with ET_MAIN_FUNCTION_NAME and ET_DO_NOT_USE_ARGC_ARGV, the former sets the function name and the letter turns it parameterless. Both defines can be found in the etRuntimeConfig.h at org.eclipse.etrice.runtime.c/src/runtime/. Here is an example how to start an eTrice application manually.

First, configure the eTrice function name to etStart(void) in etRuntimeConfig.h

/* main function */

/** sets generated main function name, default is 'main' */
#define ET_MAIN_FUNCTION_NAME etStart

/** switches generated main function parameters to (void) */
#define ET_DO_NOT_USE_ARGC_ARGV

The eTrice function can be found in the generated source file node_*_Runner.c. Call this function to start the eTrice application.

extern int etStart(void);

int main(void) {
/* startup, e.g. HAL init*/
etStart();
/* application exit */
}

OSAL Implementation

The second step is to adapt the eTrice runtime to your target. The runtime is based on an OS abstraction layer (OSAL), which is a set of header files in src/common/osal/ in project org.eclipse.etrice.runtime.c. The structure is shown in the screenshot right-handed.

Screenshot Install eTrice SoftwareScreenshot Install eTrice Software

The remaining documentation will focus on these four built-in OSAL variants:

SystemOS / CompilerThreadingeTrice Implementation
DesktopWindows MinGWMultiMT_WIN_MINGW
Desktop /
Embedded
Linux/POSIX GCCMultiMT_POSIX_GENERIC_GCC
EmbeddedFreeRTOSMultiMT_32Bit_FreeRTOS_Generic
EmbeddedNone - Bare MetalSingleST_32Bit_Generic

All available OSAL implementations can be found in src/platforms/. The subfolders have a naming convention to describe the platform characteristics like threading type or MCU name (see readme.txt in src/platforms) as well.

The first two variants can be used to run your eTrice application on a desktop PC. You might use these platforms to rapid prototype the application layer for an eTrice embedded system. The POSIX variant can be adapted for embedded (Linux) systems.

For embedded systems, there are two implementation. First, a multithreaded application with FreeRTOS and second, a single-threaded bare metal system without OS. For both platforms, most of the required interfaces are already implemented. But there are some microcontroller specific functions that still need to be provided (e.g. target time). For concrete examples, you can have a look in the subfolder "examples/".

The eTrice OSAL

This section provides a brief description for the header files in src/common/osal/ project org.eclipse.etrice.runtime.c.

  • etPlatformLifecycle.h
    When the eTrice system is started, the generated code takes control of the main thread. The life cycle functions are hooks to customize the execution. The most important function is etUserMainRun(argc, argv), which is executed while the state machines are running. Here you can call the OS schedular or if bare metal perform basic tasks. In addition, there are more life cycle hooks available. You can look at the User Code Life Cycle to see when the functions are called in the eTrice application.
  • etTime.h
    The getTimeFromTarget(etTime *t) function provides the current time for the eTrice system. The time is necessary to schedule timer on a regular basis. Therefore, the implementation should be reasonable fast. Further, the resolution (e.g. 1ms or 5us) should satisfy the timing accuracy of your application. The time must not be necessarily absolute, it can be relative to the system starting point, but always incrementing.
  • etTimer.h
    The etTimer triggers OS-timers, e.g. used for polled execution.
  • etThread.h
    The etThread provides the threading to execute the state machines concurrently. An eTrice system has at least one etThread instance. In a multithreaded system, the threads are started asynchronously from the main thread. In a single-threaded system, the only etThread instance must be called from the main thread (etUserMainRun).
  • etSema.h
    This interface provides a signal mechanism for etThread. Usually etSema wraps the semaphore provided by the OS. Required for multithreaded systems.
  • etMutex.h
    Used for resource locking, mostly to protect data structures from race-conditions. Required for multithreaded systems.
  • etDatatypes.h
    Defines the typedefs and data structured needed for the OSAL implementation.
  • etLogger.h (*)
    Implements the optional logging infrastructure. The most simple implementation is to call printf. This topic is explained with more details in Logging Configuration.

Logging Configuration

eTrice comes with two built-in loggers

  1. textual logger
  2. sequence message chart (MSC) trace logger

Both can be deactivated by its switches in the etRuntimeConfig.h.

// requires printable stream
#define ET_LOGGER_ACTIVATE
// not suited for small/real-time embedded targets
#undef ET_MSC_LOGGER_ACTIVATE

The logging is optional and can be deactivated to get started. The MSC logger instruments the generated code with the cost of memory and performance. Therefore, it is usually not suited for embedded targets. In order to be functional, the logging interface osal/etLogger.h must be implemented.

Examples Embedded Platform

Single-threaded Bare Metal

The ST_32bit_Generic platform is a simple generic implementation for microcontrollers without operating system and threading. To get started, you have to provide an implementation for the target time.

  • etTime.h
    Implement the getTimeFromTarget(etTime *t) function based on the microcontroller timing mechanism, e.g. compute the time based on the HAL Clock or SysTick. You can find concrete implementations in the examples/ subfolder.
  • The remaining OSAL functions are not required and implemented empty
  • etThread.h
    No modifications needed. At start, the pointer to the single instance of etThread is saved.
  • etPlatformLifeCycle.h
    The etUserMainRun(argc, argv) function calls thread function of single etThread instance. As a result, the eTrice Actors and State Machines are executed on the main thread. The flow is described in the diagram below.
  • etTimer.h
    No modifications needed. Whenever the execution is idle, the pending timers and timeouts are scheduled (etCheckSinglethreadedTimers).

Diagram threading

Multi-threaded with OS

The MT_32bit_FreeRTOS_Generic platform is a generic implementation for an embedded system with FreeRTOS. It should be possible to get started without or only minor adjustments. Anyway, be sure to implement the required FreeRTOS hooks for your microcontroller.

  • The OSAL functions are delegating to FreeRTOS
  • etPlatformLifecycle.h
    The etUserMainRun(argc, argv) function calls the FreeRTOS scheduler. At this point, the eTrice system is running. The flow is described in the diagram below.

Diagram threading

User Code Life Cycle

In the eTrice application, you can insert custom code and hooks

  • Runtime hooks etUserEntry and etUserMainRun(argc, argv) in etPlatformLifeCycle.h
  • Model user code ctor in ActorClasses
  • Model user code action in StateMachine transitions
  • Model user codes entry, exit and do in StateMachine states

The following diagram shows the eTrice application life cycle including when and in which order the different codes are called.

Diagram eTrice Life Cycle