Ich arbeite an einem Projekt, um eine Kamera über die DCMI-Schnittstelle an eine STM32F7 Discovery-Karte anzuschließen. Der Kamerateil funktioniert gut, aber ich habe ein seltsames Problem mit externen Interrupts über den integrierten Druckknopf.
Ich aktiviere externe Interrupts für die Schaltfläche mit der im STM BSP-Paket bereitgestellten Funktion:
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);
Der externe Interrupt für diese Schaltfläche befindet sich jetzt auf GPIO_PIN_11. Dieser Interrupt wird von der Funktion HAL_GPIO_EXTI_Callback behandelt, die ich in meiner Datei main.c implementieren kann.
Ich verwende STM HAL / BSP-Bibliotheken.
Der Interrupt bei einem Tastendruck funktioniert und die Rückruffunktion ist korrekt eingegeben, aber hier beginnt das Problem.
Folgendes möchte ich auf Knopfdruck tun:
{
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);
}
Erläuterung dieses Codes:
Dieser Code dient zum Umschalten der Live-Vorschau der Kamera auf dem LCD.
start_capture_continuous((uint8_t*)CAMERA_FRAME_BUFFER);
Diese Funktion startet das kontinuierliche Abrufen von Bildern von der Kamera und aktualisiert den Bildpuffer. Es verweist grundsätzlich auf die Funktion HAL_DCMI_Start_DMA.
stop_capture();
Diese Funktion stoppt die DMA-Übertragung.
Camera_Suspend und Camera_Resume deaktivieren / aktivieren die DCMI-Schnittstelle und senden Standby- / Weckbefehle über I2C an meinen Kamerasensor.
Hier beginnt also das Problem:
Wenn ich diesen Code in die Rückruffunktion setze, bleibt die MCU irgendwo in dieser Funktion stecken. Nur ein Reset kann mich wieder in den normalen Zustand bringen.
Irgendwo im Internet habe ich gelesen, dass dieses Problem mit I2C zusammenhängen könnte, aber selbst wenn ich die I2C-Teile in der Rückruffunktion lösche, ist das Verhalten nicht wie beabsichtigt: Manchmal funktioniert es ungefähr dreimal oder es bleibt sofort wieder hängen. Ich glaube, das Problem liegt in der Funktion HAL_DCMI_Start_DMA, bin mir aber nicht sicher.
Gibt es häufige Fehler, die zu einem solchen Problem führen?
Ich hoffe, es ist klar geworden, was mein Problem ist, und jemand kann mir einige Tipps geben, um es zu lösen.
Übrigens: Wenn ich die Taste im Polling-Modus in der Endlosschleife verwende und genau die gleichen Dinge auf einer Taste mache, funktioniert alles gut.
Um meine Interruptroutinen zu verdeutlichen:
Hauptinterrupt-Handler:
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);
}
}
Anrufe:
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);
}
}
Anrufe nach dem Zurücksetzen des IT-Flags:
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)
{
}
}
Dies funktioniert einwandfrei, aber wenn ich BSP_LED_Toggle (LED1) ersetze; Mit dem obigen Code bleibt die Funktion hängen.
Update: Ich habe den Fehler gefunden. Die SysTick-Interrupt-Priorität wurde auf die niedrigste (15) gesetzt, sodass das Aufrufen von HAL_Delay () von einem ISR mit derselben oder höherer Priorität eine Endlosschleife in der HAL_Delay-Funktion verursachte.
Seien Sie also vorsichtig: Wenn Sie die von ST bereitgestellten HAL-Standardeinstellungen verwenden, wird die Priorität für SysTick IRQ beim Aufrufen von HAL_Init () auf 15 festgelegt. Sie müssen dies in der Datei stm32f7xx_hal_conf.h oder mithilfe der Funktion HAL_InitTick (TickPriority) ändern.
In der HAL-Dokumentation von HAL_InitTick heißt es zu diesem Problem:
Vorsicht ist geboten, wenn HAL_Delay () von einem peripheren ISR-Prozess aufgerufen wird. Der SysTick-Interrupt muss eine höhere Priorität (numerisch niedriger) als der periphere Interrupt haben. Andernfalls wird der Anrufer-ISR-Prozess blockiert. Die Funktion wird als __schwach deklariert und im Falle einer anderen Implementierung in der Benutzerdatei überschrieben.
Antworten:
Update: Ich habe den Fehler gefunden. Die SysTick-Interrupt-Priorität wurde auf die niedrigste (15) gesetzt, sodass das Aufrufen von HAL_Delay () von einem ISR mit derselben oder höherer Priorität eine Endlosschleife in der HAL_Delay-Funktion verursachte.
Seien Sie also vorsichtig: Wenn Sie die von ST bereitgestellten HAL-Standardeinstellungen verwenden, wird die Priorität für SysTick IRQ beim Aufrufen von HAL_Init () auf 15 festgelegt. Sie müssen dies in der Datei stm32f7xx_hal_conf.h oder mithilfe der Funktion HAL_InitTick (TickPriority) ändern.
In der HAL-Dokumentation von HAL_InitTick heißt es zu diesem Problem:
quelle
Unter der Annahme, dass der Code nicht im ISR hängen bleibt (nach Ihrer letzten Aussage scheint dies unwahrscheinlich), löscht der Code das Interrupt-Flag innerhalb der Interrupt-Serviceroutine nicht. Wenn ISR beendet wird, "sieht" der Mikrocontroller, dass das Interrupt-Flag noch gesetzt ist, und springt sofort zur Interrupt-Serviceroutine zurück.
Sie müssen das Interrupt-Flag innerhalb der Interrupt-Serviceroutine löschen. Ich bin mit dem STM32 und der Entwicklungsumgebung nicht vertraut genug, um Ihnen genau zu sagen, wie das Interrupt-Flag gelöscht werden soll, aber das Interrupt-Flag muss innerhalb des ISR gelöscht werden.
quelle