Forum: Mikrocontroller und Digitale Elektronik STM32F767: "HAL_UART_Receive_IT" bringt busy


von Micha (michael_schwaer)


Lesenswert?

Hallo,

ich verwende bei meinem STM32F767 mehrere UARTS. Bei einem nutze ich den 
Callback für empfangene Daten (jeweils 1 Byte). Nach dem Auswerten des 
Bytes wird der Empfang des nächsten Bytes gleich wieder angestoßen.
Ca. 1 Mal in der Woche bleibt das Ganze hängen (es werden ca. 600.000 
Telegramme pro Woche empfangen). Den Grund habe ich nun gefunden, denn 
HAL_UART_Receive_IT liefert BUSY zurück. Aber warum? Was kann dazu 
führen, daß er busy ist? Es wurde ja zuvor nur 1 Byte empfangen und bis 
er das ausgewertet hat, sollte doch ein weiteres Freischalten gehen?

1
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
2
{
3
static unsigned int HallState;
4
5
UNUSED(huart);  // Prevent unused argument(s) compilation warning
6
7
if(huart->Instance == UART_KNX)
8
  {
9
  knx_rx_callback_routine(knx_UART_fifo_rx.RX_byte); // Auswertung des Bytes
10
  HallState = HAL_UART_Receive_IT(&huart7, &knx_UART_fifo_rx.RX_byte, 1);    // Den Empfang des nächsten Bytes starten (1 Zeichen mit Interrupt empfangen)
11
  if(HallState != HAL_OK)
12
    fehlerspeicher_schreiben(FKT_KNX_RX_CALLBACK, 1, HallState);      
13
  }
14
}

von N. M. (mani)


Lesenswert?

Kenne mich mit der HAL von ST nicht aus, aber könnte es sein dass in 
diesem Zustand irgendwelche Fehlerbits in den Registern gesetzt sind.
Also Parity-, Frame-, Overrunerror oder ähnliches?

Edit:Typo

: Bearbeitet durch User
von Micha (michael_schwaer)


Lesenswert?

Die Funktion sieht wie folgt aus:
1
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
2
{
3
  /* Check that a Rx process is not already ongoing */
4
  if(huart->RxState == HAL_UART_STATE_READY)
5
  {
6
   ....  //diverse Befehle
7
    return HAL_OK;
8
  }
9
  else
10
  {
11
    return HAL_BUSY;
12
  }
13
}



Also ist "huart->RxState == HAL_UART_STATE_READY" nicht erfüllt. Aber 
warum? Welche Register könnte ich im Fehlerfall in meinem Fehlerspeicher 
sichern, um den Fehler einzugrenzen?

Wie ist das eigentlich, wenn zu diesem Zeitpunkt ein Interrupt einer 
höher priorisierten Schnittstelle kommt? Kann das dazu führen, daß dann 
busy kommt?

von Georg (alphageorg)


Lesenswert?

Ich nehme an das Interrupt Flag wird in der ISR sofort
zurück gestzt? Dann würde ich die Interrupt Priorität erhöhen und
schauen ob das was bringt ...

von Micha (michael_schwaer)


Lesenswert?

Georg schrieb:
> Ich nehme an das Interrupt Flag wird in der ISR sofort
> zurück gestzt? Dann würde ich die Interrupt Priorität erhöhen und
> schauen ob das was bringt ...

Das dumme ist, daß sich der Fehler erst nach einigen Tagen bemerkbar 
macht. Kann auch mal 2-3 Wochen laufen. Daher ist die Fehlereingrenzung 
schwierig.

von Ali K. (teddy50)


Angehängte Dateien:

Lesenswert?

Du kannst in der IDE suchen, wo huart->RxState überall gesetzt wird.
Mit STRG+H gibst du die gesuchte Variable ein und klickst auf search.
Ich habe ein Bild angehängt.

Nach dem Empfang eines Bytes wird RxState in der Funktion 
UART_RxISR_8BIT wieder zurück auf STATE_READY gesetzt. Des Weiteren 
werden die Interruptflags dort zurückgesetzt.
1
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); // Zeile 4400
2
3
huart->RxState = HAL_UART_STATE_READY; 
4
// Zeile 4407

Erst danach wird deine Callback-Funktion aufgerufen.

