cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Interrupt priorities and preemption

gw
Associate II
Posted on July 18, 2013 at 15:47

Hi,

I have a problem where I cannot get a higher priority interrupt to interrupt a lower priority one. My understanding is that this should 'just work' so I'd really appreciate your input on this...

I've created a basic example which is designed to run on the STM32VLDISCOVERY board, but I've had the same issue with the F4 (and I imagine I would on other chips too)

In the example, LED1 is flashed slowly by the SysTick interrupt, and LED2 is flashed by the main loop.

Expected outcome

When BTN1 is pressed, the EXTI0 interrupt is called, it flashes LED2 quickly until the higher priority SysTick interrupt is fired, and then it exits. The LED1 keeps on flashing as before.

Actual outcome

When BTN1 is pressed, the EXTI0 interrupt is called, it flashes LED2 quickly. The higher priority SysTick interrupt is never fired, LED1 never flashes and the LED2 continues to blink quickly.

#include ''stm32f10x.h''

typedef

char

bool

;

volatile

bool

toggle;

void

delay(

void

) {

volatile

int

i = 100000;

while

(i-- > 0) {

}

}

void

delaySlow(

void

) {

volatile

int

i = 1000000;

while

(i-- > 0) {

}

}

// Toggle LED1 on SysTick

void

SysTick_Handler(

void

) {

if

(toggle = !toggle)

GPIO_SetBits(GPIOC, GPIO_Pin_8);

else

GPIO_ResetBits(GPIOC, GPIO_Pin_8);

}

// On EXTI IRQ, flash LED2 quickly, and wait for a SysTick

void

EXTI0_IRQHandler(

void

) {

bool

lastToggle = toggle;

GPIO_SetBits(GPIOC, GPIO_Pin_9);

while

(lastToggle==toggle) {

// wait for systick

// Flash LED2 slowly

GPIO_SetBits(GPIOC, GPIO_Pin_9);

delay();

GPIO_ResetBits(GPIOC, GPIO_Pin_9);

delay();

}

GPIO_ResetBits(GPIOC, GPIO_Pin_9);

EXTI_ClearITPendingBit(EXTI_Line0);

}

int

main(

void

){

GPIO_InitTypeDef GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |

RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |

RCC_APB2Periph_GPIOE, ENABLE);

// set preemption

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_Init(GPIOD, &GPIO_InitStructure);

GPIO_Init(GPIOE, &GPIO_InitStructure);

// button

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// leds

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC, &GPIO_InitStructure);

// systick

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

SysTick_Config(0xFFFFFF);

// 24 bit

NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

// Highest priority

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

// exti 0

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;

// Lowest priority

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

NVIC_Init(&NVIC_InitStructure);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

EXTI_InitTypeDef s;

EXTI_StructInit(&s);

s.EXTI_Line = EXTI_Line0;

s.EXTI_Mode = EXTI_Mode_Interrupt;

s.EXTI_Trigger = EXTI_Trigger_Rising;

s.EXTI_LineCmd = ENABLE;

EXTI_Init(&s);

while

(1)

{

// Flash LED2 slowly

GPIO_SetBits(GPIOC, GPIO_Pin_9);

delaySlow();

GPIO_ResetBits(GPIOC, GPIO_Pin_9);

delaySlow();

}

}

6 REPLIES 6
Posted on July 18, 2013 at 16:10

Observations :

There are only 4-bits to share between preemption/priority, you define how to split them. Setting F/F doesn't really seem valid.

SysTick is not an ''Interrupt'' in the sense you want it to be, it's a ''System Handler'', SysTick_IRQn will be negative, and you don't use NVIC_Init() to set it up.

On the F2/F4 you'd use

  NVIC_SetPriority(SysTick_IRQn, SysTickPriority);

It's also critical to do this AFTER SysTick_Config(), as this messes with the priority.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
gw
Associate II
Posted on July 18, 2013 at 16:49

Hi Clive,

Thanks, that's perfect! Using NVIC_SetPriority solved it!

