STM32F7 se bloquea en la función de devolución de llamada de interrupción externa

7

estoy trabajando en un proyecto para conectar una cámara a una placa de descubrimiento STM32F7 mediante la interfaz DCMI. La parte de la cámara funciona bien, pero tengo un problema extraño con las interrupciones externas del botón de a bordo.

Habilito interrupciones externas para el botón mediante la función proporcionada en el paquete STM BSP:

BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);

La interrupción externa para este botón ahora está en GPIO_PIN_11. Esta interrupción es manejada por la función HAL_GPIO_EXTI_Callback que puedo implementar en mi archivo main.c.

Estoy utilizando las bibliotecas STM HAL / BSP.

La interrupción en la pulsación de un botón funciona y la función de devolución de llamada se ingresa correctamente, pero aquí es donde comienza el problema.

Esto es lo que quiero hacer al presionar un botón:

{
        if(capture_status == 0)
        {
            start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);//start continuous grabbing, if not already running
            if(suspended == 1)
            {
                Camera_Resume();//resume DCMI and DMA if necessary and wakeup sensor from standby
            }
        }
        else
        {
            Camera_status = stop_capture();//stop if already running and update the status
            Camera_Suspend();//halt DCMI and DMA and put sensor in standby mode
        }
    HAL_Delay(50);
}

Explicación de este código:

Este código es para alternar la vista previa en vivo de la cámara en la pantalla LCD.

start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);

Esta función inicia la captura continua de marcos de la cámara y actualiza el búfer de marcos. Básicamente, hace referencia a la función HAL_DCMI_Start_DMA.

stop_capture();

Esta función detiene la transferencia DMA.

Camera_Suspend y Camera_ Reanume deshabilitan / habilitan la interfaz DCMI y envían comandos de espera / activación a mi sensor de cámara a través de I2C.

Aquí es donde comienza el problema:

Si pongo este código en la función de devolución de llamada, la MCU se atasca en algún lugar de esta función. Solo un reinicio puede volver al estado normal.

En algún lugar de Internet leí que este problema podría estar relacionado con I2C, pero incluso si elimino las partes I2C en la función de devolución de llamada, el comportamiento no es el previsto: A veces funciona alrededor de tres veces o se atasca de nuevo inmediatamente. Creo que el problema está en la función HAL_DCMI_Start_DMA, pero no estoy seguro.

¿Hay algún error común que lleve a un problema como este?

Espero que se haya aclarado cuál es mi problema y que alguien pueda darme algunos consejos para resolverlo.

btw: Si uso el botón en el modo de sondeo en el ciclo infinito principal y hago exactamente lo mismo en un botón, todo funciona bien.

Para aclarar mis rutinas de interrupción:

Controlador principal de interrupciones:

void EXTI15_10_IRQHandler(void)
{
//if button pressed
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_11) != RESET)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
}
//if touchscreen interrupt
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
}

llamadas:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}

llamadas después de restablecer el indicador de TI:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
sprintf((char*)text, "EXTI pin: %d", GPIO_Pin);
BSP_LCD_DisplayStringAt(5, LINE(8), (uint8_t*)text, LEFT_MODE);
//if button pressed -> toggle preview
if(GPIO_Pin == GPIO_PIN_11)
{
    BSP_LED_Toggle(LED1);
}
//ts interrupt
if(GPIO_Pin == GPIO_PIN_13)
{

}
}

Esto funciona perfectamente, pero si sustituyo BSP_LED_Toggle (LED1); con el código anterior, la función se atasca.

Actualizar: Encontré el error. La prioridad de interrupción de SysTick se estableció en la más baja (15), por lo que llamar a HAL_Delay () desde un ISR con la misma o mayor prioridad causó un bucle infinito en la función HAL_Delay.

Por lo tanto, tenga cuidado: si está utilizando la configuración predeterminada de HAL proporcionada por ST, la prioridad para SysTick IRQ se establece en 15 al llamar a HAL_Init (). Debe cambiar eso en el archivo stm32f7xx_hal_conf.h o mediante el uso de la función HAL_InitTick (TickPriority).

Esto es lo que dice la documentación HAL de HAL_InitTick sobre ese problema:

  

Se debe tener cuidado si se llama a HAL_Delay () desde un ISR periférico   proceso, la interrupción de SysTick debe tener mayor prioridad   (numéricamente más bajo) que la interrupción periférica. De lo contrario el   El proceso ISR de la persona que llama será bloqueado. La función se declara como __weak   para ser sobrescrito en caso de otra implementación en el archivo de usuario.

    
pregunta deinoppa

2 respuestas

5

Actualización: he encontrado el error. La prioridad de interrupción de SysTick se estableció en la más baja (15), por lo que llamar a HAL_Delay () desde un ISR con la misma o mayor prioridad causó un bucle infinito en la función HAL_Delay.

Por lo tanto, tenga cuidado: si está utilizando la configuración predeterminada de HAL proporcionada por ST, la prioridad para SysTick IRQ se establece en 15 al llamar a HAL_Init (). Debe cambiar eso en el archivo stm32f7xx_hal_conf.h o mediante el uso de la función HAL_InitTick (TickPriority).

Esto es lo que dice la documentación HAL de HAL_InitTick sobre ese problema:

  

Se debe tener cuidado si se llama a HAL_Delay () desde un ISR periférico   proceso, la interrupción de SysTick debe tener mayor prioridad   (numéricamente más bajo) que la interrupción periférica. De lo contrario el   El proceso ISR de la persona que llama será bloqueado. La función se declara como __weak   para ser sobrescrito en caso de otra implementación en el archivo de usuario.

    
respondido por el deinoppa
1

Suponiendo que el código no se quede atascado en el ISR (según su última declaración, parece poco probable), el código no borra el indicador de interrupción dentro de la rutina de servicio de interrupción. Cuando ISR sale, el microcontrolador "verá" que el indicador de interrupción aún está activado y saltará inmediatamente a la rutina de servicio de interrupción.

Debe borrar el indicador de interrupción dentro de la rutina de servicio de interrupción. No estoy lo suficientemente familiarizado con el STM32 y el entorno de desarrollo para decirle exactamente cómo borrar el indicador de interrupción, pero el indicador de interrupción debe borrarse dentro del ISR.

    
respondido por el CHendrix

Lea otras preguntas en las etiquetas