STM32 beginnt mit der Zeitüberschreitung beim Empfang von Daten UART nach dem Lesen von 1 Byte

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.

Logikanalysator-Spuren

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 \nDann 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 RXNEFlag wartet.)

Wenn die Zeitüberschreitung auftritt, sehe ich, dass keines der Fehlerflags ( ORE NE FE PE) im SRRegister gesetzt ist.

Wenn ich versuche, zwei Bits gleichzeitig zu lesen, läuft der allererste HAL_UART_ReceiveAufruf 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);
}
Was passiert, wenn Sie die Abmeldung vornehmen? Haben Sie die Kontrolle über den ESP8266-Code? Wenn ja, können Sie es "drosseln"? Implementieren Sie möglicherweise eine Bestätigung für jedes empfangene Byte, um es robust zu machen, während Sie Debug-Anweisungen verwenden. Das sieht aus wie ein klassischer „Heisenberg-Effekt“.
Wenn Sie also all Ihr printf-Debug-Zeug loswerden und sagen, Sie setzen einen Timer für einige Sekunden (oder zählen Sie einfach bis zu einer großen Zahl, noch besser) und puffern Sie alles, was zurückkommt. dann nach der Zeitüberschreitung DANN die Zählung und welchen Text auch immer. Bekommst du immer noch nur einen Charakter?
ahh, ich glaube, ST ist die Firma, bei der ich mir die Haare ausgerissen habe. Suchen Sie nach einem OVRDIS-Overrun-Disable-Bit. Deaktiviere das bei init. Du sagst aber, du bekommst kein ORE. Wie auch immer, ich habe dagegen gekämpft, ich benutze kein HAL von ihnen, also weiß ich nicht, wie ich dir da helfen soll, das Uart ist etwas trivial ohne das hal zu initialisieren, so mache ich es ...

Antworten (2)

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.

Hätte schwören können, dass ich es ohne die printf()'s versucht habe! Ich glaube, ich bin gerade zwischen verschiedenen Ansätzen zum Debuggen von diesem das gelandet. Am Ende hattest du Recht mit dem Geld. Ich habe ein wenig experimentiert und es scheint, als ob Sie wirklich nichts in der Leseschleife haben können ! Danke Chris & andere Benutzer!
So wenig wie ein printf nach dem Senden, bevor die Empfangsschleife ausreicht, um es abzuwerfen!

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.

In Bezug auf die äußere Schleife – ich mache das einfach, damit ich sehen kann, wie viele Zeichen ich bekomme. Der Code, den ich gepostet habe, ist ein Testfall, den ich zusammengestellt habe. Die innere Schleife dient nur dazu, die Welt anzuhalten, nachdem ich auf die Fehlerbedingung gestoßen bin.