SPI Interrupt on Master Device

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

Hello Everyone,

 

 

I am trying to execute SPI Interrupt on Master Device. Raise Interrupt on every transfer of byte. The Execution is not returning back to main program(it sticks in ISR). Code:

 

#include <avr/io.h>
#include <util/delay.h>                    /* Include Delay header file */
#include <stdio.h>
#include <string.h>
#include <avr/interrupt.h>
#include "pinDefines.h"

#include "USART.h"
#include "USART.c"

#define MOSI 3                                /* Define SPI bus pins */
#define MISO 4
#define SCK 5
#define SS 2
#define SS_Enable PORTB &= ~(1<<SS)            /* Define Slave enable */
#define SS_Disable PORTB |= (1<<SS)            /* Define Slave disable */

void SPI_Init()                                /* SPI Initialize function */
{    
    DDRB |= (1<<MOSI)|(1<<SCK)|(1<<SS);        /* Make MOSI, SCK, 0th pin direction as output pins */   
    DDRB &= ~(1<<MISO);                        /* Make MISO pin as input pin */
    PORTB |= (1<<SS);                        /* Disable slave initially by making high on SS pin */
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPIE);    /* Enable SPI, Enable in master mode, with Fosc/16 SCK frequency */
    SPSR &= ~(1<<SPI2X);                    /* Disable speed doubler */
}

void SPI_Write(char data)                    /* SPI write data function */
{
    char flush_buffer;
    SPDR = data;                            /* Write data to SPI data register */
    while(!(SPSR & (1<<SPIF)));                /* Wait till transmission complete */
    flush_buffer = SPDR;                    /* Flush received data */
    /* Note: SPIF flag is cleared by first reading SPSR (with SPIF set) and then accessing SPDR hence flush buffer used here to access SPDR after SPSR read */
}

char SPI_Read()                                /* SPI read data function */
{
    SPDR = 0xFF;
    while(!(SPSR & (1<<SPIF)));                /* Wait till reception complete */
    return(SPDR);                            /* return received data */
}

ISR(SPI_STC_vect)
{
    PORTB^=(1<<0) ;

}

int main(void)
{
    uint8_t count;
  
    DDRB|=(1<<0);

sei();
    
    
   
    SPI_Init();
    initUSART();
    
    SS_Enable;
    
    count = 0;
    while (1)
    {    

 SPI_Write(count);

count++;
   _delay_ms(1500);
    }
    
return(0);
}

 

 

 

 

Thanks in advance

Mav

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

What device? What compiler? Crystal ball is rather cloudy right now.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

2 ATMEGA328 Both Master and Slave. Atmel Studio

Mav

Last Edited: Tue. Apr 16, 2019 - 12:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is no logical reason for it to "stick" in the ISR. Nothing is conditional, so it should execute one statement, and exit. 

 

If you ""break all" while it is "stuck", what does PORTB show in the I/O Display (in Debug Menu > Windows > I/O). What happens when you single step from the break you did?

 

I'll bet that it comes back there so quickly that it just seems "stuck".

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Tue. Apr 16, 2019 - 04:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

can you explain how you came to the conclusion that the program is stuck in the ISR.

Did you get any compiler warnings?

As Jim already said there is no reason for the program to be stuck in the ISR, so a bit of clarification might be helping us a lot.

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

Comment: If Mav1985 were to put a breakpoint on that pin toggle statement in the ISR, then run it, it will break on the very first pass. If a continue is done, it will appear to immediatly break at the same place, giving the appearance of never moving. 

 

That is why I suggest to try, instead of continue, single stepping. I think that it will be found that it DOES execute and, in not too many steps, arrives back at that interrupt, as I hypothesize, in the first paragraph.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

That program makes no sense whatsoever anyway. It is both synchronous and asynchronous at the same time!! You need to pick one or the other.

 

(99% of people would not choose to use interrupts with SPI as the transfer is so quick that you can accomplish it faster than you can get into/out of an ISR - so there's no advantage to using interrupts - in fact a disadvantage!)

 

To correct your code above either do this:

    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPIE);    /* Enable SPI, Enable in master mode, with Fosc/16 SCK frequency */

and:

ISR(SPI_STC_vect)
{
    PORTB^=(1<<0) ;

}

or do it this way:

    SPDR = data;                            /* Write data to SPI data register */
    while(!(SPSR & (1<<SPIF)));                /* Wait till transmission complete */

But don't do both the interrupt AND the wait loop.

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

I have tried updating while loop as follows

 

while (1)
    {printString("dasfj0");

    
    SPI_Write(count);
        count++;
    _delay_ms(1500);
    }

 

I have added printString command for debugging purposes it's only printing once and turning led on.

 

 

It should fire interrupt after sending each count values (turning on and OFF PORT B Led each time through ISR)

 

 

 

Mav

Last Edited: Tue. Apr 16, 2019 - 12:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your response I was just trying to experiment. I am a beginner to AVR. I have done the same which you mentioned in my code above.

 

Mav