-> Sehr merkwürdig das ganze.
Mich hats gestern übrigens total geärgert, dass man den RX-Interrupt 
durch die Funktion TRANSMIT_IT jedesmal anstoßen muss.

: Bearbeitet durch User
von Micha (michael_schwaer)


Lesenswert?

Danke, jetzt habe ich es auch gefunden:

 huart->RxState = HAL_UART_STATE_READY;  // Ready setzen

  HAL_UART_RxCpltCallback(huart);      // Callback aufrufen

Der Callback wird ja erst aufgerufen, wenn State Ready ist. warum das 
dann ab und zu schief läuft, ist mir ein Rätsel.

1
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
2
{
3
  uint16_t* tmp;
4
  uint16_t uhMask = huart->Mask;
5
6
  /* Check that a Rx process is ongoing */
7
  if(huart->RxState == HAL_UART_STATE_BUSY_RX)
8
  {
9
10
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
11
    {
12
      tmp = (uint16_t*) huart->pRxBuffPtr ;
13
      *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
14
      huart->pRxBuffPtr +=2;
15
    }
16
    else
17
    {
18
      *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
19
    }
20
21
    if(--huart->RxXferCount == 0)
22
    {
23
      /* Disable the UART Parity Error Interrupt and RXNE interrupt*/
24
      CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
25
26
      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
27
      CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
28
29
      /* Rx process is completed, restore huart->RxState to Ready */
30
      huart->RxState = HAL_UART_STATE_READY;  // <<<<<<<<<<<<<<
31
32
      HAL_UART_RxCpltCallback(huart);  // <<<<<<<<<<<<<<
33
34
      return HAL_OK;
35
    }
36
37
    return HAL_OK;
38
  }
39
  else
40
  {
41
    /* Clear RXNE interrupt flag */
42
    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
43
44
    return HAL_BUSY;
45
  }
46
}

von Harry L. (mysth)


Lesenswert?

Du schreibst ja, daß du mehrere UARTs verwendest. Kannst du sicher 
ausschliessen, daß du nicht an irgendeiner Stelle versehentlich das 
falsche UART-Handle übergibts?
Das würde zumindest dieses Verhalten erklären.

Vielleicht nochmal als Inspiration:
Bei meinem UART-Code habe ich sowas noch nie beobachten können.
Beitrag "[STM32/HAL] simples U(S)ART-Library"

von Micha (michael_schwaer)


Lesenswert?

Harry L. schrieb:
> Du schreibst ja, daß du mehrere UARTs verwendest. Kannst du sicher
> ausschliessen, daß du nicht an irgendeiner Stelle versehentlich das
> falsche UART-Handle übergibts?
> Das würde zumindest dieses Verhalten erklären.

huart7 bzw. huart_knx wird für den Empfang nur an 2 Stellen verwendet:
- beim Initialisieren des Programms
- nach dem Empfang der einzelnen Bytes

von Ali K. (teddy50)


Lesenswert?

Micha schrieb:
> Harry L. schrieb:
>> Du schreibst ja, daß du mehrere UARTs verwendest. Kannst du sicher
>> ausschliessen, daß du nicht an irgendeiner Stelle versehentlich das
>> falsche UART-Handle übergibts?
>> Das würde zumindest dieses Verhalten erklären.
>
> huart7 bzw. huart_knx wird für den Empfang nur an 2 Stellen verwendet:
> - beim Initialisieren des Programms
> - nach dem Empfang der einzelnen Bytes

Und du bist dir ganz sicher, dass diese Instanz nicht woanders noch 
verwendet wird?
Kannst ja mal per STRG+H prüfen, ob du es ausversehen noch woanders 
verwendest :)

von Micha (michael_schwaer)


Angehängte Dateien:

Lesenswert?

Ali K. schrieb:
> Und du bist dir ganz sicher, dass diese Instanz nicht woanders noch
> verwendet wird?
> Kannst ja mal per STRG+H prüfen, ob du es ausversehen noch woanders
> verwendest :)

Anbei ein Bild, wo Interrupt-gesteuerter Empfang angestoßen wird.
Einziger Unterschied ist, daß ich einmal huart7 und huart_knx 
geschrieben habe. Ist aber durch defines identisch:

#define huart_knx huart7

#define UART_KNX  UART7

