This website uses cookies

Read our Privacy policy and Terms of use for more information.

Most embedded tutorials start with a framework. Arduino, HAL, CubeMX. They abstract away the hardware so you can get an LED blinking in five minutes without understanding a single register.

That is fine for prototyping. It is not fine for learning.

This project was a deliberate choice to do the opposite. I wanted to write directly to hardware registers on an ATmega644P microcontroller with nothing in between. To understand not just what the code does but what the silicon does when the code runs.

The hardware.

The ATmega644P is a DIP-40 AVR microcontroller running at 20 MHz on an external crystal. The PCB was designed by Richard Reeves, a lab technician at Aston University, who also provided components and guidance throughout. The board includes an LM317T voltage regulator and ten-way headers breaking out all 32 I/O pins. A Pololu USB AVR Programmer v2.1 handles flashing via STK500v2. Breadboard components for testing were five LEDs, one button and one active buzzer.

Why bare metal matters.

When you call digitalWrite() in Arduino, the library writes to the correct DDRx and PORTx registers on your behalf. You get the result without the understanding. When something breaks you have no mental model to debug from because you never built one.

Bare metal forces you to read the datasheet. You learn that DDRB controls the data direction of Port B, that setting a bit high makes that pin an output and that PORTB controls the output state. You learn how the interrupt control registers work, why sei() must be called after configuring EICRA and EIMSK and what happens in silicon when an interrupt fires. That knowledge transfers to every microcontroller you ever touch because every MCU has these concepts, just with different register names.

The build progression.

I worked through structured steps:

Fuse configuration and restoration. Understanding fuse bits is essential before anything else - wrong fuse settings can leave the chip in a state that looks broken and is not.

Double blink on PB0 using DDRB, PORTB and delayms. Proving the toolchain with the most basic I/O.

Five LEDs cycling sequentially using bit shifting on PORTB.

Button driving a buzzer via polling using PIND. Reading input state directly from the register.

Button driving a buzzer via interrupt using ISR, EICRA and EIMSK. Replacing polling with hardware interrupt handling.

Four-mode state machine using enum, ISR and software debounce.

Nine-mode state machine: the final build.

Each step added exactly one new concept, understood at register level before moving on.

The nine-mode state machine.

The final project cycles through nine modes on each button press. A volatile variable updated inside an INT0 interrupt service routine tracks the current mode. Software debounce inside the ISR prevents multiple triggers from a single physical press.

The modes: Chase, Blink All, Alternate, PWM Fade, Knight Rider, Binary Counter, Random, Reaction Game and Tetris Melody.

The Tetris melody was the most satisfying to build. The Korobeiniki theme has 30 notes across two phrases. Each note requires a specific frequency and duration. The buzzer is driven by toggling a GPIO pin at the note frequency using timer overflow interrupts, with the LED pattern updating between notes to sync visually. Getting the timing accurate required measuring against a reference recording and adjusting the tempo constant until it matched. The result is recognisable from several metres away.

One detail worth keeping.

ADC noise as a random seed: a floating, unconnected ADC input picks up electrical noise. That noise is unpredictable enough to seed a pseudo-random number generator. I read the ADC from an unused pin on startup and use the least significant bits as the seed. Different random patterns every power cycle with no RTC, no EEPROM and no external component. It is a small thing but it is the kind of detail you only find by reading the datasheet properly.

Next issue: Phaemos. Four hardware nodes, a ML pipeline and a live dashboard.

Zac

Reply

Avatar

or to participate

Keep Reading