I have another problem (High resolution system timer in STM32) which I have tracked down (mostly) to this issue, and have created a test case here for the simplest STM32 processor I could find (on the STM32VLDISCOVERY board).
The problem is that I cannot get a higher priority interrupt to interrupt a lower priority one.
In the example, LED1 is flashed slowly by the SysTick interrupt, 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. 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.
Any ideas? Is interrupt preemption something that has to be turned on somehow?
#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 quickly
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();
}
}
-
\$\begingroup\$ STM32 is not specific enough. It's an STM32F100 which has an ARM Cortex M3 core. SysTick and interrupt priorities are handled in the core. Whether preemption is possible also depends on how the priority groups are set up. \$\endgroup\$starblue– starblue2013年07月18日 15:24:57 +00:00Commented Jul 18, 2013 at 15:24
-
\$\begingroup\$ To be fair this happens on an STM32F100, F103, and the F407 (and probably more but I haven't tested). I think this particular issue is pretty standard across all of them. See my answer below though - I can't accept it for another day, but that is what the problem is. \$\endgroup\$Gordon Williams– Gordon Williams2013年07月19日 15:39:48 +00:00Commented Jul 19, 2013 at 15:39
1 Answer 1
I just found the answer from a very helpful poster on the STM32 forum
The following isn't correct. SysTick is a 'System Handler', and as such the priority isn't set in this way at all:
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);
It's actually set with:
NVIC_SetPriority(SysTick_IRQn, 0);
Calling that code instead solves the problem!
-
4\$\begingroup\$ Had the exact same problem. Using NVIC_SetPriority(SysTick_IRQn, 0); did not solve the problem entirely for me. It turns out, that while i had configured the preempt/sub priorities for my other interrupts, it turned out to be important to call NVIC_PriorityGroupConfig(...); \$\endgroup\$Zuu– Zuu2013年07月27日 14:44:13 +00:00Commented Jul 27, 2013 at 14:44