I wasn't actually aware that SysTick was that special - I checked the docs to make sure I could set priority, but I should have looked a bit more closely!

It's crazy really as NVIC_Init does the same thing (ish) if the IRQn>=0. It has all the usual assert_params in, but it DOESN'T assert that it's been given the right IRQ. Ahh well.

I guess it should have thrown up a signed to unsigned conversion warning but I must have missed that.

(As for the two Fs - I was just playing safe. I wanted to be absolutely sure it was the lowest priority!)

Thanks again,

- Gordon
Posted on July 18, 2013 at 17:13

It's one of those Cortex-Mx traps, the demarcation moved a little with the introduction of the CMSIS libraries. The original STM32F1xx libraries had ST specific NVIC and SYSTICK files.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
schperplata
Associate III
Posted on May 11, 2015 at 11:16

Hello,

I've very similar problem, but without any good results on STM32L100RCT6. I want TIM3 to be higher priority interrupt than USART1. I've set priority group to 4 (NVIC_PriorityGroup_4) and configure priority of timer and usart like this:


void
timer3_init()

{

/* other code */


NVIC_SetPriority(TIM3_IRQn, 0);

NVIC_EnableIRQ (TIM3_IRQn);

timer3_int.NVIC_IRQChannel = TIM3_IRQn;

timer3_int.NVIC_IRQChannelPreemptionPriority = 0; 

timer3_int.NVIC_IRQChannelSubPriority = 0; 

timer3_int.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&timer3_int);


/* other code */

}


void
init_usart_RXint()

{

/* other code */


NVIC_SetPriority(USARTx_IRQn, 4);

NVIC_EnableIRQ(USARTx_IRQn); 

NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);


/* other code */

}


void
main()

{

/* i configured NVIC priority group in main and then call TIM and USART functions */

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

timer3_init();

init_usart_RXint();


/* other code */

}

I'm using: - KEIL MDK-Middleware 5.1.6, - CMSIS: 3.4 - STM32L1xx_DFP 1.0.2 -STM32L1xx Standard Peripherals Library Drivers V1.3.1 Can you see where I'm making mistake? I do get interrupt from both sources(TIM3 and USART), but TIM3 doesn't nest into USART interrupt like it should. [I've got USART interrupt handler, where I call function that waits for TIM3 interrupt, but this interrupt never happens so uC ir stuck in that while loop.] Any help would be appreciated. Thank you!
qwer.asdf
Senior
Posted on May 11, 2015 at 12:25

You selected NVIC_PriorityGroup_4 which does not leave any space for preemption (all 4 bits go to sub-priority). Change the group to NVIC_PriorityGroup_2 which will leave you 2 bits (values 0-3) for preemption and another 2 bits for subpriorities for each preemption priority. And change the priority values accordingly.

schperplata
Associate III
Posted on May 11, 2015 at 23:43

This is copied from misc.c file:

/**
* @brief Configures the priority grouping: preemption priority and subpriority.
* @param NVIC_PriorityGroup: specifies the priority grouping bits length. 
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for preemption priority
* 4 bits for subpriority.
* @note When NVIC_PriorityGroup_0 is selected, it will no be any nested 
* interrupt. This interrupts priority is managed only with subpriority. 
* @arg NVIC_PriorityGroup_1: 1 bits for preemption priority.
* 3 bits for subpriority.
* @arg NVIC_PriorityGroup_2: 2 bits for preemption priority.
* 2 bits for subpriority.
* @arg NVIC_PriorityGroup_3: 3 bits for preemption priority.
* 1 bits for subpriority.
* @arg NVIC_PriorityGroup_4: 4 bits for preemption priority.
* 0 bits for subpriority.
* @retval None
*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)

Anyway, just couple of minutes ago I figured it out - another interrupt priority was missing - I was so focused on these two interrupts, that I just didn't see the third oneonce these two were set correctly. In order to control priorities of all interrupts, systick must also be configured withNVIC_SetPriority(). I've had small delay at the and of the function and USART interrupt was higher priority than systick. Thanks for quick response anyway.