Problems with Timer Interrupt and return address from ISR

hi everybody,
I'm a doing a GPIB-USB arduino based interface and i have a problem handling interrupts. I am using an Arduino Uno.

The timer counts for 0.5s and if it is not reset it calls the ISR. The problem is that when it calls it, it blocks and it calls it three times in a row until the watchdog (set at 2s) restarts arduino. I read that it s not good practice to do too many things into the ISR, so basically I only restart the counter and set a flag which should then allow arduino to go back to the main loop and print some error messages. Yet, it does not work. I would like to know exactly what is the return address and if it is possible to modify it, or know a clever way to check where the interrupt was called from to better debug everything.

Thanks :smiley:

This is the code

/*
 * GIPB USB Adapter
*/

#include <string.h>
#include <avr/io.h>
#include <avr/wdt.h>

// Define PIN name
#define DIO1  2
#define DIO2  3
#define DIO3  4
#define DIO4  5
#define DIO5  6
#define DIO6  7
#define DIO7  8
#define DIO8  9
#define IFC   A5
#define EOI   A4
#define DAV   A3
#define NRFD  A2
#define NDAC  A1
#define ATN   A0
#define REN   GND
#define SRQ   10


// set Commando val
char com[256] = "";
char c = 0;
int p = 0;
unsigned long t;
int wordsent = 0;
int timer1_counter;
int rw = 0;
boolean timeout = false;


void setup() {
    
  // initialize the serial device
  Serial.begin(115200);
  Serial.print("ELI 1.2 ready!");
           

  // initialize gpib line
  DDRC = DDRC | B00011110;
  PORTC = PORTC | B00011000;
  PORTC = PORTC & B11111001;
  
  //activate the watch dog with time_out = 4 s
  wdt_enable(WDTO_4S);
  
  // disable all interrupts
  noInterrupts();
  
  // initialize timer1 
  TCCR1A = 0;
  TCCR1B = 0;

  // Set timer1_counter to the correct value for our interrupt interval
  timer1_counter = 65536;   // preload timer 65536-16MHz/256/2Hz ---> timeout = 0.5s
  
  TCNT1 = timer1_counter;   // preload timer
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();   // enable all interrupts

}

void loop() {
  
  if(timeout){
    if (rw == 0){
    Serial.println("Writing Timeout");
    }
    else{
      Serial.println("Reading Timeout");
    }
    gpibIFC();
    *com = 0; p = 0; c = 0;
    timeout = false;
   }
   
  TCNT1 = timer1_counter;   // preload timer

  int i;
    
  if (Serial.available()) {
        c = Serial.read();
        *(com + p) = c; *(com + p + 1) = 0; 
        p++;
      }
             
  if (strcmp(com,"check") == 0){ Serial.print("Arduino ready to work");
      *com = 0; p = 0; c = 0;Serial.flush();}
      
  if (';' == c) {
    *(com + p - 1) = 0;
    if (0 == strcmp("IFC", com)) { gpibIFC();
    } else if (0 == strcmp("DCL", com)) { gpibDCL();
    } else if (0 == strcmp("STA", com)) { gpibLineStatus();
    } else {
      char *saveptr;
      char command;
      char address[20];
      int addr[10];
      char option[255];
      char *tmp = NULL;
      char *primo = NULL;
      char delim[] = " ";          
      char delim2[] = ";";
      char delim3[] = ",";
      char *secondo = NULL;
      
      primo = strtok(com,delim);
      secondo = strtok(NULL,delim);
      secondo = strtok(secondo,delim2);
      command = primo[0];
      strcpy(option,secondo);

      for (i = 1 ; i < strlen(primo) ; i++) {
        address[i-1] = *(com + i);
      } address[i-1] = 0;  
      
      tmp = strtok(address,delim3);
      int j = 0;
      while(tmp != NULL){
        addr[j] = atoi(tmp);
        tmp = strtok(NULL,delim3);
        j++;
      }
      strcat(option, "\r\n");
      
      if ('W' == command) {
        rw = 0;  
        t = micros();
        gpibTalk(addr, option, j);
        t = micros() - t;
        Serial.print(wordsent);
        Serial.print(" bytes sent in ");
        Serial.print(t);
        Serial.print("us \n");
        wordsent = 0;
      } else if ('R' == command) {
        rw = 1;
        char str[255] = "";
        t = micros();
        gpibListen(addr, str, "\r\n");
        t = micros() - t;
       /* Serial.println(strlen(str));
        Serial.println("bytes received in ");
        Serial.println(t);
        Serial.println("us \n");*/
        if(!timeout){
        Serial.println("from GPIB%");
        Serial.println(str);}
      } else if ('C' == command) {
        gpibSDC(addr);
      } command = 0;
    }
    
    *com = 0; p = 0; c = 0;
  }
  
  wdt_reset();
  TCNT1 = timer1_counter;   // preload timer
}

void gpibTalk(int *addr, char *str, int n) {
  
  // attention
  DDRC = DDRC | B00010001; // set EOI and ATN output
  PORTC = PORTC | B00010000; // set EOI HIGH
  PORTC = PORTC & B11111110; // set ATN LOW
  
  // unlisten
  gpibWrite(0x3F);
  
  // talker address
  gpibWrite(0x40); 
  
  // listener addresses
  for (int i = 0 ; i < n ; i++){
  gpibWrite((byte)(0x20 + addr[i])); 
  }
  // end of attention
  PORTC = PORTC | B00000001; // set ATN HIGH
    
  // write string
  while (0 != *(str + 1)) {
    gpibWrite(*str);
    str++;
    if(timeout){break;}
  }
  
  // write last char
  PORTC = PORTC & B11101111; // set EOI LOW
  gpibWrite(*str);
  PORTC = PORTC | B00010000; // set EOI HIGH  
  TCNT1 = timer1_counter;   // preload timer

}

boolean gpibListen(int *addr, char *str, char* del) {
  
  DDRC = DDRC | B00000001;
  
  // attention
  PORTC = PORTC & B11111110;

  // unlisten
  gpibWrite(0x3F);

  // talker address
  gpibWrite((byte)(0x40 + addr[0]));

  // listener address
  gpibWrite(0x20); 
  
  // end of attention
  DDRC = DDRC | B00000110;
  PORTC = PORTC & B11111001;
  PORTC = PORTC | B00000001;
  
  // recieve data
  int i, s, len = strlen(del);
  byte c;
  boolean isLast, isDel;
    
  s = 0;
  do { if(!timeout){
    isLast = gpibRead(&c); if(timeout){break;} *(str) = c;
    isDel = true;
    for (i = 0 ; i < len ; i++) {
      isDel = isDel & (*(str - i) == *(del + len - i - 1));
    }
    str++;}
  } while (!(isLast || isDel));
  *(str) = 0;
  
  
  return true;
}

void gpibWrite(byte data) {
  
  // set NRFD and NDAC input, and DAV output
  DDRC = DDRC | B00001000;
  DDRC = DDRC & B11111001;
  

  
  while(true){if(timeout == true){break;};}
  
  // wait until (LOW == NDAC)
  while (B11111111 == (PINC | B11111101)) { if(timeout){break;}; } 
  
  // wait until (HIGH == NRFD)
  while (B00000000 == (PINC & B00000100)) { if(timeout){break;}; }
  
    // output data to DIO
  set_dio(data);

  // validate data
  PORTC = PORTC & B11110111;  //set DAV LOW
  
  // wait until (HIGH == NDAC)
  while (B00000000 == (PINC & B00000010)) { if(timeout){break;}; }
  
  // wait until (HIGH == NRFD)
  while (B11111111 == (PINC | B11111011)) { if(timeout){break;}; }
  
  PORTC = PORTC | B00001000;  // set DAV HIGH
 // set_dio(0); 
 
  TCNT1 = timer1_counter;   // preload timer

  return;
}

boolean gpibRead(byte *data) {
  
  boolean ret = false;
    
  // prepare to listen
  DDRC = DDRC | B00000100;
  PORTC = PORTC | B00000100;
    
  // wait until (LOW == DAV)
  DDRC = DDRC & B11110111;
  while (B00001000 == (PINC & B00001000)) { if(timeout){break;}; }
  
  // Ready for data
  PORTC = PORTC & B11111011;
    
  // read from DIO
  *data = get_dio();
    
  // check EOI
  DDRC = DDRC & B11101111;
  if (B00000000 == (PINC & B00010000)) {
    ret = true;
  } else {
    ret = false;
  }
  
  // data accepted
  DDRC = DDRC | B00000010;
  PORTC = PORTC | B00000010;
    
  // wait until invalid data
  while (B00000000 == (PINC & B00001000)) { if(timeout){break;}; }
  PORTC = PORTC & B11111101;
  
  TCNT1 = timer1_counter;   // preload timer
  
  return ret; // return true when EOI==LOW
}

byte get_dio() {
  byte x = 0;
  byte y = 0;
  byte z = 0;
  char a;
  // Set data pins to input mode
  DDRD = DDRD & B00000011;
  DDRB = DDRB & B11111100;
  
  //move data from ports to returned byte
  y = PINB << 6;
  z = PIND >> 2;
  x = y | z;
  x = ~x;
  
  return x;
}

void set_dio(byte x) {
  
  byte y = B00000000;
  byte z = B00000000;
  char a;
  // SET DIO 1-8 OUTPUT
  DDRD = DDRD | B11111100;
  DDRB = DDRB | B00000011;
  
  PORTB = B00000000;  
  PORTD = B00000000;
  x = ~x;
  y = x & B11000000;
  y = y >> 6;
  y = y & B00000011;
  PORTB = PORTB | y;
  z = x << 2;
  z = z & B11111100;
  PORTD = PORTD | z;
  
  wordsent++;
  
}

ISR(TIMER1_OVF_vect)        // interrupt service routine 
{
  TCNT1 = timer1_counter;   // preload timer
  timeout = true;
  return;
}
    *com = 0;

Why not use the more conventional notation:

com[0] = 0;

?

        *(com + p) = c; *(com + p + 1) = 0;

Also known as

com[p] = c;
com[p+1] = '\0';
boolean timeout = false;
...

ISR(TIMER1_OVF_vect)        // interrupt service routine 
{
  TCNT1 = timer1_counter;   // preload timer
  timeout = true;
  return;
}

Variables modified in an ISR should be declared volatile.

int timer1_counter;

...
  // Set timer1_counter to the correct value for our interrupt interval
  timer1_counter = 65536;  // preload timer 65536-16MHz/256/2Hz ---> timeout = 0.5s
...
  TCNT1 = timer1_counter;  // preload timer

I seriously don't know what you are doing here. The timer has just overflowed so you are setting it to ... what? Zero? Why bother? And why use 65536? You may as well put zero there.

Variables modified in an ISR should be declared volatile.

Thanks, I changed the variable to volatile and it works perfectly now!

I seriously don't know what you are doing here. The timer has just overflowed so you are setting it to ... what? Zero? Why bother? And why use 65536? You may as well put zero there.

I also changed that and it works.

Why not use the more conventional notation:

I am used to this notation and i makes it more readable for me, but thanks for the advice. I might change it for the open source version.

PS: Nick your tutorial is extremely useful! Thanks :smiley: