Skip to content

bebenlebricolo/AvrAsyncCore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

227 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AvrAsyncCore

A modular, fully testable, asynchronous core for 8-bit AVR — built to use all of the silicon you already own.

There are tens of millions of perfectly capable ATmega328 boards in the world, sold as "blink an LED" toys, with most of their real capability left dormant behind a beginner-friendly abstraction. AvrAsyncCore exists to hand that capability back.


Why this exists

Somewhere in a drawer you probably have an Arduino UNO or Nano from years ago. It still works. It is still, by any reasonable measure, a capable little computer: a 16–20 MHz core, hardware timers able to synthesize multi-MHz PWM for power electronics, an ADC, I2C, and more — all on inexpensive, robust silicon with an energy envelope that is genuinely hard to beat.

The point of this project is not to chase newer, shinier parts with smaller process nodes. There will always be something faster. The point is to do more with what is already on your desk: to push the hardware to its limits, to leverage every bit of the die, and to find the beauty in doing a lot with a few kilobytes.

It is also a deliberate reaction against bloat. Modern vendor stacks and code generators produce mountains of indirection in the name of "drivers." Constraint breeds craft: when you only have ~2 KB of RAM, every architectural decision has to mean something. This codebase tries to honour that.

If that resonates with you — minimalism, craft, sustainability through reuse, and squeezing real performance out of humble hardware — you're in the right place.

What it is

AvrAsyncCore is a layered, non-blocking Hardware Abstraction Layer and a cooperative "async core" for AVR microcontrollers (primary target: the ATmega328P, i.e. the Arduino UNO / Nano, at 16 MHz). Instead of an RTOS (often too heavy and too much overhead for tiny parts) or the Arduino stack (easy, but leaving most performance and determinism on the table), it occupies the middle ground:

  • Bare-metal performance and determinism, with
  • Structured, asynchronous, cooperative drivers, that are
  • Modular, multi-instance, and — unusually for embedded C — genuinely unit-testable.

You trade some of Arduino's hand-holding for performance, modularity, and control.

What makes it different

Asynchronous, non-blocking by design

Drivers never busy-wait. Each exposes a state machine driven either by a *_process() call in your main loop or by the relevant hardware interrupt. The CPU is free to do useful work instead of spinning. A typical application loop is a clean cooperative scheduler:

while (true)
{
    i2c_process(0U);
    adc_read_values();
    hd44780_lcd_process();
    /* ... */
}

Genuinely testable embedded code

This is the project's standout feature. The drivers are compiled and unit-tested on the host (PC) with GoogleTest — no microcontroller required. That includes a full I2C bus simulator with virtual devices and a simulated TWI peripheral, exercising master/slave, transmit/receive, and mode-transition scenarios that are nearly impossible to cover reliably on real silicon.

Most embedded HALs are untestable by construction. This one was designed the other way around.

Multi-instance via dependency injection

Drivers don't hard-code register addresses; they receive them through a handle:

config.handle.TWCR = &TWCR;
config.handle.TWBR = &TWBR;
/* ... */

This is what enables both multiple peripheral instances (e.g. several TWI units on an ATmega328PB driven by a single driver) and host-side testing (inject pointers to fake registers).

Consistent, defensive API

Every public function returns an explicit error enum, output parameters are * const, and each driver ships a get_default_config() plus a unitary get/set API for fine-grained control. The whole codebase reads as one library, not a pile of experiments.

Modular CMake build

Each driver and module is an independent CMake target with its own tests. Cross-compilation for AVR is handled by a dedicated toolchain file (Toolchain/avr8-gcc-toolchain.cmake); the test suite builds natively for your host.

Architecture

The codebase is organised in clear layers:

Drivers/    Hardware-facing peripheral drivers (touch registers directly)
Modules/    Higher-level features built on top of drivers (no direct HW access)
Sensors/    Sensor logic built on drivers/modules
Utils/      Small shared helpers (e.g. memutils)
App/        Reference application wiring it all together
Tests/      Host-side GoogleTest build aggregating every component's tests
Toolchain/  AVR8 GCC CMake toolchain file

The distinction is principled: drivers speak to hardware; modules compose drivers into higher-level capabilities (e.g. a software timebase built on a hardware timer).

What's included today

Component Type Status
ADC Driver Implemented + tested
I2C / TWI (master & slave, async) Driver Implemented + tested (with bus simulator)
IO (GPIO) Driver Implemented + tested
HD44780 LCD Driver Implemented + tested
Timer 8-bit / 16-bit / 8-bit async / generic Driver Implemented + tested
Timebase Module Implemented + tested
Thermistor Sensor Implemented + tested
PWM (software + hardware) Module In progress — see the pwm_driver branch / PR #6

The flagship: LabBenchPowerSupply

AvrAsyncCore grew out of the LabBenchPowerSupply project — a bench power supply built around an Arduino Nano, converting mains-derived voltage down to a regulated 0–16 V with voltage and current control. It is the intended embodiment of this project's philosophy: a real, useful piece of power electronics driven by a humble 8-bit part pushed to its potential. (The firmware CMake project is still named LabBenchPowerSupply_Firmware for this reason.)

Getting started

Prerequisites

  • An AVR toolchain on PATH: avr-gcc, avr-g++, avr-objcopy, avr-size, avr-objdump (plus avr-libc). On Windows, an Atmel Studio 7 installation is auto-detected from the registry.
  • CMake ≥ 3.20
  • For the tests: a host C/C++ compiler and GoogleTest (find_package(GTest)).

Build the firmware (cross-compiled for AVR)

The root build is configured for the ATmega328P at 16 MHz and selects the AVR toolchain automatically.

cmake -B build -DCMAKE_BUILD_TYPE=MinSizeRel
cmake --build build

On Linux you may need to point CMake at your AVR sysroot, e.g.:

export AVR_FIND_ROOT_PATH=/usr/avr   # or /usr/lib/avr, /usr/local/avr, ...

Build and run the tests (natively, on your machine)

The test suite is a separate CMake project under Tests/. It builds the drivers for the host with UNIT_TESTING defined and links against GoogleTest.

cd Tests
# On Linux, AVR register headers are taken from /usr/avr/include by default.
# On Windows, pass the path explicitly, e.g. -DAVR_INCLUDES=C:/path/to/avr/include
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
./run_all_tests.sh

run_all_tests.sh walks build/bin/, runs every test executable it finds, and prints a summary of any failures. No microcontroller required to run the tests — that's the point.

Roadmap

  • Finish the PWM module (software-generated PWM with user callbacks, and hardware PWM exploiting the timers' full waveform-generation capability, including complementary outputs with dead-time generation). Work in progress on the pwm_driver branch.
  • Formalise the cooperative "core" into a proper, reusable scheduler so the name fully earns itself.
  • Continuous Integration to build and run the full test suite on every push.
  • Explore portability of the architecture beyond AVR (the testable, async, dependency-injected design is largely silicon-agnostic).

Status & philosophy of "done"

This is a long-running, lovingly built personal project, intentionally incomplete in places rather than rushed. The foundations (drivers, modules, testing infrastructure) are solid and tested; some higher-level features are still in progress. Contributions, questions, and curiosity are welcome.

License

Released under the GNU General Public License v3.0. See LICENSE.

About

Asynchronous Avr core which relies on cooperative "multitasking"

Resources

License

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors