SPI between Raspberry PI and ATMEGA328P

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all, this is my first message on this board so excuse in advance for the possibly trivial question, but I could not find any hint.

 

I am trying to setup a simple communication protocol via SPI between one Raspberry PI (master) and one ATMEGA328P (slave).

The protocol should have a very simple semantic: RPi send a commnd, the ATMEGA performs an action and respond with some data.

 

Wiring should be fine since I am able to program the ATMEGA via avrdude running directly on the RPi, by the way these are the connections:

RPI - ATMEGA

GPIO09 MISO - MISO PB4

GPIO10 MOSI - MOSI PB5

GPIO11 CLK - CLK PB6

 

First, super trivial version of the code should just blink a led connected to pin PD1 on the atmega:

Raspberry (Python):

import spidev
import time

#Initialze the SPI
spi = spidev.SpiDev()

try:
    spi.open(0,1)
    while True:
        resp = spi.xfer([0x00])
        print("resp: " + str(resp))
        time.sleep(1.0)
        resp = spi.xfer([0x01])
        print("resp: " + str(resp))
        time.sleep(1.0)
    spi.close()
except KeyboardInterrupt:
    # Ctrl+C pressed, so...
    spi.close()

ATMEGA:

#include <avr/io.h>
#include <util/delay_basic.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int main (void)
{
    DDRB &= ~((1<<2)|(1<<3)|(1<<5));   // SCK, MOSI and SS as inputs
    DDRB |= (1<<4);                    // MISO as output

    DDRC = 0XFF;

    SPCR &= ~(1<<MSTR);                // Set as slave
    SPCR |= (1<<SPR0)|(1<<SPR1);       // divide clock by 128
    SPCR |= (1<<SPIE);                 // Enable SPI Interrupt
    SPCR |= (1<<SPE);                  // Enable SPI

    sei();

    DDRD |= _BV(1);      // set pin 1 of port D as an output pin
    while(1)
    {
        _delay_ms(10);
    }
}

ISR (SPI_STC_vect)
{
    uint8_t data = SPDR;
    if(data != 0x01) {
        PORTD |= _BV(1);  // set pin 0 of port B high
    } else {
        PORTD &= ~_BV(1); // set pin 0 of port B low
    }
}

Actually, nothing happens. I only get a series of "[0]" as output of the python script, but no errors.

the ATMEGA seems not to receive anything, so I guess I am wrong in something on the ATMEGA side. 

Any hint is greatly appreciated.

 

Thanks,

Roberto

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you need to drive the ATmega slave select signal.

/Jakob Selbing

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh thanks, is it PB2, right? Can I statically drive it connecting to VCC? Also, is it possible to avoid the connection and autoselect the atmega as slave? 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

previ wrote:

Oh thanks, is it PB2, right? Can I statically drive it connecting to VCC? Also, is it possible to avoid the connection and autoselect the atmega as slave? 

 

Perhaps it is a good idea to first start reading on how the SPI interface works.

This will save you from future disappointments with code that after a very small change does no longer work.

 

and then continue with having a look at the AVR datasheet to see how it is best set-up for slave mode.

 

will cost you some time now, but it is time well invested in the future.......

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Are you sure that your RPi code works?

 

The trouble with trying to write both ends of a link at the same time is that you never know whether problems are in one end, or the other end - or both!

 

So start by getting you RPi Master code up & running with some standard SPI peripheral; eg, see:

 

https://www.avrfreaks.net/commen...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

meslomp wrote:

Perhaps it is a good idea to first start reading on how the SPI interface works.

This will save you from future disappointments with code that after a very small change does no longer work.

 

and then continue with having a look at the AVR datasheet to see how it is best set-up for slave mode.

 

will cost you some time now, but it is time well invested in the future.......

 

Totally agree.

To my excuse, I expected to be able to get away without knowing the details, at least for my use case, which is to use an atmega as an IO extension for the RPi, so I just need a basic protocol to send a command to do three actions: write a gpio, read a gpio, read an analog input.

 

By the way, If I understood correctly, the Slave Select pin (PB2) must be connected to the SPI0_CE0_N (GPIO08) on the RPi in order for the protocol to work; the pin is then driven by the OS driver implementation.

