8 years, 10 months ago.

Saving interrupt state

Is there a way to atomically disable interrupts and save the state of the interrupt enable bit? Or is there a different framework provided for managing the interrupts?

I don't think that using "disable_irq()" and "enable_irq()" is very safe method for disabling and re-enabling interrupts.

Question relating to:

Can you elaborate on "is not very safe method"?

posted by Martin Kojtal 10 Jun 2015

3 Answers

8 years, 10 months ago.

disable_irq() can (sometimes) return if currently the interrupts were enabled/disabled, so then you know if you should re-enable them. See: http://www.keil.com/support/man/docs/armccref/armccref_CJAFBCBB.htm

Now I don't know for which architectures it should exactly work, and also not if it works under all compilers. (Probably not). Quick check with online compiler shows it compiles for different targets, but didn't check if it actually works.

8 years, 10 months ago.

disable/enable_irq functions are part of cmsis, should work for any compiler. The thing is that disable/enable irq are not enough, as they dont save/restore state of interrupt - is this Kevin what y ou meant in your question? I haven't located a function within cmsis headers, might be there somewhere, something like:

// pseudo code
uint32_t disableIRQ() {
  irq_state = get primask;
  __disable_irq();
  return irq_state;
}

void restoreIRQ(uint32_t irq_state)
{
  set_primask(irq_state);
}

There is a version of disable irq which returns the current state, that's the one I showed. I just don't know if that works for all compilers and all targets.

posted by Erik - 10 Jun 2015

It should.

I haven't checked your link :-)

posted by Martin Kojtal 10 Jun 2015

If you look in "core_cmFunc.h" and "core_caFunc.h", you can see the different implementations of "disable_irq()". The function doesn't return anything for the Cortex M devices. I think the implementation for the Cortex A devices will work, the operation is not atomic and could still be interrupted between the two instructions.

posted by Kevin Gillepsie 10 Jun 2015
8 years, 5 months ago.

uint32_t disableIRQ() {
 irq_state = get primask;
  __disable_irq();
 return irq_state;
}

This is an incorrect solution.

Hint: What happens if there is an interrupt between get_primask() and disable_irq(), and that interrupt changes primask?

This code would have to run in either the SVC_Handler or NMI_Handler to assure that no other interrupt could change the PRIMASK in between those two instructions.

It is unfortunate that ARM did not design 'CPSID I' so that the original value of PRIMASK was stored in the CCR carry bit (or create an atomic bit for just such occasions).

-

posted by Erik - 05 Nov 2015