Flexible bare-metal development template for the AVR microcontroller family (ATmega, ATtiny, etc.). Built with CMake. seamlessly supports standalone or mixed C and C++ development workflows.
Configured out-of-the-box for the ATmega328P, it can easily target any AVR chip by passing configuration variables during CMake setup.
- Directory Structure
- Prerequisites
- Quick Starts
- Configuration Options
- Library
- Editor Integrations
- ToDo List
- License
├── .clangd # Clangd configuration for code completion and analysis
├── .vscode/ # VS Code configuration directory
├── .zed/ # Zed editor configuration directory
├── cmake/
│ └── avr-gcc.toolchain.cmake # AVR cross-compilation toolchain file
├── include/ # Public header files (.h / .hpp)
├── lib/ # Local libraries and reusable components
├── src/ # Application source code (.c / .cpp)
│ └── main.cpp # Application entry point (or main.c)
├── CMakeLists.txt # Main CMake configuration file
└── README.md # Project documentation
Ensure the following tools are installed on your host system and available in your system PATH:
- AVR Toolchain: Microchip AVR Toolchain
- Programmer Utility: AVRDUDE.
- Build System: CMake (v3.16+) and a build generator like Ninja or GNU [Make].
1. Windows (Recommended: use MSYS2 UCRT64)
Open the MSYS2 UCRT64 terminal and run:
pacman -S --needed mingw-w64-ucrt-x86_64-avr-toolchain mingw-w64-ucrt-x86_64-avrdude mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-makeNote: Ensure
C:\msys64\ucrt64\binis added to your Windows systemPATHif invoking these commands outside the MSYS2 terminal.
Run the following command in your terminal:
sudo apt update && sudo apt install -y gcc-avr binutils-avr avr-libc avrdude cmake ninja-build makeRun the following command in your terminal:
brew install avr-gcc avrdude cmake ninjaClone the repository and navigate to the project directory:
git clone https://github.com/Arif-Rachmat/AVR-CMake-Template.git <YOUR_PROJECT_DIR>
cd <YOUR_PROJECT_DIR>Standard Configuration (Default: ATmega328P @ 16MHz):
cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/avr-gcc.toolchain.cmakeTargeting a Different MCU (e.g., ATtiny85 @ 8MHz via USBasp):
cmake -B build \
-DCMAKE_TOOLCHAIN_FILE=cmake/avr-gcc.toolchain.cmake \
-DMCU=attiny85 \
-DF_CPU=8000000UL \
-DAVRDUDE_PROGRAMMER=usbasp \
-DAVRDUDE_PORT=usbBuild the executable (.elf), binary (.hex), and output memory usage:
cmake --build buildUpload the firmware to hardware using avrdude:
cmake --build build --target flashDelete all compiled objects and generated output files:
cmake --build build --target clean
# Or simply remove the build folder: rm -rf build/Default parameters target the ATmega328P (e.g., Arduino Uno/Nano). You can override them inside CMakeLists.txt or pass them via -D flags during configuration:
| Option | Default Value | Description | Examples |
|---|---|---|---|
MCU |
atmega328p |
Target microcontroller architecture. | attiny85, atmega2560, atmega32u4 |
F_CPU |
16000000UL |
Clock frequency in Hz. | 8000000UL, 1000000UL |
AVRDUDE_PROGRAMMER |
arduino |
Programmer hardware driver. | usbasp, wiring, avrispmkii, serialupdi |
AVRDUDE_PORT |
COM5 |
Upload serial port. | COM3, /dev/ttyUSB0, /dev/ttyACM0 |
This template supports integrating reusable libraries through the lib/ directory. Each library can be kept self-contained with its own source files, headers, and CMake configuration, or following the exact directory structure of this template . while the main project handles adding and linking it to the application.
A minimal workflow looks like this:
lib/
└── my_library/
├── include/
│ └── my_library.h
├── src/
│ └── my_library.c
└── CMakeLists.txt
Make sure the CMakeLists of the library expose the header and add the source as static library:
add_library(${PROJECT_NAME} STATIC ${SOURCES})
target_include_directories(${PROJECT_NAME}
PUBLIC
include
)Or if using this template to build the library, simply set the AVR_PROJECT_TYPE variable at the top of CMakeLists.txt to LIBRARY:
set(AVR_PROJECT_TYPE LIBRARY) The application can then use the library normally:
#include <my_library.h>
int main()
{
my_library_init();
}This keeps reusable code separated from application-specific code while allowing everything to be built together as a single firmware project.
For more information about library and building one go to the lib README page.
Visual Studio Code (see VSCode folder)
- Install the C/C++ (
ms-vscode.cpptools) and CMake Tools (ms-vscode.cmake-tools) extensions. - Run CMake: Configure from the Command Palette (
Ctrl+Shift+P/Cmd+Shift+P). - Build using F7 and flash via the CMake side-bar target menu.
Zed (see Zed folder)
- Open the project folder in Zed.
- Run the setup task:
- Open command palette (
Ctrl+Shift+P/Cmd+Shift+P) and typetask: spawn. - Select
CMake: Configure (AVR Toolchain).
- Open command palette (
- Compile or flash the target:
- Select
CMake: Build Firmwareto compile. - Select
AVR: Upload / Flash Firmwareto flash.
- Select
- Code completion and register navigation (
<avr/io.h>) are handled natively viaclangd.
- Add more built in editor support/configurations.
- Add libraries repository links as the example of directly pulling and integrating a library.
- Expand chip target presets and MCU frequency configurations in
CMakeLists.txt. - Add documentation for custom
avrdudeprogrammer types and baud rates.
This project is licensed under the MIT License — free for both personal and commercial use.