Page 1 of 1

SPI connection between RPi and atmega32

Posted: Mon Jan 11, 2016 12:42 pm
by xubin
Hi all, I'm new here so excuse me for my newbie questions.
I'm trying to send some data from RPi to atmega32 and display it on LCD.
Here's atmega's code ic c:

Code: Select all

#include <mega32.h>
#include <delay.h>
#include <glcd.h>
#include <font5x7.h>

// Declare your global variables here
int sw = 0;
void main(void)
{       
    unsigned char temp;        
    GLCDINIT_t glcd_init_data;
    glcd_init_data.font=font5x7;
    glcd_init(&glcd_init_data);

    DDRB=(1<<DDB6); // MISO
    PORTD=(1<<PORTD7)|(1<<PORTD6)|(1<<PORTD5)|(1<<PORTD4)|(1<<PORTD3)|(1<<PORTD2)|(1<<PORTD1)|(1<<PORTD0); // Activate pullups
    SPCR=(1<<SPIE)|(1<<SPE); // Slave mode , Interrupt enabled , Clock = Fcpu / 4
    temp=SPSR;
	temp=SPDR;
	SPDR=PIND;
    #asm("sei");
    while(1);
}
interrupt [SPI_STC] void SPI_Serial_Transfer_Complete(void)
{          
    glcd_outtextxyf(5,40,"GOTCHA!");
    delay_ms(10);
    glcd_clear();
    PORTC=SPDR;
    SPDR=PIND;
}


And here's RPi's code in c++:

Code: Select all

#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <cstring>
#include <iostream>

using namespace std;


/**********************************************************
Declare Global Variables
***********************************************************/
int fd;
unsigned char hello[] = {'H','e','l','l','o',' ',
                           'A','r','d','u','i','n','o'};
unsigned char result;

/**********************************************************
Declare Functions
***********************************************************/
int spiTxRx(unsigned char txDat);

/**********************************************************
Main
***********************************************************/
int main (void)
{
   fd = open("/dev/spidev0.0", O_RDWR);

   unsigned int speed = 250000;
   ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

   while (1)
   {

      for (int i = 0; i < sizeof(hello); i++)
      {
         result = spiTxRx(hello[i]);
         cout << result;
         usleep (10);
      }

   }

   return 0;
}
/**********************************************************
spiTxRx
 Transmits one byte via the SPI device, and returns one byte
 as the result.

 Establishes a data structure, spi_ioc_transfer as defined
 by spidev.h and loads the various members to pass the data
 and configuration parameters to the SPI device via IOCTL

 Local variables txDat and rxDat are defined and passed by
 reference.
***********************************************************/

int spiTxRx(unsigned char txDat)
{

  unsigned char rxDat;

  struct spi_ioc_transfer spi;

  memset (&spi, 0, sizeof (spi));

  spi.tx_buf        = (unsigned long)&txDat;
  spi.rx_buf        = (unsigned long)&rxDat;
  spi.len           = 1;

  ioctl (fd, SPI_IOC_MESSAGE(1), &spi);

  return rxDat;
}
I expect that for each byte is sent, "GOTHA!" shown on LCD, but just two times is shown!
Any help would be appreciated.

Thanks in advance.

Re: SPI connection between RPi and atmega32

Posted: Mon Jan 11, 2016 4:44 pm
by ghp
Hello,
SPI is driven by the master. In the slave interrupt code, you do a lot of things, delay 10ms and use lcd output code. If the master sends data faster than the controller stays in ISR, then bytes sent are lost.
A rule of thumb is: keep ISR time as short as possible. One idea to avoid this would be to write arriving data to a ring buffer and let the main code get data out from the buffer to display on LCD.

Another topic is the reply byte you print out on sender side. If client needs to place these bytes to SPI send buffer, then from 'data received' to place data you have very narrow time slot to achieve this. This depends on send speed of server, with 'spidev' I get only a few usec to achieve this. I wrote highly optimized ISR code in assembler for an atmel328 as a slave processor (see http://heppg.de/ikg/wordpress/?page_id=549 for description) to achieve guaranteed 8usec response times. This are only 64 instructions in 8MHz '328...

Short term solution is to slow down send rate to say 1 byte per second and then increase send rate till data are not received correctly.

Regards,
Gerhard

Re: SPI connection between RPi and atmega32

Posted: Mon Jan 11, 2016 11:46 pm
by StuartF
You seem to be missing a few settings in the rpi code.

Add these global vars

Code: Select all

uint8_t bitsPerWord = 8;
uint8_t spiMode = SPI_MODE_0;
In main() add

Code: Select all

ioctl( fd, SPI_IOC_WR_MODE, &spiMode );
ioctl( fd, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord );
In your atmega code you pause 10ms (milli).
In your rpi code you pause 10us (micro).
try

Code: Select all

usleep( 10000 );
In spiTxRx() add

Code: Select all

spi.speed_hz = speed;
spi.bits_per_word = bitsPerWord;
Hope this helps.