This is a demonstrative project of software architecture based on 4 independent layers.
βββββββββββββββββββββββββββββββββββββββββββ
β APP LAYER β
β (Application / Orchestration) β
β - Main logic β
β - Task coordination β
βββββββββββββββββββββββββββββββββββββββββββ
β can ONLY call
βββββββββββββββββββββββββββββββββββββββββββ
β CONTROL LAYER β
β (Control / Business Logic) β
β - Algorithms β
β - State machines β
β - Data processing β
βββββββββββββββββββββββββββββββββββββββββββ
β can call β
ββββββββββββββββββββββ ββββββββββββββββββββββ
β DRIVER LAYER β β DRIVER LAYER β
β (Sensors) β β (Actuators) β
ββββββββββββββββββββββ ββββββββββββββββββββββ
β β
βββββββββββββ¬ββββββββββββ
β can call
βββββββββββββββββββββββββββββββββββββββββββ
β MCU-PERIPHERALS LAYER β
β (Microcontroller HAL) β
β - GPIO, ADC, UART, SPI, I2C β
β - Vendor libs (emlib, HAL) β
βββββββββββββββββββββββββββββββββββββββββββ
- APP can call CONTROL only
- CONTROL can call DRIVER and MCU-PERIPHERALS
- DRIVER can call MCU-PERIPHERALS only
- APP CANNOT call DRIVER or MCU-PERIPHERALS directly
- DRIVER CANNOT call CONTROL or APP
- MCU-PERIPHERALS CANNOT call anything (base layer)
- CONTROL CANNOT call APP
- System initialization
- Main application loop
- Coordination between CONTROL modules
- Global state management
- User interface (if applicable)
- Never accesses hardware directly
- Control algorithm implementation
- Business logic
- Sensor data processing
- State machines
- Validations and business rules
- Bridge between APP and DRIVER
- External sensor drivers (temperature, pressure, humidity via I2C)
- Logical actuator drivers (LED, fan, heater, alarm)
- External module drivers (displays, SD cards, etc)
- High-level device interface
- Maps logical concepts (ACTUATOR_FAN) to physical hardware (PORT_B, PIN_0)
- Uses MCU-PERIPHERALS to access hardware
- See: docs/actuator_driver_rationale.md - Explains why actuator_driver exists in DRIVER
- Lowest layer - microcontroller hardware abstraction
- Implementation/wrapper of vendor libraries
- GPIO, ADC, UART, SPI, I2C, PWM, Timers, etc
- Direct access to MCU registers
- β¨ Modularity: Each layer has well-defined responsibility
- π Reusability: Drivers can be reused in other projects
- π§ͺ Testability: Layers can be tested independently
- π Maintainability: Easy to locate and fix issues
- π Portability: Easy to change hardware - MCU changes affect only MCU-PERIPHERALS layer, external devices affect only DRIVER layer
architecture-example/
βββ .clang-format # Code formatting configuration (Barr C Standard)
βββ Makefile # Build system with validation
βββ README.md # Project documentation
βββ template.c # Template for .c files
βββ template.h # Template for .h files
βββ docs/
β βββ 4-layer-architecture.md # Architecture documentation
β βββ architecture_diagram.md # Visual diagrams
β βββ layer_rules.md # Layer rules reference
βββ build/ # Build artifacts (auto-generated)
β βββ obj/ # Object files
β βββ architecture-example.elf # Executable
βββ src/
βββ app/ # APPLICATION LAYER
β βββ inc/
β β βββ app.h # APP layer public interface
β βββ src/
β βββ main.c # Entry point
β βββ app_manager.c # Application coordinator
β βββ app_cooling.c # Cooling management module
β βββ app_hmi.c # HMI (buttons/LEDs) module
β βββ app_msg.c # Message/communication module
βββ control/ # CONTROL LAYER
β βββ inc/
β β βββ control.h # CONTROL layer public interface
β βββ src/
β βββ board_init.c # Board initialization
β βββ temperature_control.c # Temperature control algorithm
β βββ alarm_control.c # Alarm management
β βββ actuator_control.c # Actuator control abstraction
β βββ hmi_control.c # HMI control abstraction
βββ driver/ # DRIVER LAYER
β βββ inc/
β β βββ driver.h # DRIVER layer public interface
β βββ src/
β βββ temperature_sensor_driver.c # LM75 I2C sensor
β βββ humidity_sensor_driver.c # SHT31 I2C sensor
β βββ pressure_sensor_driver.c # BMP280 I2C sensor
β βββ actuator_driver.c # LED, fan, heater drivers
β βββ button_driver.c # Button event driver (interrupt-based)
β βββ uart_driver.c # UART communication
βββ mcu-peripherals/ # MCU-PERIPHERALS LAYER (HAL)
βββ inc/
β βββ mcu_hal.h # MCU HAL public interface
βββ src/
βββ mcu_peripheral_init.c # Peripheral initialization
βββ mcu_peripheral_internal.h # Internal HAL declarations
βββ gpio.c # GPIO HAL implementation
βββ adc.c # ADC HAL implementation
βββ uart.c # UART HAL implementation
βββ i2c.c # I2C HAL implementation
- This is an example/demonstrative project
- The code is simplified for learn purposes
- The architecture can be adapted according to project needs
This project uses make to automate compilation and validation. Available commands:
Compiles the entire project and generates the executable.
make build- Compiles all
.cfiles from the 4 layers - Generates object files in
build/obj/ - Links and creates the executable
build/architecture-example.elf
Removes all compiled files.
make clean- Deletes the entire
build/folder - Useful for doing a clean build from scratch
Validates if architecture rules are being respected.
make validateChecks:
- β APP does not include DRIVER or MCU-PERIPHERALS directly
- β CONTROL does not include APP
- β DRIVER does not include CONTROL or APP
- β MCU-PERIPHERALS does not include any upper layer
Auto-formats all source files according to Barr C Coding Standard.
make format- Applies consistent code formatting across all
.cand.hfiles - Uses
clang-formatwith modified Barr C Coding Standard - Ensures 2-space indentation, 80 character line limit
Shows project information and dependencies.
make infoDisplays:
- List of source files for each layer
- Allowed dependencies between layers
- Project structure overview
Shows help message with all available commands.
make help# Clean, compile and validate everything
make clean build validate
# Build and validate architecture
make build validate
# Format code and build
make format build
# Full workflow: format, clean, build, validate
make format clean build validate# Run in simulation mode
./build/architecture-example.elf
# Run for a limited time (3 seconds)
timeout 3 ./build/architecture-example.elfThe program runs in simulation mode (-DSIMULATION) printing messages about hardware operations.