This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

disable interrupts and enable interrupts if they where enabled

Hello,

I'm not sure if this was already asked before. I didn’t found a similar question, so here it is: When I have a function that manipulates a data structure to communicate with an interrupt service routine and if that manipulation can not be done atomically, an usual approach is to disable all interrupts, do the manipulation and enable all interrupts again (`__disable_irq(); manipulation(); __enable_irq() ).

The problem with this approach is that it would enable interrupts, if interrupts where already disabled. Is there a disable function, that returns the previous irq disable status?

bool was_enabled = __disable_irq();
manipulation();
if ( was_enabled )
    __enable_irq();

I don’t ask this in the context of a soft device. I’m aware that disabling interrupts is not reasonable, when using one of the soft devices.

Cheers, Torsten

  • You are using it wrong. The if statement should be

    if ( !was_enabled )
    

    infocenter.arm.com/.../index.jsp

    The __disable_irq gives you the value of PRIMASK prior to calling that function. If it returns 0, then it means that no interrupts were masked and this current call __disable_irq has set the mask disabling configurable interrupts.

    If it returns 1, it means that it was already masked before calling this __disable_irq and enabling interrupts is not done at current context.

  • I see that ARM documentation says that it returns value of PSR, that is incorrect or it does not make sense, because that is not single bit. It should be PRIMASK

  • You should be able to use __get_PRIMASK() and __set_PRIMASK() like so

    uint32_t old_primask = __get_PRIMASK();
    __disable_irq();
    manipulation();
    __set_PRIMASK( old_primask );
    

    This looks like it might have a race condition but doesn't. If interrupts were enabled and something interrupts you between the __get_PRIMASK() and the __disable_irq() and disables IRQs itself, it will restore them before it finishes so your 'old_primask' variable will still be valid.

  • There's more confusion than that. The __disable_irq() function which returns something is in the ARM toolchain (only I think). The CMSIS function which is in core_cmFunc.h declares it as returning void, and that's the one my compiler picks up at least and I'd think most others would if CMSIS is included.

  • Ups, my code was ment as pseudo code. I wasn't aware that there is a version of __disable_irq() that works like I would expect it. I was looking up the function in core_cm0.h and there it returns void.

1 2