Search code examples
cspiinterruption

Atmel : can't turn to the main after interruption


I am using atmega328P , as it shown in the attached picture when the interruption is executed , the program doesn't turn back to the main to execute the rest of the program ? i made 2 functions ; one to blink led in portC and the other in PORT D the Led in PORT D (interruption) is working fine but the Led for PORT C in the main is not executed is there a problem ??

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

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

#define ACK 0x01 

void portc_led(void)
{
    PORTC|=(1<<5);
    _delay_ms(100);
    PORTC=(0<<5) ;
    _delay_ms(100);
    PORTC|=(1<<5);
    _delay_ms(100);
    PORTC=(0<<5) ;
    _delay_ms(100);
}

void portd_led(void)
{
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
}


int main(void)
{

    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


    DDRC= 0xFF ; // set PORT C as output 
    DDRD = 0xFF ;
    sei();

    spi_send_data(ACK);

    portc_led();

}



ISR(SPI_STC_vect)
{
    portd_led();

}

Solution

  • first of all your code will have a compile Error! because you don't provide a reference to spi_send_data function

    but let us imagine that you include it above this piece of code

    analyse your code

    you say that

    interruption is executed , the program doesn't turn back to the main

    the program execution path definitely will ruturn to main routine... where will it go ?! :) the code will execut the portc_led function one time (and only one time) maybe before interrupt or maybe after interrupt or maybe interrupt happen in between the function ... so maybe portc_led alredy excuted happen befor interupt but you did not see it becuse it executed in only 400 ms !! and after finsh interupting nothing to do just wait for other interupt ! ..

    simple solution : try to change the 100ms delay in portc_led to bigger delay and you will see ...

    little advices for improve practicing techniques

    1. look at this code PORTB=(0<<5) equivalent to portB=0b00000000 when you try to clear single bit in register you clear all register's bits ! which is not good ...use this code PORTB&=~(1<<5) for clear single bit which make bitwaise & between portc and 0b11101111 only change single bit and keep other bits as it is
    2. always in interrupt routine make it small as much as you can ... just raise a flags and handle it in the main loop ... read more way you should make it small routine
    3. your program dose not have a mian loop !! (sometimes called super loop).. this loop is simply an infinity loop come after initalization of your systerm and run over and over ... some compiler add empty infinity loop at the end of main routine and other compiler dose not add ... it's a good practice to have a main loop in the main routine even if you not use it ! To keep your program alive

    modify the code

    not that the following code will not excute blancking in parallel (simultaneously) it will excute them in series (not simultaneously).. if you like to have a parallel blanking use timer interupt in portc_led insted of delay /or use an RTOS (a little bit advanced topic)

    
    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    #define ACK 0x01
    
    volatile char spi_interupt_flag = 0;
    
    
    void portd_led(void)
    {
        // this will blank led in pd7 for 3 sec
        for(char i=0;i<6;i++){  
            PORTD^=(1<<PD7) ; // toggle pd7
            _delay_ms(500); // you will see 500 ms blank
        }
    }
    
    
    int main(void)
    {
    
        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
    
    
        DDRC= 0xFF ; // set PORT C as output
        DDRD = 0xFF ;
        sei();
    
        spi_send_data(ACK); // this code will make compile error if you not provide a source for implementation
    
        
        
        while(1){
            if (spi_interupt_flag)
            {
                //this code only execute when data received from SPI
                portd_led(); //do whatever you want to do for handle it
                spi_interupt_flag = 0; //reset the flag again
            }
            PORTC^=(1<<PC5); //toggle pc5 for ever
            _delay_ms(1000); // pc5 will toggle every 1 sec unless ther is interupt 
        }
    
    }
    
    
    
    ISR(SPI_STC_vect)
    {
        // just set a flag for handle interrupt in main     
        spi_interupt_flag = 1;
    }