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
| Action | Register Operation | Description |
|---|---|---|
| Set pin as output | DDRx |= (1 << DDBx); | Configure pin x on port x as output |
| Set pin HIGH | PORTx |= (1 << PORTx##); | Drive pin x HIGH (5V) |
| Set pin LOW | PORTx &= ~(1 << PORTx##); | Drive pin x LOW (0V) |
| Read pin state | PINx & (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.