0
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ I see. So NVIC_SetPriorityGrouping() sets the PRIGROUP bits in the AIRCR register, according to this website: keil.com/pack/doc/cmsis/Core/html/group__NVIC__gr.html. So yeah, the values vary between 3 and 7 as per the PM0056 manual, but what values should I then put into NVIC_SetPriority()? According to "Cutting Through the Confusion with ARM Cortex-M Interrupt Priorities" in the ARMcommunity site, subpriority are the least significant, so with 1 subpriority bits, calling this function with 0b0001 would give me highest priority (first 000) and second highest subpriority (last 1)? \$\endgroup\$ – Chi Jan 18 '17 at 1:49
  • 1
    \$\begingroup\$ @Chi Yes, that's correct. Perhaps some confusion arises because although the M3 core supports 256 priority levels (8 bits worth), most chips don't support that many levels. The STM32F10x supports 16 levels, so the priority is specified by just four bits. But these four bits are left-aligned in the 8-bit NVIC_IPRx registers fields. This left-alignment is why the priority grouping ranges from 3 to 7, rather than 0 to 3. The NVIC_SetPriority() function does the required alignment shift, so using 0b0001 as the priority argument does give group priority 0, sub-priority 1. \$\endgroup\$ – user28910 Jan 18 '17 at 14:38

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.