Ich habe Probleme bei der Verwendung des UART auf dem STM32F103, wo er den Datenempfang stoppt, während keines der Fehlerflags gesetzt wird.
Das UART-Gerät ist ein ESP8266 mit 115.200 Baud. Ich sende es AT\r\n
. Der ESP8266 gibt jedes Byte zurück, das ich sende – ich kann diese Echos empfangen. Wenn es jedoch darum geht, die Antwort nach den Echos (+ einige Zeilenumbrüche) zu lesen OK
, läuft es nach dem Empfang eines Bytes ab.
Hier ist die gesamte Transaktion, wie sie auf einem Logikanalysator zu sehen ist.
STM32 sends: A T \r \n
ESP8266 sends: A T \r \r \n \r \n O K \r \n
In meinem Code sende ich ein Byte und empfange dann ein Byte, bis die Nutzlast gesendet wird. \n \r \n O K \r \n
Dann versuche ich, die verbleibenden 7 Bytes ( ) einzeln abzuhören . Ich erhalte die \n
, dann läuft die Kommunikation nach 5 Sekunden ab (mit dem Debugger sehe ich, dass es auf das RXNE
Flag wartet.)
Wenn die Zeitüberschreitung auftritt, sehe ich, dass keines der Fehlerflags ( ORE NE FE PE
) im SR
Register gesetzt ist.
Wenn ich versuche, zwei Bits gleichzeitig zu lesen, läuft der allererste HAL_UART_Receive
Aufruf ab.
Das Programm erstellt einige Debugging-Informationen (unten), während es jedes Byte sendet und das Echo empfängt, und versucht dann, die Antwort zu empfangen. Der Code für das Programm ist in einem Kern.
Ich schlage mir seit mehreren Stunden den Kopf dagegen. Was könnte dieses Verhalten verursachen?
Sending 4 bytes: AT(\r\n)
Echo:
Byte 0: sent 65, echo 65 (ORE 0) // A
Byte 1: sent 84, echo 84 (ORE 0) // T
Byte 2: sent 13, echo 13 (ORE 0) // \r
Byte 3: sent 10, echo 13 (ORE 0) // \n, echo \r
Receive:
Recv 10 // \n
Recv fail
RXNE: 0 ORE: 0 NE: 0 FE: 0 PE: 0
Auszug aus dem Code, der versucht, die Bytes zu lesen, nachdem das Senden abgeschlossen ist ( vollständiger Code ):
while (1) {
uint8_t recvChar;
if (HAL_UART_Receive(&Device_UART_Handle, &recvChar, 1, 5000) != HAL_OK) {
printf(" Recv fail\r\n");
printf(" RXNE: %d ORE: %d NE: %d FE: %d PE: %d\r\n",
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_RXNE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_ORE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_NE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_FE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_PE));
while(1) {}
}
printf(" Recv %d\r\n", recvChar);
}
Es besteht die Möglichkeit, dass Ihnen der größte Teil der Antwort entgeht, da die umfangreiche Protokollierung in Ihrer Empfangsschleife so lange dauert, dass das nächste Zeichen nicht erfasst werden kann. Selbst wenn Sie die Ausgabe von printf () um eine Größenordnung schneller senden als die 115200-Baud-Antwort des ESP8266, generieren Sie für jedes empfangene Zeichen so viele Ausgabezeichen, dass Sie höchstwahrscheinlich nicht mithalten können.
In der Anfangsphase, als für jedes gesendete Zeichen nur ein Antwortzeichen generiert wurde, könnte man vielleicht damit durchkommen, aber sobald der ESP8266 frei ist, einen 115200-Baud-Kanal voll zu halten, muss man damit Schritt halten können.
Die Konsolenausgabe ist in der Tat nützlich, aber Sie müssen die benötigte Zeit berücksichtigen, sie für die spätere Ausgabe in eine Warteschlange stellen, eingehende Zeichen mit einem UART ISR in eine Empfangswarteschlange ziehen oder ähnliches.
Ich stimme Chris Stratton zu, dass es sich um eine unglaublich große Menge an Protokollierung handelt.
Außerdem scheint sich der Code mit einer Endlosschleife selbst zu blockieren while(1) {}
:
while (1) {
uint8_t recvChar;
if (HAL_UART_Receive(&Device_UART_Handle, &recvChar, 1, 5000) != HAL_OK) {
printf(" Recv fail\r\n");
printf(" RXNE: %d ORE: %d NE: %d FE: %d PE: %d\r\n",
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_RXNE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_ORE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_NE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_FE),
__HAL_UART_GET_FLAG(&Device_UART_Handle, UART_FLAG_PE));
while(1) {} // <================= block everything forever?
}
printf(" Recv %d\r\n", recvChar);
}
wenn es einen Fehler bekommt.
Ist es das, was du vorhattest? Wenn dies ausgelöst wird, weil die Protokollierung zu lange dauert, bleibt es für immer hängen.
Bearbeiten: (aus meinem Kommentar):
Wenn Sie die Kontrolle über den Code an beiden Enden der UART-Verbindung (STM32 und ESP8266) haben, implementieren Sie ein Protokoll, das sicherstellt, dass keine Bytes verloren gehen.
Senden Sie beispielsweise eine Bestätigung für jedes empfangene Byte. Dies würde es komplexer, aber auch robuster machen, wenn Debug-Anweisungen verwendet werden.
Dies sieht aus wie ein klassischer "Heisenberg-Effekt", bei dem es sich um zeitkritische Prozesse handelt, deren Beobachtung jedoch schwer definierbare Verzögerungen einführt.
Ein alternativer Ansatz zur Protokollierung von printfs, der viel schneller wäre und daher weniger Auswirkungen hätte, wäre das Einschalten von LEDs, wenn ein Fehler erkannt wird und wenn eine gültige Übertragung erkannt wird.
gbulmer
Oldtimer
Oldtimer