Hi, Ich möchte gerne über die UART Schnittstelle Daten empfangen und dazu die HAL Libraries verwenden. Nun kann man ja in CubeMX den UART aktivieren und mit HAL_UART_Receive_DMA(u, &rx_buff, BUFFSIZE_RX) aktiviert man den DMA. Ich habe den Circular Mode aktiviert, damit es den vollen Buffer wieder überschreibt. Jetzt löst mir void DMA1_Channel5_IRQHandler(void){...} nur aus, wenn der Buffer auch voll ist und sonst nicht. Was ich möchte ist, dass ich jedes mal, wenn ich einen String über den UART sende, ich den ganzen in den rx_buff bekomme und dann ein Interrupt aktiviert wird, so dass ich die Daten verwenden kann. Die gesendeten Daten sind nicht alle gleicher Länge. Doch wie mache ich das genau?
Woher soll die Hardware wissen wie lange denn dein String wird?
Hmm, da hast du schon recht. Aber irgend eine Möglichkeit muss es ja geben, ganze Befehle zu verschicken ohne immer zu pollen?
@Bert Siegfried (kautschuck) >den vollen Buffer wieder überschreibt. Jetzt löst mir void >DMA1_Channel5_IRQHandler(void){...} nur aus, wenn der Buffer auch voll >ist und sonst nicht. Logisch. > Was ich möchte ist, dass ich jedes mal, wenn ich >einen String über den UART sende, Empfange. > ich den ganzen in den rx_buff bekomme >und dann ein Interrupt aktiviert wird, so dass ich die Daten verwenden >kann. Dafür brauchst du einen IRQ-Handler, der bei jedem ankommenden Zeichen prüft, ob das Stringende erreicht ist, meist mit '\r'. Für diese Art des Datenempfangs kann man keinen DMA nutzen. > Die gesendeten Daten sind nicht alle gleicher Länge. Vom PC bzw. der Gegenstelle gesendet. > Doch wie > mache ich das genau? Siehe oben.
Bert S. schrieb: > Aber irgend eine Möglichkeit muss es ja > geben Ja die gibt es. Wenn man DMA für den Empfang nutzt, kann man einfach nicht wissen wie lang die zu Empfangenen Daten sind - daür gibt es in der USART/UART die "Receiver timeout" Funktion (Interrupt). Näheres müsstest du deinem Datenblatt entnehmen. Funktionsweise: - DMA für Empfang initialisieren - Timeout Funktion so konfigurieren, dass sie bei jedem empfangenen Byte neustartet, Wird nun nichts mehr empfangen, schlägt der Interrupt nach der gewünschten Timeout-Zeit zu und dan kannst die Daten aus deinem DMA Buffer verwenden.
Ich habe jetzt mal den Interrupt Ansatz probiert, doch auch hier wirkt wieder der Ringbuffer. Sagen wir ich empfange jetzt ein Wort und dann ein /0, dann möchte ich ja eine Funktion aufrufen, dort den Befehl abarbeiten und anschließend rx_data zurücksetzen. Doch wie genau bewerkstellige ich das zurücksetzen des Pointers von rx_data?
1 | void USART1_IRQHandler(void) |
2 | {
|
3 | /* USER CODE BEGIN USART1_IRQn 0 */
|
4 | |
5 | /* USER CODE END USART1_IRQn 0 */
|
6 | |
7 | HAL_UART_IRQHandler(&huart1); |
8 | |
9 | /* USER CODE BEGIN USART1_IRQn 1 */
|
10 | HAL_UART_Receive_IT(&huart1,rx_data,10); |
11 | /* USER CODE END USART1_IRQn 1 */
|
12 | }
|
Bert S. schrieb: > doch auch hier wirkt > wieder der Ringbuffer Dies wird auch immer so bleiben, wenn du die Funktion für den Empfangs-Timeout deiner USART nicht konfigurierst. Beachte: Nicht jede USART bestitzt diese Funktion (siehe Datenblatt). Welcher STM32 ist bei dir verbaut? Hab auf Github eine "stm32f0xx_hal_usart.h" gefunden, in dieser Datei (HAL) ist die Funktion des "Empfangs-Timeouts" gar nicht implementiert, obwohl der µC diese unterstützt. Du würdest zwei Interrupts behandeln müssen, bzw. beide Zustände betrachten. - Interrupt für: gewünscht DMA Datenlänge empfangen - Interrupt für: Empfangs-Timeout (Register: USART_ISR / Bit 11: RTOF) Den globalen UASRT_IRQHandler zu nutzen ist gut. Darin müsstest du prüfen welcher von beiden Fällen aufgetretten ist. Im Vorfeld musst du natürlich die USART richtig konfigurieren (inkl. Timeout), sollten in deiner HAL keine Funktionen für den Timeout vorhanden sein, musst du entweder direkt die Register beschreiben oder die HAL erweitern. Hast du dir mal den Abschnitt "Universal synchronous asynchronous receiver transmitter (USART)" im Datenblatt überhaupt mal durchgelesen? Dort ist nämlich beschrieben wie dieser Timeout funkioniert. Nebenbei: Weiterhin sollte dir klar sein, dass du den Empfang, Verarbeitung und Versenden nicht alles in deinem Interrupt abarbeiten solltest.
Wenn ich auf einem STM32 mit den HAL Libraries einen UART Interrupt auslöse, dann wird für tx und rx die gleiche Callback Funktion aufgerufen, nämlich USART1_IRQHandler(). Doch welche Flags muss ich nun überprüfen, ob es sich um rx oder tx handelt?
Warum nutzt du nicht dein Beitrag von gestern? Es handelt sich ja wohl immer noch um gleiches Problem. Da kommt es drauf an was du wissen möchtest. RX und TX haben viel mehr Unterteilungen: (siehe Datenblatt - Register: USART_ISR)
:
Bearbeitet durch User
Danke, ich werde mir den Abschnitt "Universal synchronous asynchronous receiver transmitter (USART)" mal genau durchlesen. Vebraut ist eine STM32F303K8T6.
Also ich hab mir grad mal das HAL Paket "STM32Cube_FW_F3_V1.9.0" heruntergeladen und da ist die Timeout Funktion nicht implementiert. Wirst nicht drum herum kommen, es zu verstehen und selbst zu implementieren. Aber so ein Hexenwerk ist es auch wieder nicht. Wenn du dein DMA RX Interrupt schon hast, kommt das mit dem Timeout eigentlich nur noch hinzu. Wenn er richtig konfiguriert ist und läuft - und du dann nur ein Zeichen sendest obwohl du per DMA auf 10 wartest, wird nach kurzer Zeit dein Timeout Interrupt zuschlagen.
:
Bearbeitet durch User
Je nach dem wie die Datenübertragung geartet ist könnte man evtl. bei jedem Systick an der letzten beschriebenen Position des Ringpuffers nachschauen ob das Schlußzeichen empfangen wurde und die Verarbeitung auslösen.
Ich hange immer noch am RX interrupt, besser gesagt bei der Unterscheidung von RX und TX in der globalen IRQ.
1 | if(__HAL_UART_GET_IT(&huart1,UART_IT_RXNE) != RESET) {...} |
Scheint nicht zu passen.
Hier das "Datenblatt" bei ST ist es "Reference Manual": http://www.st.com/content/ccc/resource/technical/document/reference_manual/4a/19/6e/18/9d/92/43/32/DM00043574.pdf/files/DM00043574.pdf/jcr:content/translations/en.DM00043574.pdf Seite 943 Register USART_ISR Diese Möglichkeiten gibt es was ein Interrupt sein kann. -> Du solltest aber lieber die USART Funktionen nutzen (stm32f30x_usart.h) nicht die aus der HAL. Nachtrag zur Timeout-Funktion: Tatsache, diese ist zwar nicht im HAL implementiert, jedoch in der Peripherie Datei (stm32f30x_usart.h). Siehe:
1 | void USART_ReceiverTimeOutCmd(...); |
2 | void USART_SetReceiverTimeOut(...); |
Bzgl. deines Interrupts Problems, siehe die Definition von der dazugehörigen Fkt.
1 | /**
|
2 | * @brief Checks whether the specified USART interrupt has occurred or not.
|
3 | * @param USARTx: Select the USART peripheral. This parameter can be one of the
|
4 | * following values: USART1 or USART2 or USART3 or UART4 or UART5.
|
5 | * @param USART_IT: specifies the USART interrupt source to check.
|
6 | * This parameter can be one of the following values:
|
7 | * @arg USART_IT_WU: Wake up interrupt.
|
8 | * @arg USART_IT_CM: Character match interrupt.
|
9 | * @arg USART_IT_EOB: End of block interrupt.
|
10 | * @arg USART_IT_RTO: Receive time out interrupt.
|
11 | * @arg USART_IT_CTS: CTS change interrupt.
|
12 | * @arg USART_IT_LBD: LIN Break detection interrupt.
|
13 | * @arg USART_IT_TXE: Transmit Data Register empty interrupt.
|
14 | * @arg USART_IT_TC: Transmission complete interrupt.
|
15 | * @arg USART_IT_RXNE: Receive Data register not empty interrupt.
|
16 | * @arg USART_IT_IDLE: Idle line detection interrupt.
|
17 | * @arg USART_IT_ORE: OverRun Error interrupt.
|
18 | * @arg USART_IT_NE: Noise Error interrupt.
|
19 | * @arg USART_IT_FE: Framing Error interrupt.
|
20 | * @arg USART_IT_PE: Parity Error interrupt.
|
21 | * @retval The new state of USART_IT (SET or RESET).
|
22 | */
|
23 | ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint32_t USART_IT) |
...
1 | void USART1_IRQHandler(void) |
2 | {
|
3 | /* 1 Byte empfangen */
|
4 | if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) |
5 | {
|
6 | }
|
7 | |
8 | /* 1 Byte versendet */
|
9 | if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) |
10 | {
|
11 | }
|
12 | }
|
Das wird dir aber bei deinem DMA und Timeout nicht weiterhelfen, aber vllt. kommst du ja jetzt drauf wie und welche Interrupts du benötigst. Nett, jetzt lerne ich auch noch nebenbei ST µC zu programmieren und die Library :-D
Wo der Interrupt herkommt verrät dir das Interrupt Status Register (ISR) des jeweiligen UART und um ein Bit in einem Register abzufragen benötigt es meiner Meinung nach auch keiner Library und erst recht nicht zwei Libraries.
1 | if (UART1->ISR & UART_ISR_TXE) { |
2 | // TX(-Buffer) empty, d.h. es wurde etwas versendet
|
3 | }
|
4 | |
5 | if (UART1->ISR & UART_ISR_RXNE) { |
6 | // RX(-Buffer) not empty, d.h. es wurde etwas empfangen
|
7 | }
|
Der Interrupt feuert aber grundsätzlich nur dann wenn die entsprechenden Bits im Configuration Register 1 des jeweiligen UARTs gesetzt sind (siehe 29.7 in RM0360 bzw. 29.8.1 und 29.8.8 für CR1 und ISR). Auch für STs HAL gibt es ein User-Manual. Für die F3-Familie wäre das z.B. www.st.com/resource/en/user_manual/dm00122016.pdf Siehe dort Kapitel 54.2 "UART Firmware Driver API Description"
Danke euch, ich werde mich mal daran versuchen.
:
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.