0

My question is about real time data logging and multi-interrupt. I am trying to program an MCU-ATMega 1280 by winAVR to make it read the pulses from the quadrature encoder(20um/pitch) and store the data into the flash memory (Microchip SST25VF080B, serial SPI protocol). After the encoder finishes its operation (around 2 minutes), the MCU export the data from the memory to the screen. My code is below.

But I don't know why it is not run correctly. There are 2 kind of bugs: one bug is some points suddenly out of the trend, another bug is sudden jumping value although the encoder runs slowly. The jumping seems to appear only when there is a turn.

I think the problem may lie only in the data storing because the trend happens like what I expected except for the jumps. I just want to ask if I run both ISR like what I did in the program. is there a case a ISR will be intervened by another ISR when it is running? According to atmega 1280 datasheet, it seems that when one ISR is occurring, no other interrupt allow to happen after the previous interrupt finish its routine.

    #include <stdlib.h>
    #include <stdio.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    #include "USART.h"  // this header is for viewing the data on the computer
    #include "flashmemlib.h"  // this header contains the function to read n 
        //write on the memory

    #define MISO     PB3
    #define MOSI     PB2
    #define SCK      PB1
    #define CS       PB0
    #define HOLD     PB6
    #define WP       PB7
    #define sigA     PD0        //INT0
    #define sigB     PD2        //INT2
    #define LED      PD3


        uint8_t HADD,MADD,LADD, HDATA, LDATA,i; //HADD=high address, MADD-medium address, LADD-low address
        volatile int buffer[8]; //this buffer will store the encoder pulse
        uint32_t address = 0;
        uint16_t DATA16B = 0;

        int main(void)
        {
        INITIALIZE();   //initialize the IO pin, timer CTC mode, SPI and USART protocol 
            for(i=0;i<8;i++)
                buffer[i]=0;

        sei();

        //AAI process- AAI is just one writing mode of the memory 
        AAIInit(address,0);
        while (address < 50)        //just a dummy loop which lasts for 5 secs (appox)
        {
        _delay_ms(100);
        address++;
        }
        AAIDI();//disable AAI process
        cli(); //disable global interrupt
        EIMSK &= ~(1<<INT0);
        TIMSK1 &= ~(1<<OCIE1A);

    //code for reading procedure. i thought this part is unnecessary because i am quite //confident that it works correcly
    return (0);
    }


    ISR(INT0_vect) // this interrupt is mainly for counting the number of encoder's pulses
    { // When an interrupt occurs, we only have to check the level of
         // of pB to determine the direction
        PORTB &= ~(1<<HOLD);
        for(i=0;i<8;i++)
            buffer[i+1]=buffer[i];

         if (PIND & (1<<sigB))
             buffer[0]++;
         else buffer[0]--;
        PORTB |= (1<<HOLD);
    }

    ISR(TIMER0_COMPA_vect)   //after around 1ms, this interrupt is triggered. it is for storing the data into the memory.
    {
        HDATA =(buffer[7]>>8)&0xFF;
        LDATA = buffer[7]&0xFF;
        PORTB &= ~(1<<CS);
        SEND(AD);
        SEND(HDATA);
        SEND(LDATA);
        PORTB |=(1<<CS);
    }

void SEND(volatile uint8_t data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF))){}   // Wait the end of the transmission
}
uint8_t  SREAD(void)
{
  uint8_t data;
  SPDR = 0xff;                    // Start the transmission
  while (!(SPSR & (1<<SPIF))){}    // Wait the end of the transmission
    data=SPDR;
    return data;
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

1 Answers1

0

In the Interrupt Service Routine of INT0 you are writing:

    for(i=0;i<8;i++)
        buffer[i+1]=buffer[i];

Means that when i=7 you are writing outside of the array's predetermined space, and probably overwriting another variable. So you have to do:

    for(i=0;i<7;i++)
        buffer[i+1]=buffer[i];

AVR will manage the interrupts as you described, based on the ATmega1280 datasheet. Alternatively, if you want to allow the interruption of an ISR vector by another interrupt you need to do as follows (example):

ISR(INT0_vect, ISR_NOBLOCK)
{...
...}
ChrisB
  • 498
  • 3
  • 10