6
\$\begingroup\$

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();
  }
}
\$\endgroup\$
  • \$\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 Jul 18 '13 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 Jul 19 '13 at 15:39
8
\$\begingroup\$

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!

\$\endgroup\$
  • 3
    \$\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 Jul 27 '13 at 14:44

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.