Disable interrupts to enter critical section on nRF5340

Hi!

I'm working on the firmware part that needs to perform operations on the same variables both inside GPIO IRQ and the software timer callback.
So, there is a need for a critical section to make sure they operate properly.

By looking through the documentation, I found that I can use "irq_lock()"/"irq_unlock()" to achieve this (software timer implementation also makes use of these under the hood), but I found that after calling irq_lock(), GPIO interrupts are not locked.

Diving deeper into the "lock()" implementation, I found the following:


So, BASEPRI register is set with the value 32 (_EXC_IRQ_DEFAULT_PRIO)

So, all priorities higher than 32 (numerically lower) can generate interrupts while the code is insiode this critical section.
According to the *.dts config, "NUM_IRQ_PRIO_BITS" is set to 3, so lowest IRQ priority possible should be 8.


With default configuration, the priority for the GPIO interrupts are 6 (got this value by calling "NVIC_GetPriority(GPIOTE0_IRQn").


Therefiore, it looks like "irq_lock()" does not disable any interrupts.
That is why I need to call something like "irq_disable(GPIOTE0_IRQn)" to explicitly disable GPIO interrupts for the time of processing.

Am I missing something here or is it correct behaviour for the "irq_lock()"?

Thanks,
Anton

  • Hi Anton,

    BASEPRI==0x20 should disable interrupts with priority 1-7 thus only leaving interrupts with priority 0 enabled (SVCs, zero latency interrupts).  This may seem confusing at first, but the register is 8-bit wide, and since this CPU only implements 3-bits, we need to left-shift the priority bits before writing to the basepri register.  

    1 << 5 = 0x20 # disable interrupt priority 1-7

    2 << 5  = 0x40 # disable interrupt priority 2-7

    3 << 5  = 0x60 # disable interrupt priority 3-7

    ...

    From ARM's documentation at https://developer.arm.com/documentation/100235/0004/the-cortex-m33-processor/programmer-s-model/core-registers#vox1485885594532__CRHJEW 

    I tried to test this with the peripheral_lbs sample in SDK v2.7.0 (without TF-M) but was unable to reproduce the issue. I added the code below before bt_enable() in main() and confirmed that I could not trigger the button interrut while the program was running in this loop.

    	unsigned int key;
    
    	key = irq_lock();
    	
    	// Wait for GPIOTE IRQ
    	while(1);
    
    	irq_unlock(key);
    

    Do you still read the BASEPRI value as 0x20 if you place a breakpoint in the GPIOTE ISR?

    Best regards,

    Vidar

  • Hi Vidar,

    Thanks for the quick response and an explanation.

    Yes, BASEPRI configuration is a bit confusing. I just missed the point with the bit shift.

    Just made a simpler test code and found that "irq_lock()" is enough to restrict GPIO IRQs.
    Looks like a context switch took place (that is why lock was released by the kernel as described here: Interrupt docs).

    Thanks,
    Anton

Related