Electrical – STM32F103 – NVIC Confusion

armstm32stm32f10x

While reading the RM0008 reference manual I got confused about how to use the NVIC to configure interrupts. The manual basically redirects the reader to the PM0056 programming manual which, in my opinion, doesn't do a great job in explaining how to use the NVIC functions provided by CMSIS.

So, I'm trying to set up an interrupt for GPIOA pin 1 using EXTI Line 1 in a NucleoF103 board, and I want to setup priority and subpriority bits, but I'm not sure how to do that. The RM0008 manual states that the NVIC has 4 bits of interrupt priority.

CMSIS provides functions such as "NVIC_SetPriorityGrouping" and "NVIC_SetPriority" to choose priority and subpriority bits, but I can't seem to find a good explanation for what the arguments do in these functions.

It seems that the "NVIC_SetPriorityGrouping" changes some values in the AIRCR register, which does have some bits to configure number of priority and subpriority bits.

So, for instance, is this code correct for setting up and EXTI interrupt on Line 1?

#define RESET_WITH_MASK(reg,mask) reg &= ~(mask)
#define SET_WITH_MASK(reg,mask) reg |= (mask)

[...]

//Configure EXTI Line1 to not be masked
SET_WITH_MASK(EXTI->IMR,EXTI_IMR_MR1);

//Configure a rising edge to trigger an interrupt
SET_WITH_MASK(EXTI->RTSR,EXTI_RTSR_TR1);

//Configure EXTI Line1 multiplexer to listen to port A
SET_WITH_MASK(AFIO->EXTICR[0],AFIO_EXTICR1_EXTI1_PA);

//Choose type of priority bits: 3bits for priority, 1bit for subpriority
NVIC_SetPriorityGrouping(1);

//Set priority of EXTI Line1 to 0 (highest priority), subpriority to 1
NVIC_SetPriority(EXTI1_IRQn,0b0001);

//Enable EXTI Line 1 interrupt
NVIC_EnableIRQ(EXTI1_IRQn);

//Enable interrupts
__enable_irq();

Here I am assuming that the argument for the "NVIC_SetPriorityGrouping" chooses the number of subpriority bits, and that the "NVIC_SetPriority" takes the priority bits, the most significant being priority and least significant being subpriority.

Obviously pin 1 of GPIOA needs to be configured as an input for this to work, but aside from that, am I missing any configuration stuff? Also, is "__enable_irq()" truly necessary?

Any help would be appreciated as I was not able to find any good examples of this, and I'd like to avoid doing the configurations using all those shifts in the NVIC registers when CMSIS already provides functions for this.

Best Answer

The function NVIC_SetPriority(IRQn, priority) writes the priority to that field of the NVIC_IPRx register corresponding to the interrupt specified by the IRQn argument. It basically assigns the priority to the interrupt, as its name suggests. The priority is separated into group priority (upper bits) and sub-priority (lower bits).

The function NVIC_SetPriorityGrouping(priority_grouping) writes the value of its argument to the PRIGROUP field of the SCB_AIRCR register. This tells the NVIC how many bits of priority are the group priority and the sub-priority.

The descriptions of the SCB_AIRCR and NVIC_IPRx registers are in the Programming Manual.

The Programming Manual describes the priority grouping:

Only the group priority determines preemption of interrupt exceptions. When the processor is executing an interrupt exception handler, another interrupt with the same group priority as the interrupt being handled does not preempt the handler,

If multiple pending interrupts have the same group priority, the subpriority field determines the order in which they are processed. If multiple pending interrupts have the same group priority and subpriority, the interrupt with the lowest IRQ number is processed first.

I believe the argument NVIC_SetPriorityGrouping() has to have a value between 3 and 7; so 0b100 to config for 1 sub-priority bit. The rest looks okay.

You don't need the __enable_irq() unless there was a prior__disable_irq(). __enable_irq() clears the PRIMASK bit; its reset value is 0.