So it should be:

RPI - ATMEGA

GPIO08 CE0 - SS PB2

GPIO09 MISO - MISO PB4

GPIO10 MOSI - MOSI PB5

GPIO11 CLK - CLK PB6

 

Only doubt is, how can avrdude work missing Slave select pin? Possibly a different feature of SPI? 

 

Thanks

Roberto

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

previ wrote:
I just need a basic protocol

So wouldn't the UART be easier?

 

send a command to do three actions: write a gpio, read a gpio, read an analog input.

There are probably chips available which do exactly that!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

So wouldn't the UART be easier?

Yes, initially I was thinking about using both: SPI for programming and UART for communication protocol. It would than be possible to use the firmata library that should be pretty easy to use.

I dropped this design because, my bad, I preferred less connections and I thought SPI was not so complex. 

 

awneil wrote:

There are probably chips available which do exactly that!

This is also interesting: drop the atmega and choose a single purpose device. I will look for it.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

There’s zillions of examples for the raspi talking to the avr via spi and twi/i2c. Have you consulted these examples?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

previ wrote:
Only doubt is, how can avrdude work missing Slave select pin? Possibly a different feature of SPI? 

You seem to be confusing SPI with ISP, although the same pins may be involved, one has nothing to do with the other.

SPI talks to the SPI peripheral to transfer data while ISP talks to the OBD with in the chip for program and data loading.

 

The reason for connecting the CS is it clears the shift register so it is ready for new data, otherwise if any glitch occurs on the clk line will preload one or more bits in the shift register and mess up your data/command xfer.

As already suggested, take some time to understand how SPI works.

 

Good luck with your project.

Happy New Year!

 

Jim

edit: spelling

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

previ wrote:
 choose a single purpose device. I will look for it.

You could start with the ones on the above-mentioned Microchip SPI demo board ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
There’s zillions of examples for the raspi talking to the avr via spi and twi/i2c. Have you consulted these examples?

Actually yes, but none of them is working with my project (most probably for missing Slave Select).

Also I could not find a complete example, with RPi master - atmega slave with full duplex communication (master write, slave read and write back).

I might missed the right ones, by the way. Any suggestion is more than welcome.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I googled raspi arduino twi
And raspi arduino spi
More hits than Cheech and Chong’s bong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
I googled raspi arduino twi And raspi arduino spi More hits than Cheech and Chong’s bong.

 

Thanks, I didn't look at arduino examples as I am using an atmega328p with no other circuitry and I thought Arduino (UNO) could be sligthly different.

For example, consulting some examples (like this one http://mitchtech.net/raspberry-pi-arduino-spi/) I found they do not connect SS at all.

By the way, I am following this example: http://robotics.hobbizine.com/raspiduino.html it should be pretty close to my configuration, except it's C on the RPi instead of python.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's nothing magic about the Arduino UNO hardware - its just a mega328 with the bare essentials and a usb->serial interface. You can load Arduino code onto your mega328 chip.

 

Since you can get Arduino UNO clones for less than what you'd pay for just the mega328 chip out of China, would it not be easier for you to go this route? Using USB avoids the level translation issues and there's the likes of Firmata where all the hard work has been done.

Last Edited: Fri. Jan 3, 2020 - 05:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Kartman wrote:

There's nothing magic about the Arduino UNO hardware - its just a mega328 with the bare essentials and a usb->serial interface. You can load Arduino code onto your mega328 chip.

And just like that...it worked!

I took this example https://roboticsbackend.com/raspberry-pi-master-arduino-uno-slave-spi-communication-with-wiringpi/ with small changes to blink the led:

#include <SPI.h>

void setup() {
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPI.attachInterrupt();
  pinMode(PD1, OUTPUT);
}

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;
  if(c == 0x01) {
    digitalWrite(PD1, 1);
  } else {
    digitalWrite(PD1, 0);
  }
 
  SPDR = c+10;
}  // end of interrupt service routine (ISR) for SPI

void loop () { }

It's actually working with the Python script on the RPi side, unchanged, even with no Slave Select connection between RPi and atmega.

 

Now I will complete the protocol, thank you so much!