Problemas de prioridad de interrupción (prioridad) de STM32

Tengo otro problema ( temporizador del sistema de alta resolución en STM32 ) que he rastreado (principalmente) hasta este problema, y ​​he creado un caso de prueba aquí para el procesador STM32 más simple que pude encontrar (en la placa STM32VLDISCOVERY).

El problema es que no puedo obtener una interrupción de mayor prioridad para interrumpir una de menor prioridad.

En el ejemplo, la interrupción SysTick parpadea lentamente el LED1, el bucle principal parpadea el LED2.

Gastos esperados

Cuando se presiona BTN1, se llama a la interrupción EXTI0, el LED2 parpadea rápidamente hasta que se dispara la interrupción SysTick de mayor prioridad y luego sale. El LED1 sigue parpadeando como antes.

resultado real

Cuando se presiona BTN1, se llama a la interrupción EXTI0, parpadea rápidamente el LED2. La interrupción SysTick de mayor prioridad nunca se dispara, el LED1 nunca parpadea y el LED2 continúa parpadeando rápidamente.

¿Algunas ideas? ¿Es la preferencia de interrupción algo que debe activarse de alguna manera?

#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 no es lo suficientemente específico. Es un STM32F100 que tiene un núcleo ARM Cortex M3. SysTick y las prioridades de interrupción se manejan en el núcleo. Si la preferencia es posible también depende de cómo se configuren los grupos prioritarios.
Para ser justos, esto sucede en un STM32F100, F103 y F407 (y probablemente más, pero no lo he probado). Creo que este problema en particular es bastante estándar en todos ellos. Sin embargo, vea mi respuesta a continuación: no puedo aceptarla para otro día, pero ese es el problema.

Respuestas (1)

Acabo de encontrar la respuesta en un póster muy útil en el foro STM32

Lo siguiente no es correcto. SysTick es un 'Controlador del sistema' y, como tal, la prioridad no se establece de esta manera en absoluto:

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

En realidad está configurado con:

  NVIC_SetPriority(SysTick_IRQn, 0);

¡Llamar a ese código resuelve el problema!

Tenía exactamente el mismo problema. Usando NVIC_SetPriority(SysTick_IRQn, 0); no resolvió el problema por completo para mí. Resulta que, si bien había configurado las prioridades prioritarias/secundarias para mis otras interrupciones, resultó ser importante llamar a NVIC_PriorityGroupConfig(...);