Programming Atmega 328P-PU using Raspberry Pi (B+)

[I am new to microcontrollers – whatever I’ve written worked for me, but proceed at your own risk]
I wanted to start playing with a little bit of home automation. I recently got RaspberryPi. I also got a few Atmegas 328P-PU (much cheaper than complete arduino! $1.7 each). However… I am still waiting for my programmer.

I did not want to wait. And I figured: RPi has SPI. It should be possible to program Atmega using RPI;)
So it was.

Raspberry Pi: if you are using Raspbian, it might be much easier. I am using RaspBMC, which does not set up SPI correctly to begin with.
Here are my steps to program Atmel Atmega 328P-PU.

Software installation

Get avrdude.
On Raspbian should be as easy as sudo apt-get install avrdude.
On RaspBMC:

apt-get install bison autoconf make gcc flex git
git clone
cd avrdude/avrdude
# make sure linuxspi is ENABLED
sudo make install

Run avrdude -c ?type and look for
linuxspi = SPI using Linux spidev driver

Connecting Atmega to RPI

Connect your RPi to Atmega. Word of caution make sure that you do not have 5V anywhere in your circuit. 5V will destroy GPIO on your RPI.

RPI PIN Atmega 328P-PU PIN
24 1 (reset)
19 MOSI 17
21 MISO 18
23 SCLK 19
17 3.3V 7, 20
25 GND 8, 22

You can use also GPIO 7 (port 26).

Software configuration and testing

Go to /usr/local/etc/avrdude.conf or /etc/avrdude.conf and find:

id = "linuxspi";
desc = "Use Linux SPI device in /dev/spidev*";
type = "linuxspi";
reset = 24;

Make sure to set ‘reset’ to the port you connected reset to (see first row in the table above).

On RaspBMC, trick port outputs to properly work with SPI
boblightd --help

Initialize your reset-controlling GPIO to output:

gpio -g mode 8 out

(change 8 to 7 depending which PIN you connected to Atmega Reset).
Next, put your reset GPIO to low:

gpio -g write 8 0

Now you should be able to get some info about your atmega:

sudo avrdude -p m328p -P /dev/spidev0.0 -c linuxspi -b 10000

You should see something like:

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e950f
avrdude: safemode: Fuses OK (E:07, H:D9, L:E2)
avrdude done. Thank you.

Let’s stop here for just a second. “Fuses OK (E:07, H:D9, L:E2)”. You can find fuse calculator here. My atmega initially had L:62. This means that it uses internal oscillator (8MHz) with divider (8), which effectively causes your Atmega to run @1MHz.
I don’t know why is that, but you can always change that.
Be extremely careful when manipulating fuses

sudo avrdude -p m328p -P /dev/spidev0.0 -c linuxspi -b 10000 -U lfuse:w:0xe2:m -U hfuse:w:0xd9:m -U efuse:w:0x07:m

I should mention, that while this write-up talks about Atmega328, you can program different atmegas by changing “-p” parameter in the command above.

Anyway. Now that you know that your atmega communicates with your raspberry Pi, it’s time to program it.
I connected 2 diodes with 220 Ohm resistors to PB0 and PB6.
Next, download: blink.c

It doesn’t have much comments, but: DDRB |= _BV(DDBx); sets up PB0 and PB6 as output, and then it blinks them every 500ms.
If you didn’t change your fuses to run without clock divider, change

#define F_CPU 8000000UL

to use 1000000L (1MHz) instead of 8MHz.

Compile and burn

I created little script for simple programs to compile and burn them. You can download it here: You can use it by calling
./ blink1.c

Compile your program:

avr-gcc -mmcu=atmega328p -Wall -Os -o blink1.c.elf blink1.c
avr-objcopy -j .text -j .data -O ihex blink1.c.elf blink1.c.hex

Set RESET to low:

gpio -g write 8 0

Burn the program:

/usr/local/bin/avrdude -p m328p -P /dev/spidev0.0 -c linuxspi -b 10000 -e -U flash:w:blink1.c.hex

Start the program (set RESET to high)

gpio -g write 8 1

SPI Test

I should mention, that if those instructions do not work, fall back to testing if SPI works for you.
You must have /dev/spidev0.0 devices.
If you don’t, try gpio load spi. try modprobe spidev. Add

to your /etc/modules.

It all depends on the linux you are using (and in particular, version of kernel).

SPI Test – communication

If all those did not help, short MISO and MOSI (port 19 and 21) on your raspberry PI and compile spitest:

gcc spidev_test.c
sudo ./a.out -D /dev/spidev0.0

This should give non-empty response.

If this one fails on “gcc” command, I am attaching one that I found in the web here spidev_test (unfortunately, I lost the source).

You can find all of the files mentioned here on GitHub.


I don’t remember exactly which things I took from which source, so I am pasting them all:

Raspberry Pi as an AVR Programmer


ATmega328P-PU 12MHz bootloader

AVR Raspberry Pi Programmer

Leave a Reply