von Ali K. (teddy50)


Lesenswert?

Hmm...
also mir gehen die Ideen aus.
Du könntest höchstens noch die Variable huart->RxState abfragen bzw. 
tracen, wenn ein HAL_BUSY zurückgegeben wird.

von Thorsten M. (pappkamerad)


Lesenswert?

Hab mir jetzt nur den vom TE geposteten Code angeschaut. Könnte es sein, 
dass das Empfangen per Interrupt in der HAL nicht mehr vorgesehen ist, 
wenn das nächste Byte bereits angekommen ist?

In HAL_UART_Receive_IT(...) heißt es (siehe Kommentar) ja:
1
  /* Check that a Rx process is not already ongoing */
2
  if(huart->RxState == HAL_UART_STATE_READY)

"already ongoing" verstehe ich so, dass das nächste Byte schon da ist.
Vielleicht ist auch nur ein kurzer Zeitraum "gesperrt" zwischen Empfang 
in der HAL und Verarbeitung* durch die HAL. *Es scheint ja so, dass man 
nicht nur einzelne Byte abholen kann.

von Micha (michael_schwaer)


Lesenswert?

Thorsten M. schrieb:
> Es scheint ja so, dass man nicht nur einzelne Byte abholen kann

Die Anzahl der Bytes wird beim Aufruf angegeben. Ich verwende 1, da die 
Länge von der jeweiligen Nachricht abhängig ist.

von Thorsten M. (pappkamerad)


Lesenswert?

Blos wie macht die HAL das mit mehreren Bytes wenn angegeben? Wenn mit 
DMA, dann wird es problematisch sein, wenn bereits ein Byte im 
Empfangsbuffer liegt. Das Busy-Flag könnte das absichern. Meine 
Vermutung war eben, dass deine Verarbeitung (des Bytes) sporadisch zu 
lange dauert und dann das nächste schon angekommen ist, was dann ein 
Busy signalisiert.

von Harry L. (mysth)


Lesenswert?

Thorsten M. schrieb:
> Meine
> Vermutung war eben, dass deine Verarbeitung (des Bytes) sporadisch zu
> lange dauert und dann das nächste schon angekommen ist, was dann ein
> Busy signalisiert.

Da musst du bei einem F7 aber schon ne Menge Radau machen, damit sowas 
passiert.
Das einschieben in einen FiFo wird dazu sicher nicht reichen.
Und wenn man sich bei der Vergabe der Interrupt-Prioritäten nicht allzu 
dusselig anstellt werden auch Unterbrechungen durch andere Interrupts 
sicher nicht zum Problem - erst recht nicht bei einem doch recht lahmen 
UART.

von Micha (michael_schwaer)


Lesenswert?

Thorsten M. schrieb:
> "already ongoing" verstehe ich so, dass das nächste Byte schon da ist.
> Vielleicht ist auch nur ein kurzer Zeitraum "gesperrt" zwischen Empfang
> in der HAL und Verarbeitung* durch die HAL. *Es scheint ja so, dass man
> nicht nur einzelne Byte abholen kann.

Ich vermute, daß dann die Bytes verloren gehen, wenn man zu spät wieder 
freigibt. Busy kann er eigentlich nicht sein, denn wenn kein Empfang für 
ein neues Byte freigegeben wurde, kann er auch nicht damit beschäftigt 
sein.

Ich denke, bis ich das erste Byte in der Initialisierung freigebe, sind 
schon ein paar Byte von der Schnittstelle vom KNX gekommen. Wenn dann 
schon busy kommen würde, hätte ich da ja schon das Problem und er würde 
nie was empfangen. Wenn nicht freigeschaltet, werden alle Bytes 
ignoriert- so meine Vermutung. Baudrate ist übrigens 19200, sollte daher 
kein Problem machen.

Ich werde morgen mal schauen, daß ich die neusten STM-HAL´s drauf 
spiele. IDE (Segger) ist auch noch eine ältere Version (5.50d). Mal 
sehen, ob das Problem dann weg ist. Kurios ist, daß ich das Problem nur 
bei UART 7 habe. Bei einem anderen UART hängt eine Wetterstation dran, 
die jede Sekunde Daten sendet. Da hatte ich noch nie ein derartiges 
Problem. Hat ebenfalls 19200 Baud.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.