1
\$\begingroup\$

I'm using an STM32F4 Discovery board with ST's standard peripheral library (SPL). I have a situation with a circular buffer: timer interrupt is polling buttons and filling a circular buffer every millisecond if a button is pressed, with an index of that button. The main loop then takes it out of the circular buffer and executes the appropriate command. Both of these actions require multiple steps (checking and changing indices to circular buffer, ...).

When this is happening in the main loop, the timer interrupt has to be disabled for that short while (so that the indices don't get messed up), but I don't want to disable all interrupts just for that. Also, it is preferable for an interrupt to still be serviced if it happened while it was disabled.

I tried to do this by disabling the timer interrupt for that specific timer (TIM6 in my case) in the NVIC (but left it enabled on the timer itself). But then I found out that there is no way for me to check if interrupts were disabled in the first place - before disabling them (I can't enable interrupts again if they weren't enabled before, as it can mess things up).

So my questions are:

  • How do I check if a specific peripheral interrupt is enabled in the NVIC? (There are only EnableIRQ and DisableIRQ functions.)

    I tried checking value at

    NVIC->ICER[((uint32_t)(IRQn) >> 5)];

    and

    NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5];

    but they come out 0 even if the interrupt is enabled.

  • Will the interrupt still be served (if it occurred when it was disabled on NVIC side only) when enabled again?

\$\endgroup\$
  • \$\begingroup\$ According to the ref manual, reading NVIC->ISER should give you the current enable/disable state. Are you sure you're looking at the correct one? \$\endgroup\$ – brhans Sep 4 '16 at 3:23
3
\$\begingroup\$

Quick answer:

I would use the following (ugly) code:

if (NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5] &
   (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F))
{
    // It's enabled!
}

Explanation:

The NVIC_ISERx registers are dual-purpose. If you write a 1 to a specific bit it will enable the interrupt. If you read a specific bit it will tell you if the interrupt is enabled:

enter image description here

You are using the SPL and so it is handling the mapping of interrupt sources to ISER registers and bit locations.

In the core_cm4.h file, version 3.00, this is the NVIC_EnableIRQ() function:

__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
    /*  NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));  enable interrupt */
    NVIC->ISER[(uint32_t)((int32_t)IRQn) >> 5] = (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); /* enable interrupt */
}

It's interesting that they commented out the first line (which was identical to the same function in core_cm3.h) and left it there; I'm guessing it was a bugfix and they forgot to remove the incorrect code. I got lost by all the typecasts, but I expect they are necessary.

My answer above is modeled after this NVIC_EnableIRQ() function.


As far as system behavior, the following is taken from ST's PM0056 document (which is for M3, not M4, but the behavior is similar):

If a pending interrupt is enabled, the NVIC activates the interrupt based on its priority. If an interrupt is not enabled, asserting its interrupt signal changes the interrupt state to pending, but the NVIC never activates the interrupt, regardless of its priority.

If the "pending" flag gets set then the interrupt will be served as soon as you re-enable the interrupt.

\$\endgroup\$
  • \$\begingroup\$ Thank you, looks like I didn't read the register correctly. I looked at the enableIRQ function and thought only the part before = would suffice. I got a bit confused. I tested your solution and it works, returns 0 if disabled and 8388608 if enabled for TIM7 (random timer selected for testing). \$\endgroup\$ – Terraviper-5 Sep 4 '16 at 15:07
  • \$\begingroup\$ @Terraviper-5 Glad it worked! That value represents bit23 being set. If you use the "if" statement as I typed it, you won't need to keep track of the register value, or change anything if you decide to change timers. Good luck! \$\endgroup\$ – bitsmack Sep 4 '16 at 16:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.