Turn off interrupts during ISR, then keep them off once main code resumes?

Can this be done? I know that calling cli() inside an ISR won't do it, because upon exiting the ISR will renable interrupts. I'm interested in a way for an interrupt to turn off interrupts as it exits (or, so to speak, not turn them back on), and have them remain off in the main code until a certain amount of time (a relatively short time, so micros measurement can be used, which isn't interrupt based to my understanding) has elapsed.

I know that a ISR_NOBLOCK flag can be used in the ISR's "function" definition to let interrupts stay on throughout it, but is there a way to have an ISR enter and run normally, except not have it undo any cli() commands issued within it when it exits? I can use a micros timing copied to a variable during the ISR and some logic in the main loop of code to handle the renabling of interrupts at an appropriately later time.
Thanks

You can call cli(), sei(), noInterrupts() or interrupts() at any time in the main program.

millis() and most serial I/O functions will stop working if the interrupts are off.

1 Like

Really you don't need this on a most arduino boards, because all other interrupts will be postponed automatically while the running the ISR. It is a normal behaviour of the system.

You could have a flag so that you would still take the interrupt, but just skip over anything it would have done otherwise.

So normally, the flag allows the interrupt to do its thing, part of which is to set the flag so it won't do anything on subsequent invocations.

In the big code, reset your flag so once again the interrupt will do something once.

No need to mess things up turning off interrupts, as noted, it messes with stuff you don't even think about.

a7

Many newer microcontrollers support multiple interrupt priorities. Your ISR can still be preempted when an interrupt with higher priority fires.

You can not use micros() timing with interrupts off.

What you can do is disabling specific interrupts for some time.

State exactly what this application is. There is surely a better way of achieving what you want. Generally prolonging the suspension of interrupts after an interrupt has been serviced sounds odd. Maybe ignoring specific interrupts if some condition is not met would be a solution.

XY Problem?

My comment would be that it is absolutely possible to do what the OP asks, but I would never describe how, because it should NEVER necessary to do so. In 30+ years of doing embedded development, I have never once needed to do anything remotely like that. The fact the the OP thinks he needs to do this tells me his whole approach to his problem is wrong, and needs to be re-thought.

1 Like

ARM has NVIC, but perhaps that's not preemptive?

I had thought it could be a button push debouncing type problem where you could imagine a solution involving a prolonging of the interrupt suppression to prevent any following bounce. Of course the solution there is simply to ignore those interrupts for the next X ms.

Or you could disable that interrupt* within the ISR, then re-enable it later. That would prevent the bouncing from generating interrupts at all. I have a rotary encoder routine that switches the interrupt to the other line to prevent all those bounce interrupts.

Edit:

  • and clear the flag

Thanks, I can see how turning off the specific interrupt makes more sense than disabling entirely. That way I can have the interrupt trgger on the edge of an incoming communication signal (I've been setting up a protocol for a network of AVRs working together), and then not trigger again by any other events until a set amount of time has elapsed (ensuring if any one of them on the network were to go wrong and start spamming the bus with repeat messages others would be able to ignore some of the repeats and be able to keep doing individual tasks without being constantly interrupted).

You're over-thinking this. Just use a (volatile) flag within the ISR to tell it whether to do its thing or return immediately. Set / Reset that flag in both the ISR and the main code as necessary.

1 Like

Thanks for validating my idea.

I work to not use interrupts, but have and can. Little tricks that seem to make sense don't always work out like one would think.

a7

That's up to the programmer to decide, by default, they're not preemptive. The N in NVIC refers to nested interrupts, which involves the current ISR being preempted by a higher priority one. This is achieved by switching modes and enabling interrupts when entering an ISR.

How can I decide this - I don't see any registers controling this, for example, in STM32F401 mcu

which modes?

You can set the interrupt priority and priority grouping. See e.g. https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-entry-and-return?lang=en or section 2.3 of https://developer.arm.com/documentation/dui0553/b/?lang=en for more information.
The ST datasheets/reference manuals may not go into this topic into detail, because it's the same across all Cortex M4 microcontrollers.

The ARM processor modes.
It's been a while since I worked on this lower-level stuff, I was confusing Cortex M nested interrupts with Cortex A/R nested interrupts. The Cortex M has interrupt nesting enabled by default, so to use it, you only have to change the priorities, you don't have to manually re-enable interrupts or switch modes.
For Cortex A, the procedure is a bit more involved, see e.g. https://developer.arm.com/documentation/dui0471/m/handling-processor-exceptions/reentrant-interrupt-handlers.

Thank you!

I can confirm that this method is working for me:

ISR (PCINT0_vect ){
 //various things
if(certain condition during interrupt){
  PCICR &= 0b11111110;
}
//various things
TimeOfLastInterrupt=micros();
}

//then in the main loop

if(PCICR == 0){
    //Serial.println("Int dis");//Interrupt disabled
    //for debugging
  }else{
    //for debugging
  }
  if( ( (micros() - TimeOfLastInterrupt) > Period ) && (PCICR ==0)){ //Period us since last interupt and interrupt is disabled
    PCIFR  |= bit (PCIF0);   // clear any outstanding interrupts
    PCICR  |= bit (PCIE0);   // re-enable pin change interrupts for D8 to D13
    //Serial.println("Interrupt re-enabled");
  }


Oddly enough (PCICR & 0b00000001) ==0 wouldn't work in the main loop's if expressions, but as I'm not using the other two pin banks for change interrupts PCICR ==0 is good enough for my needs.