Probleme mit STM32-Interrupt-Priorität (Präemption).

Ich habe ein weiteres Problem ( Hochauflösender Systemtimer in STM32 ), das ich (meistens) zu diesem Problem zurückverfolgt habe, und habe hier einen Testfall für den einfachsten STM32-Prozessor erstellt, den ich finden konnte (auf dem STM32VLDISCOVERY-Board).

Das Problem ist, dass ich einen Interrupt mit höherer Priorität nicht dazu bringen kann, einen Interrupt mit niedrigerer Priorität zu unterbrechen.

Im Beispiel wird LED1 langsam durch den SysTick-Interrupt geblinkt, LED2 wird durch die Hauptschleife geblinkt.

Erwartetes Ergebnis

Wenn BTN1 gedrückt wird, wird der EXTI0-Interrupt aufgerufen, LED2 blinkt schnell, bis der SysTick-Interrupt mit höherer Priorität ausgelöst wird, und wird dann beendet. LED1 blinkt weiter wie zuvor.

Tatsächliches Ergebnis

Wenn BTN1 gedrückt wird, wird der EXTI0-Interrupt aufgerufen, LED2 blinkt schnell. Der SysTick-Interrupt mit höherer Priorität wird nie ausgelöst, LED1 blinkt nie und die LED2 blinkt weiterhin schnell.

Irgendwelche Ideen? Ist Interrupt Preemption etwas, das irgendwie eingeschaltet werden muss?

#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();
  }
}
STM32 ist nicht spezifisch genug. Es ist ein STM32F100 mit einem ARM Cortex M3-Kern. SysTick- und Interrupt-Prioritäten werden im Kern gehandhabt. Ob Vorkauf möglich ist, hängt auch davon ab, wie die Prioritätsgruppen eingerichtet sind.
Um fair zu sein, passiert dies bei einem STM32F100, F103 und dem F407 (und wahrscheinlich mehr, aber ich habe es nicht getestet). Ich denke, dieses spezielle Problem ist bei allen ziemlich Standard. Siehe meine Antwort unten - ich kann es nicht für einen weiteren Tag akzeptieren, aber das ist das Problem.

Antworten (1)

Ich habe gerade die Antwort von einem sehr hilfreichen Poster im STM32-Forum gefunden

Folgendes ist nicht korrekt. SysTick ist ein 'System Handler', und als solcher wird die Priorität überhaupt nicht auf diese Weise festgelegt:

  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);

Es ist eigentlich eingestellt mit:

  NVIC_SetPriority(SysTick_IRQn, 0);

Das Aufrufen dieses Codes löst das Problem stattdessen!

Hatte genau das gleiche Problem. Verwendung von NVIC_SetPriority (SysTick_IRQn, 0); hat das Problem bei mir nicht ganz gelöst. Es stellte sich heraus, dass ich zwar die Preempt/Sub-Prioritäten für meine anderen Interrupts konfiguriert hatte, es sich aber als wichtig herausstellte, NVIC_PriorityGroupConfig(...);