¿Cómo interrumpo un ISR con un ISR de mayor prioridad en un STM32F105?

5

Tengo dos fuentes de interrupción externas que entran en un STM32F105. Quiero que uno de ellos (llámelo "IRQHigh") para adelantarse al otro ("IRQLow"). Actualmente, si IRQHigh se activa durante el IRQLow ISR, el flujo del programa espera hasta que borre el bit IRQLow ITPending antes de que se ramifique en el IRQHigh ISR.

El STM32F105 es un microcontrolador basado en Cortex-M3. Soporta interrupciones anidadas. Mi solicitud está escrita en C, usando GCC (arm-none-eabi-gcc) en Eclipse, con la biblioteca de periféricos estándar STM32F1.

Creo que tengo las prioridades configuradas correctamente, pero me falta algo.

Aquí está el código de inicialización correspondiente. He eliminado los comandos de reloj de AFB, la configuración de GPIO, etc., ya que cada subsistema parece funcionar bien por sí mismo:

#define IRQHIGH_EXTI_PORT  GPIO_PortSourceGPIOA
#define IRQHIGH_EXTI_PIN   GPIO_PinSource3
#define IRQHIGH_EXTI_LINE  EXTI_Line3
#define IRQHIGH_EXTI_IRQn  EXTI3_IRQn

#define IRQLOW_EXTI_PORT   GPIO_PortSourceGPIOC
#define IRQLOW_EXTI_PIN    GPIO_PinSource11
#define IRQLOW_EXTI_LINE   EXTI_Line11
#define IRQLOW_EXTI_IRQn   EXTI15_10_IRQn

NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;

// Sixteen levels of pre-emption priority, no subpriorities
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

// IRQHigh

    // Connect EXTI Line to GPIO Pin
    GPIO_EXTILineConfig(IRQHIGH_EXTI_PORT, IRQHIGH_EXTI_PIN);

    // Configure EXTI line
    EXTI_InitStructure.EXTI_Line = IRQHIGH_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // Configure and enable EXTI Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = IRQHIGH_EXTI_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

// IRQLow

    // Connect EXTI Line to GPIO Pin
    GPIO_EXTILineConfig(IRQLOW_EXTI_PORT, IRQLOW_EXTI_PIN);

    // Configure EXTI line
    EXTI_InitStructure.EXTI_Line = IRQLOW_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // Configure, but do not enable, EXTI Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = IRQLOW_EXTI_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
    NVIC_Init(&NVIC_InitStructure);

Los controladores de IRQ se configuran como tal:

void EXTI3_IRQHandler(void)
{
    IRQHigh();
    EXTI_ClearITPendingBit(IRQHIGH_EXTI_LINE);
}

void EXTI15_10_IRQHandler(void)
{
    if (EXTI_GetITStatus(IRQLOW_EXTI_LINE) == SET)
    {
        if (IRQLow()) // This returns a non-zero value if an overflow happened
        {
            CleanUpOverflow();
        }

        // Clear interrupt bit.
        EXTI_ClearITPendingBit(IRQLOW_EXTI_LINE);
    }
    else // unknown EXTI source
    {
        ErrorHandler(ERR_UNKNOWN_EXTI15_10_IRQ); // This never happens
    }
}

Algunas cosas importantes:

  1. IRQHigh () e IRQLow () toman un tiempo significativo para completar (por eso quiero que uno interrumpa al otro)

  2. IRQLow no está habilitado inicialmente, pero está habilitado en la línea con NVIC_EnableIRQ(IRQLOW_EXTI_IRQn);

  3. Dentro de EXTI15_10_IRQHandler (), obtengo un valor de retorno de IRQLow ().

  4. He declarado las funciones xxx_IRQHandler () con y sin __attribute__ ((interrupt ("IRQ"))) . Entiendo que este atributo no es necesario con Cortex-M3, pero lo intenté de todos modos (y obtuve los mismos resultados).

¿Qué estoy haciendo mal?

Actualización: con la ayuda de un comentario de @ Jeroen3, descubrí que IRQLow está interrumpiendo IRQHigh. Ahora necesito averiguar por qué ...

    
pregunta bitsmack

1 respuesta

5

Las prioridades no se están inicializando correctamente.

El código en la pregunta inicializa el NVIC así:

// IRQHigh, enabled immediately
NVIC_InitStructure.NVIC_IRQChannel = IRQHIGH_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

// IRQLow, to be enabled later:
NVIC_InitStructure.NVIC_IRQChannel = IRQLOW_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);

Luego, más adelante, IRQLow se habilita explícitamente con NVIC_EnableIRQ() .

El problema es que la función NVIC_Init() (de la SPL) en realidad no inicializa nada (!) si IRQChannelCmd = DISABLE . Simplemente establece el registro ICER para deshabilitar esa interrupción.

Esto me parece un error, pero que así sea. Ahora necesito ir y comprobar las otras funciones xxx_Init() en el SPL y ver si algo más podría morderme más tarde :)

Hay algunas soluciones. El que prefiero es dejar de lado las cinco líneas de la secuencia de inicio de IRQLow y reemplazarlas por esta:

NVIC_SetPriority(IRQLOW_EXTI_IRQn, 5);

Luego, cuando sea el momento, NVIC_EnableIRQ() se puede usar según lo previsto.

Tenga en cuenta que esto funciona porque el NVIC está configurado con NVIC_PriorityGroup_4 (sin subprioridades). Las diferentes configuraciones de PriorityGroup requerirán que también configure la subprioridad.

    
respondido por el bitsmack

Lea otras preguntas en las etiquetas