0
0
AutocadHow-ToBeginner · 4 min read

How to Write Bare Metal Code for Arduino: Simple Guide

To write bare metal code for Arduino, you program the microcontroller directly by manipulating its hardware registers without using Arduino libraries. This means writing code that sets pins, timers, and peripherals using C/C++ and the microcontroller's datasheet. You upload this code using the Arduino IDE or other tools as a normal sketch but avoid Arduino functions.
📐

Syntax

Bare metal Arduino code uses direct register access instead of Arduino functions like digitalWrite(). You write C/C++ code that sets bits in hardware registers to control pins and peripherals.

Example parts:

  • DDRB |= (1 << DDB5); sets pin 13 as output by setting bit 5 in the DDRB register.
  • PORTB |= (1 << PORTB5); sets pin 13 HIGH by setting bit 5 in PORTB.
  • PORTB &= ~(1 << PORTB5); sets pin 13 LOW by clearing bit 5 in PORTB.
c
DDRB |= (1 << DDB5);  // Set pin 13 as output
PORTB |= (1 << PORTB5); // Set pin 13 HIGH
PORTB &= ~(1 << PORTB5); // Set pin 13 LOW
💻

Example

This example blinks the built-in LED on pin 13 by directly controlling registers without Arduino functions.

c
#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    DDRB |= (1 << DDB5); // Set pin 13 as output

    while (1) {
        PORTB |= (1 << PORTB5);  // LED ON
        _delay_ms(500);
        PORTB &= ~(1 << PORTB5); // LED OFF
        _delay_ms(500);
    }

    return 0;
}
Output
The built-in LED on pin 13 blinks on and off every 500 milliseconds.
⚠️

Common Pitfalls

Common mistakes when writing bare metal Arduino code include:

  • Not setting the pin as output before writing HIGH or LOW.
  • Using wrong register names or bit positions for your Arduino model.
  • Forgetting to include delay functions to see visible changes.
  • Mixing Arduino functions with bare metal code causing conflicts.

Always check your microcontroller datasheet for correct registers and bits.

c
/* Wrong: Writing HIGH without setting pin as output */
PORTB |= (1 << PORTB5); // May not turn LED on

/* Right: Set pin as output first */
DDRB |= (1 << DDB5);
PORTB |= (1 << PORTB5);
📊

Quick Reference

ActionRegister OperationDescription
Set pin as outputDDRx |= (1 << DDBx);Configure pin x on port x as output
Set pin HIGHPORTx |= (1 << PORTx##);Drive pin x HIGH (5V)
Set pin LOWPORTx &= ~(1 << PORTx##);Drive pin x LOW (0V)
Read pin statePINx & (1 << PINx##);Read current input state of pin x

Key Takeaways

Bare metal Arduino code controls hardware by setting microcontroller registers directly.
Always set pin direction (input/output) before writing or reading pin values.
Use the microcontroller datasheet to find correct registers and bit positions.
Avoid mixing Arduino library functions with bare metal register code.
Delays are needed to see visible effects like blinking LEDs.