[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.
On Raspbian should be as easy as
sudo apt-get install avrdude.
apt-get install bison autoconf make gcc flex git
git clone https://github.com/kcuzner/avrdude.git
# make sure linuxspi is ENABLED
sudo make install
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|
|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
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: burn-and-run.sh. You can use it by calling
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
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:
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: