Ich versuche, einen UART-Empfänger zu implementieren, der funktioniert, indem er ein '\ 0' im Datenstrom findet, ODER wenn er 256 Zeichen empfängt, an welcher Stelle die Daten von einem Interrupt verarbeitet werden sollten. Der Punkt ist, DMA für den Empfang zu verwenden, aber wenn eines dieser Ereignisse eintritt, sollte es aufhören, den aktuellen Puffer zu füllen und die Daten zu verarbeiten. Der Grund ist, dass ich COBS-Codierung verwende , um meine Daten zu rahmen.
Der STM32F7-Chip hat etwas namens Character Match als Teil der Modbus-Spezifikation, das ich durch Setzen der Bits im Konfigurationsregister zum Laufen gebracht habe, da es von den HAL-Bibliotheken (stm32cubemx, die diesen Code beim Regenerieren entfernen würden) nicht unterstützt wird:
MODIFY_REG(huart->Instance->CR1, UART_CR1_FIELDS, tmpreg | USART_CR1_CMIE);
Und am Ende des UART-Interrupt-Handlers mache ich das
UART8->ICR |= USART_ISR_CMF;
Um das Interrupt-Flag für die Zeichenübereinstimmung zu löschen, damit es nicht erneut ausgeführt wird.
So wie ich es verstehe, sind die Interrupt-Handler in STM32f7xx_it.c tatsächlich die ersten Funktionen
void DMA1_Stream6_IRQHandler(void) and void UART8_IRQHandler(void)
in meinem Fall, die ausgeführt werden, wenn Interrupts in einem Peripheriegerät auftreten, und von diesen Funktionen wird ein Handler (HAL_xxx_IRQHandler()) ausgeführt, der überprüft, welcher Interrupt aufgetreten ist, und alle benutzerdefinierten Funktionen in Abhängigkeit von den Interrupt-Flags ausführen, wie zum Beispiel:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
//process data, this runs when DMA finishes receiving bytes
}
Das Problem ist, dass nicht klar ist, welche der Interrupt-Funktionen ausgeführt wird, wenn ich zum Beispiel DMA verwende und meine angegebene Datenmenge über UART erhalten habe. Führt es den UART-Interrupt oder den DMA-Stream-Interrupt aus? Wie kann ich zuverlässig in der gleichen Callback-Funktion auf '\0' (uart?) oder 256 Bytes (dma?) landen, um meine Daten zu verarbeiten, ohne die Interrupts zu verpfuschen?
Das DMA-CNDTR-Register zählt nach jeder Übertragung auf Null herunter und zeigt an, wie viele Elemente noch zu übertragen sind. Sie können damit überprüfen, ob der DMA läuft oder nicht.
Ihre UART-Interrupts laufen, falls aktiviert, immer neben den DMA-Übertragungen und -Interrupts, sodass die UART-Interrupts das CNDTR-Register des DMA überprüfen müssen, um zu wissen, ob sie tatsächlich ausgeführt werden sollen oder nicht.
Sie können Interrupts auch innerhalb von Interrupts deaktivieren. Ihr DMA-Transfer-Abschluss-Interrupt kann also Ihren Charakter-Empfangs-Interrupt deaktivieren (oder umgekehrt) und Sie können ihn an anderer Stelle wieder aktivieren. Denken Sie daran, dass Sie auch Interrupt-Prioritäten handhaben müssen, wenn die letzte DMA-Übertragung ein "\0"-Zeichen ist und gleichzeitig sowohl die DMA-Übertragung abgeschlossen als auch die Zeichenübereinstimmungs-Interrupts auslöst.
In meinem Code verwende ich die Zeichenübereinstimmung, um die Eingabetaste zu erkennen, um zu wissen, dass ein Benutzerbefehl eingegeben wurde, und um die vom DMA gespeicherte Nachricht im Speicher zu analysieren. Ich habe auch einen UART-Empfangsinterrupt, um Zeichen zu echoen, der das Zeichen direkt aus dem UART-Empfangsregister zurückgibt. Diese laufen alle gleichzeitig zusammen mit den DMA-Übertragungen und Interrupts.
Ich habe nicht mit STM32F7 gearbeitet, aber Sie können dieses Repository überprüfen . Ich habe eine Schritt-für-Schritt-Anleitung zur Verwendung von DMA mit Zeichenübereinstimmung und Empfänger-Timeout für STM32L4-MCUs geteilt. Wie ich sehen kann, sehen die Register für beide MCUs ähnlich aus.
Peter Schmidt
Chris Stratton
Tryphon