STM32F767: "HAL_UART_Receive_IT" bringt busy

OP #7488892
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
}
OP #7488924
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?

#7488967
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. [CODE] ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); // Zeile 4400

huart->RxState = HAL_UART_STATE_READY; // Zeile 4407 [/CODE]

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.

Angehängte Dateien:
OP #7488983
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
}
OP #7488995
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
#7488999
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 :)

OP #7489008
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

Angehängte Dateien:
#7489316
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.

#7489532
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.

#7489549
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.

OP #7489627
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren