Estoy trabajando en un proyecto para conectar una cámara a una placa STM32F7 Discovery utilizando la interfaz DCMI. La parte de la cámara funciona bien, pero tengo un extraño problema con las interrupciones externas del pulsador de la placa.
Habilito las interrupciones externas para el botón usando la función provista en el paquete STM BSP:
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);
La interrupción externa para este botón está ahora 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 HAL/BSP de STM.
La interrupción al pulsar un botón funciona y la función de devolución de llamada se introduce correctamente, pero aquí es donde empieza el problema.
Esto es lo que quiero hacer al pulsar 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 fotogramas de la cámara y actualiza el buffer de fotogramas. 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_Resume deshabilitan/habilitan la interfaz DCMI y envían comandos de espera/despertar a mi sensor de cámara vía I2C.
Así que aquí es donde empieza el problema:
Si pongo este código en la función callback, el MCU se queda atascado en alguna parte de esta función. Sólo un reinicio puede devolverme 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 de I2C en la función de devolución de llamada el comportamiento no es el previsto: A veces funciona durante unas tres veces o se atasca inmediatamente de nuevo. 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 éste?
Espero que haya quedado claro cuál es mi problema y alguien pueda darme alguna pista para solucionarlo.
btw: Si uso el botón en modo de sondeo en el bucle infinito principal y hago exactamente las mismas cosas al pulsar el botón todo funciona bien.
Para aclarar mis rutinas de interrupción:
Manejador de la interrupción principal:
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 la bandera 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 reemplazo BSP_LED_Toggle(LED1); con el código anterior, la función se atasca.
Actualización: He encontrado el error. La prioridad de la interrupción SysTick estaba establecida en la más baja (15), por lo que llamar a HAL_Delay() desde un ISR con la misma o mayor prioridad causaba un bucle infinito en la función HAL_Delay.
Por lo tanto, tenga cuidado: Si estás usando la configuración por defecto de la HAL proporcionada por ST, la prioridad para la IRQ de SysTick se establece en 15 cuando se llama a HAL_Init(). Tienes que cambiar eso en el archivo stm32f7xx_hal_conf.h o usando la función HAL_InitTick(TickPriority).
Esto es lo que dice la documentación de HAL de HAL_InitTick sobre este tema:
Hay que tener cuidado si se llama a HAL_Delay() desde un proceso ISR periférico periférico, la interrupción SysTick debe tener mayor prioridad (numéricamente inferior) que la interrupción periférica. De lo contrario, el proceso proceso ISR que llama será bloqueado. La función se declara como __débil para ser sobrescrita en caso de otra implementación en el archivo de usuario.
1 votos
¿Incluyó código para borrar la bandera de interrupción dentro de su manejador/retorno?
2 votos
Eso es una tonelada de cosas para hacer en una interrupción, y una mala práctica. Establece una bandera en la interrupción, y actúa sobre la bandera en el main.
0 votos
Sé que esto es una mala práctica, pero parece ser la práctica estándar de la biblioteca ST HAL. El manejador principal es la función EXTI15_10_IRQHandler(void) en el archivo stm32f7xx_it.c. Esta función comprueba en qué pin GPIO se ha producido la interrupción y llama a HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11). La bandera de la interrupción se borra en la función HAL que también llama a la función callback después. Así que el procedimiento es realmente más complicado de lo necesario, pero el problema no es borrar las banderas de interrupción.
0 votos
¿Qué programa está utilizando para la depuración? Tuve un problema similar una vez y tuve que corregir lo que creo que es un error de una biblioteca HAL de ST. Pero para saber específicamente donde se atascaba mi programa utilicé Visual Studio con VisualGDB, sería difícil precisar exactamente tu problema sin una depuración paso a paso de algún tipo. Si puedo encontrar dónde cambié el código te responderé con él, pero no estoy seguro de que resuelva tu problema.
0 votos
Todavía no he configurado un entorno de depuración adecuado. El problema es que estoy usando OpenSTM32 IDE basado en Eclipse y las herramientas de depuración (OpenOCD) son bastante confusas con el soporte del STM32F7. También tengo que admitir que soy relativamente nuevo en la programación de STM32.
0 votos
Ahora he configurado un entorno de depuración y parece que hay un problema con las prioridades de las interrupciones. Así que mi botón ISR siempre es interrumpido por otra interrupción (que necesito para la interfaz DCMI) y por lo tanto parece colgar.
1 votos
Deberías publicar tu solución y convertirla en la respuesta aceptada para que la gente no pierda el tiempo leyendo esto.