Skip to content

naimmas/Embedded-Project-Template

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

381 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Embedded Project Template

A professional, test-driven embedded systems development template supporting multiple microcontroller platforms with comprehensive DevOps tooling, automated testing, and continuous integration.

License: GPL v3

🎯 Overview

This project template provides a robust foundation for embedded software development with a focus on Test-Driven Development (TDD), code quality, and DevOps best practices. It demonstrates a layered architecture approach suitable for production-grade embedded systems.

Key Features

  • βœ… Multi-Platform Support: STM32F4 (ARM Cortex-M4) and Raspberry Pi RP2040
  • πŸ§ͺ Test-Driven Development: Full unit testing with Ceedling, Unity, and CMock
  • πŸ“Š Code Coverage: Automated coverage reporting with gcov/gcovr
  • πŸ” Static Analysis: clang-tidy with customizable rulesets
  • 🎨 Code Formatting: clang-format for consistent code style
  • πŸ”’ Security Analysis: Flawfinder and Lizard for vulnerability and complexity analysis
  • 🐳 Containerized Builds: Docker-based development environment
  • πŸš€ CI/CD Pipeline: Jenkins pipeline with comprehensive quality gates
  • πŸ“¦ CMake Build System: Cross-platform build configuration
  • πŸ—οΈ Layered Architecture: Clean separation of concerns

πŸ“ Project Structure

Embedded-Project-Template/
β”œβ”€β”€ source/                      # Production source code
β”‚   β”œβ”€β”€ 00_MCU_SDK/             # MCU-specific SDK and startup code
β”‚   β”‚   β”œβ”€β”€ stm32/              # STM32F4 HAL and CMSIS
β”‚   β”‚   └── rp2040/             # Raspberry Pi Pico SDK
β”‚   β”œβ”€β”€ 01_MCU_PORT/            # MCU abstraction layer (MP)
β”‚   β”‚   β”œβ”€β”€ stm32/              # STM32 port implementations
β”‚   β”‚   └── rp2040/             # RP2040 port implementations
β”‚   β”œβ”€β”€ 02_HW_API/              # Hardware API abstraction (HA)
β”‚   β”‚   β”œβ”€β”€ ha_gpio/            # GPIO abstraction
β”‚   β”‚   β”œβ”€β”€ ha_iic/             # I2C abstraction
β”‚   β”‚   β”œβ”€β”€ ha_uart/            # UART abstraction
β”‚   β”‚   └── ha_timer/           # Timer abstraction
β”‚   β”œβ”€β”€ 03_DEV_DRV/             # Device drivers (DD)
β”‚   β”‚   └── dd_bmp388/          # BMP388 barometric pressure sensor driver
β”‚   β”œβ”€β”€ 03_PFM_SVC/             # Platform services (PS)
β”‚   β”‚   β”œβ”€β”€ ps_iic_bus_scanner/ # I2C bus scanner utility
β”‚   β”‚   β”œβ”€β”€ ps_logger/          # Logging service
β”‚   β”‚   └── ps_timer/           # Timer service
β”‚   β”œβ”€β”€ 04_APP_SW/              # Application software
β”‚   β”‚   β”œβ”€β”€ inc/                # Application headers
β”‚   β”‚   └── src/                # Application source
β”‚   └── SW_UTILS/               # Software utilities
β”‚
β”œβ”€β”€ tests/                       # Unit tests
β”‚   β”œβ”€β”€ 01_MCU_PORT/            # MCU port layer tests
β”‚   β”œβ”€β”€ 02_HW_API/              # Hardware API tests
β”‚   β”œβ”€β”€ 03_DEV_DRV/             # Device driver tests
β”‚   β”œβ”€β”€ cmock/                  # CMock configuration and stubs
β”‚   └── support/                # Test support files
β”‚
β”œβ”€β”€ tools/                       # Development tools
β”‚   β”œβ”€β”€ clang-format/           # Code formatting configuration
β”‚   β”œβ”€β”€ clang-tidy/             # Static analysis configuration
β”‚   └── jenkins/                # Jenkins-specific tools
β”‚
β”œβ”€β”€ build/                       # Build artifacts (generated)
β”œβ”€β”€ docs/                        # Documentation
β”œβ”€β”€ Dockerfile                   # Development container definition
β”œβ”€β”€ Jenkinsfile                  # CI/CD pipeline definition
β”œβ”€β”€ Makefile                     # Top-level build orchestration
β”œβ”€β”€ project.yml                  # Ceedling configuration
└── LICENSE                      # GPL v3 License

πŸ—οΈ Architecture

The project follows a layered architecture pattern:

  1. 00_MCU_SDK: Vendor-provided SDKs and low-level hardware definitions
  2. 01_MCU_PORT (MP): Microcontroller abstraction layer - direct hardware access
  3. 02_HW_API (HA): Hardware API layer - platform-independent hardware interface
  4. 03_DEV_DRV (DD): Device drivers - external component drivers
  5. 03_PFM_SVC (PS): Platform services - higher-level utilities and services
  6. 04_APP_SW: Application layer - business logic

