Timer inside an ISR?

I understand that ISR (Interrupt Service Routine) must be kept as short as possible, but in my particular project most of the action happens as long as the INT0 pin (D2) is LOW, so I need to run a timer inside the
ISR that is called to perform some action if the time of activity (active LOW) is greater than certain amount of time, milis(), delay() and some other functions do not work (this is mentioned quite clear) so what can be used inside an ISR to measure time?

Thanks

millis() will still return a number, albeit that timer is suspended during the ISR... so you could timestamp an interrupt event... then process when the program resumes.

volatile unsigned long myIsrTimeStamp;
volatile boolean myFlag;

void myISR()
{
  myFlag = true;
  myIsrTimeStamp = millis();
}

void setup()
{
  
}

void loop()
{
  
}

How long an interval did you need to measure? If it's more then a few hundred microseconds (a fraction of a millisecond) then you should NOT do it in the ISR.

Can't you just test Pin 2 in loop() and start a timer when it goes LOW?

You may not be approaching the problem optimally. It's hard to know without seeing your code. But consider that possibility first.

To answer your question directly, you can use one of the timers. It may be simplest to read timer0 (e.g. uint8_t count4us = TCNT0) since the system sets it up to increment every 4us. If that's not sufficient resolution than program one of the other timers.

Define "certain amount of time"

... so I need to run a timer inside the ISR that is called to perform some action ...

No, you don't. The ISR can initiate the action, and initiate the timing.

If you use a CHANGE type ISR then you get another interrupt when the pin goes high again.

Use an interrupt to detect when the interrupt signal goes low. Remember the time. Then use another interrupt to detect when it goes high again.

Following one of the advices here, I changed the code so the ISR ("rising" INT0 for pin D2 on the 2560) sets to HIGH another pin (D25) and starts a timer that will set to LOW D25 after certain amount of time.

For example:
void setup(){

** set some variables
attachInterrupt(0,ISR0,RISING) // Run routine ISR0 when pin D2 goes high.

}

//
void loop(){

** do stuff

}

void ISR0(){
PORTA = B00001000; // Turn LED on port D25 on.
Alarm.timerOnce(60, ptt_off); // Initialize the 60 seconds timer, once due run ptt_off.
}
//
//
void ptt_off(){

PORTA = B00001000; // Turn LED on port D25 off

}

//

So when pin D2 (INT0) goes from LOW to HIGH it does turn on the LED, and it is supposed to start the 60 secs timer, but the LED never goes off so the timer never kicks in.

This is confusing:
PORTA = B00001000; // Turn LED on port D25 on.
then
PORTA = B00001000; // Turn LED on port D25 off

What's wrong with

void setup()
{
attachInterrupt(0,ISR0,RISING); // Run routine ISR0 when pin D2 goes high.
}

volatile unsigned long startedAt=0;
void loop()
{
if( (startedAt) && (micros()-startedAt ) >60000 )
  {
   digitalWrite(52,LOW);
   startedAt=0;
  }

//Do other loop type stuff

}

void ISR0()
{
digitalWrite(52,HIGH);
  startedAt=micros();
}
This is confusing:
PORTA = B00001000; // Turn LED on port D25 on.  
then
PORTA = B00001000; // Turn LED on port D25 off

Yes, if this was used instead it would toggle the output bit:

PINA = B00001000; // toggle the IO pin

or be more explicit about it:

PORTA = PORTA | 0b00001000; // set bit3 high, rest untouched

PORTA = PORTA & 0b11110111; // clear bit 3 low, rest untouched

CrossRoads:
PINA = B00001000; // toggle the IO pin

What is PINA?

PINA is the "reading" port. PORTA is the "writing" port.

If you write to the reading port any one-bits toggle the corresponding pin in the writing port.

Cool! I didn't know that. I haven't had a chance to read all 450+ pages of the datasheet yet. :slight_smile:

Hopefully this can be a litttle bit more clear:

There are two radios, one only used for receive and the other only for transmit (a repeater), whenever the RX radio receives a signal it toggles a pin to high (rising), this signal should tell the controller (or Arduino) to send a HIGH to D25 which activates the TX radio.

So simultaneously as long at the RX is active, the TX is also active or in other words the RX drives the TX.

But if there is a long receive period, the TX also will be transmitting for that same long period and eventually the TX radio can get so hot that it can be damaged, that's why a timer is needed to shutdown the TX (pin D25) once the Time Out Timer (say 3 minutes of continuos transmission) is reached even if the RX radio still active.

On pin D2 (INT0) I connected the RX signal input which is supposed to trigger a timer (for testing purposes I set it up to 60 seconds with the Alarm.timerOnce function) and also activate the TX radio. So the Interrupt is served and the loop routine resumes, BUT the timer has been set (supposedly) so while the RX signal is HIGH (on D2) the TX radio is active (HIGH on D25), since the ISR only get active on RISING, then once the ISR is done with those two task (start the timer and set D25 to HIGH) then the loop routine can test D2 to see if it stills HIGH, if so then it will remain HIGH(or supposed to) until the timer is reached and ptt_off function toggles D25 to LOW which means that the Time Out Timer (or maximun time for transmission) has ben reached and the TX radio is shutdown.

That is why I need to start some kind of timer inside ISR0 once D2 RISES and that the timer remains active after the ISR has been served so the loop routine can take care of checking if D2 still HIGH and let the timer expire or if the time out timer is not reached (short RX/TX) meaning D2 is LOW then it wont matter if the ptt_off kicks in since we want the radio to be OFF while D2 is LOW.

Thanks all in advance for your great advices.