This repository demonstrates a clean, modern C++ architecture for embedded systems using STM32 microcontrollers. It decouples application logic and C++ drivers from the specific hardware capabilities and the STM32CubeIDE generated boilerplate.
The goal is to provide a portable, professional structure where C++ code remains board-agnostic, while STM32-specific configuration (generated by CubeMX) stays isolated in target folders.
This project uses a Multi-Target Architecture:
App/: Contains the high-level application logic. This code is 100% portable.Device/: Contains C++ wrapper classes for peripherals (GPIO, USART, etc.). These classes do not include specific MCU headers directly but use an adapter layer.Adapters/: The Hardware Abstraction Layer.mcu_adapter.hselects the correct Low-Level (LL) drivers based on the selected target.Targets/: Contains board-specific implementations. Each folder here corresponds to a complete STM32CubeIDE project (including.ioc,Core,Driversand startup code).
/
├── App/ # Application Logic (Portable)
│ ├── Inc/
│ └── Src/
├── Device/ # C++ Drivers (Portable Wrappers)
│ ├── Inc/
│ └── Src/
├── Adapters/ # Hardware Abstraction Layer
│ └── Inc/
│ └── mcu_adapter.h
├── Library/ # 📚 External Libraries
├── Utils/ # 🛠 Helpers & C-to-C++ Bridge
└── Targets/ # 🎯 Board Specific Projects
├── Nucleo_L433/ # Complete CubeIDE Project for L433
└── Nucleo_.../ # Future Targets
- STM32CubeIDE (latest version recommended)
- A supported Nucleo board (currently configured for Nucleo-L433RC)
- Open STM32CubeIDE.
- Select File > Open Projects from File System....
- Click Directory... and navigate to
STM32_Embedded_CPP/Targets/Nucleo_L433. - Click Finish.
The project structure should look like this:
Since the source code (App, Device) lives outside the project folder, you need to ensure the linked resources are set up correctly if they appear broken.
The project uses the variable ${PROJECT_LOC} to refer to files relative to the target folder.
If folders App, Device, Utils are missing in the Project Explorer:
-
Right-click the Project -> New -> Folder.
-
Click Advanced >> -> Check Link to alternate location (Linked Folder).
-
Enter the location using the project variable:
App->${PROJECT_LOC}/../../AppDevice->${PROJECT_LOC}/../../DeviceUtils->${PROJECT_LOC}/../../UtilsAdapters->${PROJECT_LOC}/../../Adapters
-
Add the Include paths to the project properties:
- Connect your Nucleo Board.
- Click Run (Green play button).
- The Application should blink the LED and print to UART/LPUART.
Work primarily in the App/ folder. This is where your main loop (App_Run), initialization (App_Init), and business logic reside.
Work in Device/.
- Create your C++ wrapper class (
MyDriver.h/.cpp). - Include
mcu_adapter.hinstead of specificstm32l4xx_ll_*.hfiles. - If a specific LL driver is missing, add it to
mcu_adapter.h.
- Create a new folder in
Targets/(e.g.,Nucleo_F446). - Generate a new project using STM32CubeMX (or create a new STM32 Project in IDE) inside that folder.
- Recommended: Select "LL" (Low Layer) drivers for peripherals managed by
Device/classes (like GPIO, UART) to maintain efficiency. However, you can mixed LL and HAL drivers if needed (e.g., using HAL for USB/Ethernet). - Setup Linked Resources & Includes: Repeat the steps from Getting Started -> 3. Setting up linked resources to:
- Add the linked folders (
App,Device,Utils,Adapters). - Add the C and C++ Include Paths.
- Add the linked folders (
- Update
Adapters/Inc/mcu_adapter.hto support the new MCU family (add#ifdef STM32F4...).
Contributions are welcome! If you port this to a new board, please submit a PR with the new folder in Targets/.
MIT License. See LICENSE file for details.