This layered approach ensures:

  • Portability: Easy migration between different MCU platforms
  • Testability: Each layer can be tested independently with mocks
  • Maintainability: Clear separation of concerns
  • Reusability: Components can be reused across projects

πŸš€ Getting Started

Prerequisites

Native Development (without Docker)

  • Build Tools: CMake 4.0+, Make, GCC
  • ARM Toolchain: arm-none-eabi-gcc 14.2+
  • RP2040 SDK: Pico SDK 2.1.1+ (if targeting RP2040)
  • Testing: Ruby, Ceedling 1.0.1+
  • Code Quality: clang-tidy-19, clang-format-19
  • Coverage: gcov, gcovr
  • Security: flawfinder, lizard, junitparser
  • Python: 3.x with pip

Docker Development (Recommended)

  • Docker or compatible container runtime
  • Make

Quick Start with Docker (Recommended)

  1. Clone the repository

    git clone <repository-url>
    cd Embedded-Project-Template
  2. Build for STM32

    make cont-build MCU=stm32
  3. Build for RP2040

    make cont-build MCU=rp2040
  4. Run unit tests

    make cont-test MCU=stm32
  5. Generate code coverage

    make cont-cov MCU=stm32

Native Development Setup

  1. Configure Python environment (required for Ceedling)

    pip install gcovr flawfinder lizard junitparser
  2. Install Ruby and Ceedling

    gem install ceedling
  3. Install ARM toolchain (platform-specific)

  4. Install clang tools

    # Ubuntu/Debian
    apt-get install clang-tidy-19 clang-format-19
    
    # macOS
    brew install llvm@19
  5. Build the project

    make build MCU=stm32 BUILD_TYPE=Debug

πŸ”¨ Build Commands

Docker-Based Commands

Command Description
make build-image Build the Docker development image
make cont-build MCU=<mcu> Build firmware in container
make cont-test MCU=<mcu> MODULE=<module> Run unit tests
make cont-cov MCU=<mcu> Generate test coverage report
make cont-analyse MCU=<mcu> TYPE=<type> Run static analysis
make cont-analyse-all MCU=<mcu> Run all static analysis checks
make cont-analyse-flaws Run security analysis
make cont-format Format source code
make cont-format-tests Format test code
make cont-start Start interactive container shell
make cont-exec CMD="<command>" Execute custom command in container

Native Commands

Command Description
make build MCU=<mcu> BUILD_TYPE=<type> Build firmware natively
ceedling test:all Run all unit tests
ceedling gcov:all Generate coverage report
make analyse TYPE=<type> Run specific static analysis
make analyse-all Run all static analysis
make analyse-flaws Run security analysis
make format Format source code
make format-tests Format test code
make clean-all Clean all build artifacts

Parameters

  • MCU: stm32 or rp2040
  • BUILD_TYPE: Debug or Release
  • MODULE: Specific test module or all
  • TYPE: Static analysis type: bug, cert, core, misc, perf, read

πŸ§ͺ Testing

The project uses Ceedling (Unity + CMock) for comprehensive unit testing.

Running Tests

# Run all tests for STM32
export MCU=stm32
ceedling test:all

# Run specific test module
ceedling test:ha_gpio

# Run with coverage
ceedling gcov:all

# Run in container
make cont-test MCU=stm32 MODULE=all

Test Structure

  • Unit Tests: Located in tests/ directory
  • Mocks: Auto-generated CMock mocks in build/test/mocks/
  • Test Runners: Auto-generated by Unity in build/test/runners/
  • Reports: JUnit XML and HTML reports in build/artifacts/

Coverage Reports

Coverage reports are generated in multiple formats:

  • HTML: build/artifacts/gcov/TestCoverageReport.html
  • Cobertura XML: build/artifacts/gcov/TestCoverageReport.xml
  • JSON: build/artifacts/gcov/GcovCoverage.json

πŸ” Code Quality

Static Analysis

The project uses clang-tidy with multiple analysis categories:

# Analyze specific category
make analyse TYPE=bug MCU=stm32

# Run all categories (bug, cert, core, misc, perf, read)
make analyse-all MCU=stm32

# In container
make cont-analyse-all MCU=stm32

Analysis results are saved to build/source/<mcu>/Debug/clang-tidy.txt

Code Formatting

Automated code formatting with clang-format:

# Format source code
make format

# Format test code
make format-tests

# In container
make cont-format
make cont-format-tests

Configuration files:

  • Source code: tools/clang-format/configs/sources.clang-format
  • Test code: tools/clang-format/configs/tests.clang-format

Security Analysis

Security and complexity analysis with Flawfinder and Lizard:

make analyse-flaws

