Tengo otro problema ( Temporizador de sistema de alta resolución en STM32 ) que he rastreado (en su mayor parte) 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 consigo que una interrupción de mayor prioridad interrumpa a otra de menor prioridad.
En el ejemplo, el LED1 parpadea lentamente por la interrupción SysTick, el LED2 parpadea por el bucle principal.
Resultado esperado
Cuando se pulsa BTN1, se llama a la interrupción EXTI0, que hace parpadear rápidamente el LED2 hasta que se dispara la interrupción SysTick de mayor prioridad, y luego sale. El LED1 sigue parpadeando como antes.
Resultado real
Cuando se pulsa BTN1, se llama a la interrupción EXTI0, que hace parpadear rápidamente el LED2. La interrupción SysTick de mayor prioridad nunca se dispara, el LED1 nunca parpadea y el LED2 sigue parpadeando rápidamente.
¿Alguna idea? ¿Hay que activar de alguna manera la interrupción anticipada?
#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();
}
}