ECU

Embedded C Utilities (ECU) is a hardware-independent collection of data structures and frameworks targeted for embedded platforms. This is a personal project primarily for personal use, but is documented here for those that may find is useful. Some features include:

  • Assertion framework.

  • Endianness framework.

  • Linked lists.

  • N-ary trees.

  • State machine framework.

  • Timers.

  • And more.

The following principles are followed to make ECU compatible with embedded platforms:

  • No dynamic memory allocation.

  • No recursion.

  • Portable. ISO C99-compliant with no system calls.

Directory Structure

ecu/
├── .devcontainer/
├── .github/
├── .vscode/
├── doc/
├── inc/
├── src/
├── tests
└── toolchains/
  • .devcontainer/: Settings for this repository’s VSCode devcontainer.

  • .github/: GitHub actions settings for CI pipeline.

  • .vscode: VSCode settings for debugging.

  • doc/: Documentation.

  • inc/: Public API used by application.

  • src/: Source code cross-compiled by application.

  • tests/: Unit and integration tests.

  • toolchains/: CMake toolchain files.

All files are internal to ECU besides inc/ and src/ which are consumed by the end user.

Porting

ECU must be cross-compiled with the user’s toolchain and requires at least an ISO C99 compliant compiler. The following steps explain how to add ECU to applications that use various build systems:

  1. Import ECU using CMake FetchContent:

    # ------------------------ Application CMakeLists.txt ------------------------
    FetchContent_Declare(
        ecu
        GIT_REPOSITORY https://github.com/ress059/ecu.git
        GIT_TAG        v0.1.0 # Replace with specific version desired.
    )
    FetchContent_MakeAvailable(ecu)
    
  2. Link ECU against the application with target_link_libraries(). CMake will automatically handle ECU’s include paths, compiler options, and other settings since FetchContent was used.

    # ------------------------ Application CMakeLists.txt ------------------------
    target_link_libraries(application # Name of application target.
        PRIVATE
            ecu
    )
    
  3. If assertions are enabled, define ecu_assert_handler(). This function executes when a run-time assertion fires in ECU. System response to this condition must be defined by the application. Leaving this undefined with assertions enabled results in a linker error.

    /* ------------------------------- application.c ----------------------- */
    #include "ecu/asserter.h"
    
    void ecu_assert_handler(const char *file, int line)
    {
        record(file, line);
        reset_cpu();
    }
    

Once imported, ECU can be used throughout the application. To provide additional scope, all public symbols are prefixed with “ecu” and library headers are placed in inc/ecu/:

/* #include "ecu/dlist.h" instead of #include "dlist.h" adds scope to avoid potential file name clashes. */
#include "ecu/dlist.h"

/* All public symbols are prefixed with "ecu_" to add scope and prevent potential symbol name clashes. */
static struct ecu_dnode my_node;
ecu_dnode_ctor(&my_node, .....);

Further Reading

Navigate through the sidebar or click any of the icons below to view more extensive documentation:

Doxygen Documentation. Explanation of ECU Modules. View ECU on GitHub.