# In container
make cont-analyse-flaws

Reports generated:

  • Flawfinder: build/logs/ff_report.log
  • Lizard HTML: build/logs/liz_report.html
  • Lizard warnings: build/logs/liz_warns.log

Thresholds:

  • Cyclomatic Complexity: CCN ≀ 15
  • Function Length: NLOC ≀ 60
  • Parameters: ≀ 7

🐳 Docker Environment

The project includes a multi-architecture Docker image supporting both x86_64 and ARM64.

Image Details

Base: Ubuntu 24.04

Included Tools:

  • ARM GCC Toolchain 14.2.rel1
  • CMake 4.0.2
  • Raspberry Pi Pico SDK 2.1.1
  • Ceedling (Ruby gem)
  • clang-tidy-19, clang-format-19
  • gcovr, flawfinder, lizard, junitparser
  • Git, Python 3, build essentials

Building the Image

# Build with current user permissions
make build-image

# Manual build with custom UID/GID
docker build -t naimmas/embedded-dev-img:multi_mcu \
  --build-arg USER_UID=$(id -u) \
  --build-arg USER_GID=$(id -g) .

Using the Container

# Interactive shell
make cont-start

# Run single command
make cont-exec CMD="ls -la"

# Build project
make cont-build MCU=stm32

πŸš€ CI/CD Pipeline

The project includes a comprehensive Jenkins pipeline with multiple quality gates.

Pipeline Stages

  1. Checkout: Clean workspace and fetch source code
  2. Build: Compile firmware for all target platforms
  3. Unit Tests: Run test suite with coverage
  4. Static Analysis: clang-tidy analysis
  5. Security Analysis: Flawfinder and Lizard checks

Artifacts and Reports

  • Build logs with GCC warnings
  • JUnit test results
  • Code coverage reports (Cobertura format)
  • Static analysis warnings (clang-tidy)
  • Security vulnerabilities (Flawfinder)
  • Complexity metrics (Lizard HTML)

Running Locally

# Simulate CI build
make cont-build MCU=stm32 BUILD_TYPE=Debug
make cont-build MCU=rp2040 BUILD_TYPE=Debug
make cont-cov MCU=stm32
make cont-cov MCU=rp2040
make cont-analyse-all MCU=stm32
make cont-analyse-all MCU=rp2040
make cont-analyse-flaws

Jenkins Setup

  1. Install required Jenkins plugins:

    • Warnings Next Generation
    • JUnit
    • Code Coverage API
    • HTML Publisher
  2. Create pipeline job pointing to Jenkinsfile

  3. Configure post-build actions for reports

πŸ“Š Example Application

The template includes a demo application that:

  • Initializes the BMP388 barometric pressure sensor
  • Configures sensor settings (oversampling, ODR, IIR filter)
  • Reads temperature and pressure data in a loop
  • Demonstrates logging and I2C communication

Hardware Support

STM32F401xC:

  • GPIO control (LED)
  • I2C communication
  • UART logging
  • Hardware timers

Raspberry Pi RP2040:

  • GPIO control
  • I2C communication
  • UART logging
  • Timer functionality

πŸ› οΈ Development Workflow

Adding a New Module

  1. Generate module structure:

    ceedling module:create[module_name]
  2. Write tests first (TDD approach):

    // tests/02_HW_API/test_new_module.c
    #include "unity.h"
    #include "new_module.h"
    
    void test_new_module_should_initialize(void) {
        TEST_ASSERT_EQUAL(RET_OK, new_module_init());
    }
  3. Implement functionality:

    // source/02_HW_API/new_module/new_module.c
    response_status_t new_module_init(void) {
        // Implementation
        return RET_OK;
    }
  4. Run tests:

    ceedling test:new_module
  5. Check coverage:

    ceedling gcov:new_module

Code Review Checklist

  • All unit tests pass
  • Code coverage β‰₯ 80%
  • No clang-tidy warnings
  • Code formatted with clang-format
  • No security vulnerabilities (Flawfinder)
  • Cyclomatic complexity < 15
  • Function length < 60 lines
  • Build succeeds on all platforms

πŸ“š Documentation

🀝 Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for new functionality
  4. Ensure all quality checks pass
  5. Submit a pull request

Commit Message Format

<type>(<scope>): <subject>

<body>

<footer>

Types: feat, fix, docs, style, refactor, test, chore

πŸ“„ License

This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.

πŸ™ Acknowledgments

  • Ceedling/Unity/CMock: ThrowTheSwitch.org
  • ARM Toolchain: ARM Limited
  • Raspberry Pi Pico SDK: Raspberry Pi Foundation
  • STM32 HAL: STMicroelectronics

πŸ“§ Contact

For questions or support, please open an issue on GitHub.


Note: This is a template project designed to be customized for your specific embedded application needs. The example application demonstrates capabilities but should be replaced with your actual application logic.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors