Three interrupts in the same sketck

Dear all,

I have a program with 3 interrupts.

ISR(TIMER1_COMPA_vect)
ISR(ADC_vect)
ISR (INT0_vect)

TIMER1_COMPA is configured as a 0.5s timer (aprox)
ADC_VECT is just here because I used ADCL and ADCH inside TIMER1.
INT0_vect it is a triggering and it fires at 1s

I supposed would not be a problem because INT0 will actuate as Master because it is interrupt number 2 ( Gammon Forum : Electronics : Microprocessors : Interrupts ) .

The program works fine with TIMER1 and ADC_VECT.....but it works continuosly and I want that INT0_VECT (a photosensor) would make the trigger to adquire the data.

When In insert INT0_VECT, it has an chaotic behaviour

Is it possible or the ATMega just can't handle the three interrupts working at the same time?

They are not one inside the other by the way.

Thanks in advance.

When In insert INT0_VECT, it has an chaotic behaviour

What is connected to INT0? How is it connected?

'At the same time' is a very movable feast.

If this is true to within a clock cycle of your processor you can buy 'priority encoders' whch sort this out...

but I suspect your software needs refining ...

regards

Allan

Thanks for the quick response's!

Before I conected the photosensor to the int0 pin I have tested with a little program that with or without light I have a 0 or 1 logic. I calculate a tension division for that purpose. During 30 minutes with a flashing light at 2 lighting per second no error ocurred.

And allanhurst yes, probably I'm doing it wrong but I don't get the point. I think the problem it is not in the interrupts, it is in loop.

I need to disable interrupts when I have to send a burst of data throw serial and it seems when I reactivate them sometimes never reactivate so the program doesn't work.

So I guess it is my sw problem and not a problem of the interrupts.

But. Is there any possibility I crush the arduino? Because it freezes after some seconds and I only ocuppied 55% of the mem....

Thanks!

To give more information, I receive strange characters via serial port before it freezes the arduino

I am not sure what are you trying to achieve but:
cli(); disables all interrupts
sei(); enables all unmasked interrupts
When entering interrupt routine interrupts are disabled (as if you called cli(); as the first command)
When leaving ISR unmasked interrupts are enabled (as if you called sei(); as last command)
Calling sei(); inside ISR is unwise unless you know what you re doing - the interrupt can trigger again and again and you may run out of RAM (entering ISR including pushing some registers to the Stack possibly corrupting data if RAM is low). I suspect it may be your problem.
If you don't call sei(); inside the ISR you cannot enter ANY ISR until you finish the current ISR being executed - so you cannot get result from ADC ISR inside TIMER ISR - do you know it?

madring:
To give more information, I receive strange characters via serial port before it freezes the arduino

That sounds like you are trying to print from inside an ISR. Don't.

Post your program so we can all see what you are talking about.

And when posting code please use the code button </>so your code looks like thisand is easy to copy to a text editor

...R

Is it possible or the ATMega just can't handle the three interrupts working at the same time?

ATmega can service all interrupts. I bet it is problem in your program.

  1. Keep your ISR as short as it is possible. Just to set a flag etc.
  2. Do things in the main program, not in ISR.
  3. Do not call functions in ISR which can depend on interrupt (like Serial.print()) because the MCU hangs or get slow down.
  4. ?

madring:
I supposed would not be a problem because INT0 will actuate as Master because it is interrupt number 2 ( Gammon Forum : Electronics : Microprocessors : Interrupts ) .

There is no multilevel priority in the 328 processor. Once an interrupt is being serviced, no other interrupts can interrupt it. Although I guess one can work around it if needed (never worked with interrupts on a 328). Only if two or more interrupt flags are set at the moment that the processor checks, the priority will determine which one will be serviced first.

With the timings that you mention (0.5 seconds and 1 second), do you really need interrupts? Can't you handle this in the loop(), possibly by using millis() for the timing?

Thanks a lot for the help!

Here you have part of the code. The rest is just configuration of timer and adc, but that works fine, I tested in other program without problem.

......
    EICRA |= (1 << ISC00);    // set INT0 to trigger on ANY logic change
    EIMSK |= (1 << INT0);     // Turns on INT0
      sei();
}

void loop() {                 
  if (i==500 ){ //if the array is filled, then send it
  cli(); //stop interrupts to send via serial
  for (i=0; i<500; i++){ 
    Serial.println(data[i]); 
  }
  }
  sei();  //activate interrupts                                       
}

ISR(TIMER1_COMPA_vect){//controls  when I take the sample.
  aval = ADCL;
  aval += ADCH<<8 ;
  data[i]=aval;
  i++;
}

ISR(ADC_vect) {
}

ISR (INT0_vect) { //when I receive a change in the state (light to dark or dark to light) activate
      i=0; //ok, you can start to fill the array.
 }

Thanks again!

I believe Serial.println depends on interrupts. When you disable them via cli() you run into troubles. The Serial buffer will overflow and you will get strange results.

This won't work

cli(); //stop interrupts to send via serial

because the Serial system needs to use interrupts.

If you need to stop your own interrupts (but why would you?) you need to do it specifically for each one.

...R

I need to disable interrupts when I have to send a burst of data throw serial

Serial.print() requires interrupts to function, and this is code disabling and reenabling interrupts is not right.

void loop() {                 
  if (i==500 ){ //if the array is filled, then send it
  cli(); //stop interrupts to send via serial
  for (i=0; i<500; i++){ 
    Serial.println(data[i]); 
  }
  }
  sei();  //activate interrupts                                       
}

Do you have i and data[] declared as volatile?

When i = 500 you need to make a protected copy of the data by disabling interrupts, transferring the data into another working array, and re- enabling interrupts to restart the data collection of another 500 values. Print or analyse the data in the working array while data is collected by interrupts in the background.

Also do you have variables used in ISRs declared as volatile?

I think the real problem is here:
The Compare Match interrupt will increment i over 500 and data will get out of the declared array and corrupt your data unless reset foom external interrupt come soon enough.

The Serial.print use interrupt surely, do not disable interrupts. Why you don't set some flag and read adc in loop and without cli/sei ?

auch! that hurts, I supposed that serial.println didnt use interrupts.

THe thing is that I need to collect a window of 500ms and send it throw serial to matlab before another window start. I have like 600ms to send all that data so during that time I dont need any new sample.

So the flow chart is

Trigger
adquire data
send data
wait until trigger

But if I didn't stop interrupts during the "send data" new data would come.

ANd if I put flags inside the interrupts, I didn't keep them short xD.....

hard decission

The program works fine with TIMER1 and ADC_VECT.....but it works continuosly and I want that INT0_VECT (a photosensor) would make the trigger to adquire the data.

When In insert INT0_VECT, it has an chaotic behaviour

If you're using photosensor with LM393 comparator, there's likely no feedback (hysteresis) in the design, so the digital signal is quite noisy and would create many, many false interrupts on each edge of the pulse. This could explain the chaotic behavior. The solution here was to add a capactior from D0 to GND on the sensor module.

You can leave all the interrupts alone, and stop Timer1 by writing the prescaler to 000 after you collect the 500 samples. Then the trigger can reset TCNT1 = 0 and start the timer running by writing the desired prescaler.

You ned to ged rid of the unchecked array index.

data[i]=ADCW;
i++;

will overflow from the array boundaries and get you into troubles! Quick fix is

if (i<500) i++;

To the rest, you can

  1. Disable Compare interrupt as suggested above (quickest way);
  2. Write your own blocking (not using interrupts) version of Serial.println (difficult but you will learn much)
  3. Don't care: Serial.println should send data faster than you acquire new data.

But beware - using Serial.println faster than the hardware send the data may cause some of the data lost when Serial buffer overflows. Try

for (int i =0; i<500; i++) Serial.println(i);

I guess you won't get all the numbers. Why do you want send data in bursts anyway?

I believe Serial.println depends on interrupts. When you disable them via cli() you run into troubles. The Serial buffer will overflow and you will get strange results.