Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

AVR: SPI using interrupt

Status
Not open for further replies.

Athul

Newbie
Newbie level 4
Joined
Nov 24, 2018
Messages
5
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
99
Hello,
I'm completely new SPI protocol. I wrote my first code today. It was uisng polling method from these two tutorials
https://sites.google.com/site/qeewiki/books/avr-guide/spi
https://maxembedded.com/2013/11/the-spi-of-the-avr/

First link also has interrupt based code. But it's not working.


Code C++ - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// this program enables SPI communication and
// Sets the AVR into Master mode using interrupts
 
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util//delay.h>
 
volatile uint8_t data;
 
int main (void)
{
    char blah = 'B';
 
    DDRB |= (1<<2)|(1<<3)|(1<<5);    // SCK, MOSI and SS as outputs
    DDRB &= ~(1<<4);                 // MISO as input
 
    SPCR |= (1<<MSTR);               // Set as Master
    SPCR |= (1<<SPR0)|(1<<SPR1);     // divided clock by 128
    SPCR |= (1<<SPIE);               // Enable SPI Interrupt
    SPCR |= (1<<SPE);                // Enable SPI
 
 
    sei();
    SPDR = 'A';
    while(!(SPSR & (1<<SPIF)));
 
    while(1)
    {
        if ((SPSR & (1<<SPIF)) > 1)  // checks to see if the SPI bit is clear
        data=blah;               // send the data
        
        
 
        // if you use multiple slaves, switch slave here.
    }
}
 
 
ISR (SPI_STC_vect)
{
    SPDR = data;
    _delay_ms(100);
}




Code C++ - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// this program enables SPI communication and
// Sets the AVR into Slave mode
 
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//#include "USART.h"
 
volatile uint8_t data;
 
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();
 
    while(1)
    {
        _delay_ms(10);
    }
}
 
ISR (SPI_STC_vect)
{
    data = SPDR;
    transmitByte(data);
}



Can anyone suggest me how to properly code this.

I don't have two Arduino, so I'm using Protues to simulate code for ATMega168

1.PNG

Thanks
 

First of all remove delay from ISR and never do that again. We will ban users if they will post such a things.
 

Is it possible to edit post??

I'm new to micro controllers, so sorry if I make any mistakes
 

Easyrider83 is being a bit harsh (and does not have the ability to ban users!).

His comment is quite right though, it is very bad practice to add delays to an ISR. An ISR needs to react quickly when a hardware condition is met, for example when data arrives so if you add a delay it may not be ready again in time if another interrupt occurs.

Brian.
 

We will ban users if they will post such a things.
Not sure if the poster shares your sense of humour. Anyway, I agree that the coding style should be avoided.

Is it possible to edit post??

I'm new to micro controllers, so sorry if I make any mistakes
Editing is only enabled 30 minutes after posting. Consider that others already read your original post and start to think about it. It would be very confusing if it's changed in the meantime. Better send an addon explaining your new results.
 

Hi,

Drawing a flow chart and a timing diagram of your application before you start coding could in future help to avoid such mistakes.

After coding you then should compare the simualtor results with the drawings.

Klaus

Added:
About your schematic:
* a LED needs a current limiting resistor. Even if the simulator is happy without it, I strongly recommend to draw one, just not to miss it in the real circuit.
* use the /SS signals. They usually enable the slave's MISO output drivers, and they are used to synchronize "bit to byte"

Your code:
It now is sending and receiving data randomly.
But every application has it's own requirements. What data are sent via the SPI in the meaning of frame size and transfer rate.
Example: Maybe you want to send some commands with parameter via SPI. Such a command will have a maximum length in bytes.
--> use software byte buffer with appropriate size. During communication just store the received bytes in the buffer. After transmission the master should inactivate the SS signal to show the slave the End_of_frame ... and the slave may start to parse the complete frame.

Klaus
 

Thanks for all the replies.

I was able to implement Slave receive interrupt, Master is transmitting data via polling.


Code C++ - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// this program enables SPI communication and
// Sets the AVR into Master mode
 
#include <avr/io.h>
#include <util/delay.h>
 
int main (void)
{
    char data = 'c';
    //initUSART();
    
    //printString("MASTER\r\n");
 
    DDRB |= (1<<2)|(1<<3)|(1<<5);    // SCK, MOSI and SS as outputs
    DDRB &= ~(1<<4);                 // MISO as input
 
    SPCR |= (1<<MSTR);               // Set as Master
    SPCR |= (1<<SPR0)|(1<<SPR1);     // divided clock by 128
    SPCR |= (1<<SPE);                // Enable SPI
    
    while(1)
    {
        SPDR = data;                 // send the data
        while(!(SPSR & (1<<SPIF)));  // wait until transmission is complete
        //transmitByte(SPDR);
        //data = SPDR;
        _delay_ms(100);
        // if you have multiple slaves, this is where you want to switch
    }
}




Code C++ - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// this program enables SPI communication and
// Sets the AVR into Slave mode
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "USART.h"
 
volatile uint8_t data;
 
volatile uint8_t data;
 
void spi_init_slave (void)
{
    DDRB=(1<<PINB4);               //MISO as OUTPUT
    SPCR=(1<<SPE)|(1<<SPIE);       //Enable SPI && interrupt enable bit
    SPDR=0;
}
 
ISR(SPI_STC_vect)
{
    uint8_t y = SPDR;
    PORTC = y;
    transmitByte(y);
}
 
int main(void)
{
    initUSART();
    printString("Slave\r\n");
    DDRC = 0XFF;
    spi_init_slave();                             //Initialize slave SPI
 
    sei();
    while(1)
    {
 
    }
}



This one works.

How can I make master to transmit data using interrupt??
and slave to transmit data to master using interrupt??


use the /SS signals. They usually enable the slave's MISO output drivers, and they are used to synchronize "bit to byte"


Code C++ - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DDRB |= (1<<2)|(1<<3)|(1<<5);    // SCK, MOSI and SS as outputs
    DDRB &= ~(1<<4);                 // MISO as input
    DDRC |= (1 << PC1);              // To select SS
    PORTC |= (1 << PC1);
 
    SPCR |= (1<<MSTR);               // Set as Master
    SPCR |= (1<<SPR0)|(1<<SPR1);     // divided clock by 128
    SPCR |= (1<<SPE);                // Enable SPI
    
    while(1)
    {
        PORTC &= ~(1 << PC1);         // Select slave
        SPDR = data;                 // send the data
        while(!(SPSR & (1<<SPIF)));  // wait until transmission is complete
        //transmitByte(SPDR);
        //data = SPDR;
        PORTC |= (1 << PC1);         // UnSelect slave
        _delay_ms(500);
        // if you have multiple slaves, this is where you want to switch
    }



You mean this way???

Example: Maybe you want to send some commands with parameter via SPI. Such a command will have a maximum length in bytes.
--> use software byte buffer with appropriate size. During communication just store the received bytes in the buffer. After transmission the master should inactivate the SS signal to show the slave the End_of_frame ... and the slave may start to parse the complete frame.

is there any example code ?

I have one general doubt about SPI communication.

Say I will send a command to Slave from Master. So when clock pulses are complete Slave Data Register will have data transmitter by Master and Master Data Register will have data transmitted from Slave. It could be some junk data. The Slave then process this data to check whether it is a read or write command. If it is a valid command it will send an ACK back to receiver. To read this ACK from Slave, Master will send some junk data to Slave and once transmission completes Master will have ACK data and Slave will have Junk data. I hope I'm clear up to this point.
My doubt is, before Master transmit Junk data to receive ACK data from Slave, Slave should read it's data received before(Here it is Read/Write command) process this info and if it's valid, place ACK in Data register, so that when master sends junk data to read ACK. SO for this duration of time, Should MATER wait in it's loop????
 

How can I make master to transmit data using interrupt??
and slave to transmit data to master using interrupt??

I have one general doubt about SPI communication.
Say I will send a command to Slave from Master.

The concept of interruption in the context of synchronous device communication in general applies mostly to the slaves, once the master is the one who decides at any time to send data, interrupting and forcing them to pause their tasks to handle the data just received, as well as it is the master which sets the clock.

I believe that either if implemented by the microcontroller's built-in hardware module, or if by software library, on the Master side there should be available some status indicating the success of the writing/reading at the slave.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top