Hi, alsooo ich habe einen STM32F103 (BluePill) und möchte in ein Programm einen einfachen Test für die UARTs implementieren. Die Idee dahinter ist, dass ich Rx und Tx brücke, dann ein paar Byte raus sende und wieder empfange.. Vom Prinzip her hätte ich vermutet, dass sowas in der Richtung geht: uint8_t out[] = {0xff,0x55,0x66}; uint8_t in[3]; HAL_UART_Transmit(uart, out, 3, 100); HAL_UART_Receive(uart, in, 3); Was ich dabei empfange ist aber großes Ka**.. :-( Wie gehts denn nun tatsächlich? Anders herum wäre es sicher einfacher aber der Controller soll ja seine Hardware selbst testen.. Grundsätzlich gibt es scheinbar die Funktion HAL_USART_TransmitReceive() aaaaber ich finde im STMCube keine Implementierung dafür..
Jens R. schrieb: > Wie gehts denn nun tatsächlich? Ohne die Doku und Beispiele der HAL zu studieren empfehle ich, sie nicht zu benutzen. Es geht ja auch ohne. Siehe meine Anleitung http://stefanfrings.de/stm32
Steve van de Grens schrieb: > Ohne die Doku und Beispiele der HAL zu studieren empfehle ich, sie nicht > zu benutzen. Die HAL ist gerade im Bereich UART unheimlich eigenartig aufgebaut. Die dürfte wohl ein frisch studierter Schulabgänger programimert haben. Ich schließe mich diener Empfehlung vollumfänglich an. Jens R. schrieb: > Was ich dabei empfange ist aber großes Ka** Und was passiert tstsächlich auf dem Bus? Zum Debuggen serieller Busse ist ein Speicheroszi oder ein Logikanalyzer zwingend. Jens R. schrieb: > Die Idee dahinter ist, dass ich Rx und Tx brücke, dann ein paar Byte > raus sende und wieder empfange... Wie wäre es, einfach nur 1 Byte zu senden und dann sofort im RX-Datenregister zu schauen, was empfangen wurde?
Lothar M. schrieb: > Steve van de Grens schrieb: >> Ohne die Doku und Beispiele der HAL zu studieren empfehle ich, sie nicht >> zu benutzen. > Die HAL ist gerade im Bereich UART unheimlich eigenartig aufgebaut. Die > dürfte wohl ein frisch studierter Schulabgänger programimert haben. Ich > schließe mich diener Empfehlung vollumfänglich an. Ich hätt tatsächlich auch lieber was anderes benutzt aber wenn man schon Vorgaben hat.. > Jens R. schrieb: >> Was ich dabei empfange ist aber großes Ka** > Und was passiert tstsächlich auf dem Bus? Zum Debuggen serieller Busse > ist ein Speicheroszi oder ein Logikanalyzer zwingend. Erst mal gehts ja tatsächlich nur um die Drahtbrücke. Wenn das nicht das gewünschte Ergebnis liefert brauch ich die Hardware die dann dran soll gar nicht erst debuggen ;) > Jens R. schrieb: >> Die Idee dahinter ist, dass ich Rx und Tx brücke, dann ein paar Byte >> raus sende und wieder empfange... > Wie wäre es, einfach nur 1 Byte zu senden und dann sofort im > RX-Datenregister zu schauen, was empfangen wurde? Der Hinweis ist aber Gold wert. Muss nur noch schauen wie ich an das Register komme. Die UART_HandleTypeDef hat da einen Buffer.. mal schauen wie man den nutzt..
Jens R. schrieb: > Muss nur noch schauen wie ich an das Register komme. Indem du es direkt liest, ohne HAL. Orientiere dich an meinem Beispiel.
Die HAL UART Funktionen funktionieren, habe ich schon zigfach in allen Varianten eingesetzt.
J. S. schrieb: > Die HAL UART Funktionen funktionieren Sicher, nur wie? Stellen die interruptgesteuertes Senden und Empfangen zur Verfügung? Wartet HAL_UART_Transmit, bis das letzte Byte auch wirklich gesendet wurde, oder kehrt es sofort nach dem Eintragen der Bytes in einen (hypothetischen) Sendepuffer zurück? Woher holt HAL_UART_Receive die Daten? Aus einem (hypothetischen) Empfangspuffer, den ein Interrupthandler im Hintergrund mit Daten befüllt? Was macht es, wenn im Puffer zum Zeitpunkt des Aufrufs noch nicht genug Daten verfügbar sind? Wartet es oder kehrt es mit einem Fehlercode zurück?
Eben, HAL kann keine Gedanken lesen. Das sind low level Funktionen. Wer soll nach dem Senden wo wieviele Zeichen wie speichern? Um Fifo oder blockweises Speichern muss man sich selber kümmern.
Lothar M. schrieb: > Die HAL ist gerade im Bereich UART unheimlich eigenartig aufgebaut. Die > dürfte wohl ein frisch studierter Schulabgänger programimert haben. Ich > schließe mich diener Empfehlung vollumfänglich an. Das Gegenteil ist der Fall. Gerade die UARTs funktionieren hervorragend mit HAL. Man muss es nur einmal verstehen. Hier habe ich gezeigt, wie man das macht: Beitrag "[STM32/HAL] simples U(S)ART-Library"
Jens R. schrieb: > HAL_UART_Transmit(uart, out, 3, 100); > > HAL_UART_Receive(uart, in, 3); Ohne es wirklich ausprobiert zu haben: das sollte so nicht funktionieren da der UART keine 3 Bytes puffern kann wenn 3 Bytes gesendet wurden. Da müsste mindestens ein Receive- Interrupthandler implementiert sein .....
Wastl schrieb: > Da müsste mindestens ein Receive- > Interrupthandler implementiert sein Hätte ja sein, daß das ein anständiger HAL-Treiber macht ...
Wastl schrieb: > Da müsste mindestens ein Receive- > Interrupthandler implementiert sein ..... So ist es! Genau deshalb gibt es HAL_UART_ReceiveIT
Ich sehe gerade dass beim Generieren des UART Codes mit HAL ein Interrupt-Handler installiert wird (werden kann) der von <stm32f1xx_it.c> auf die ausführliche Behandlung in <stm32f1xx_hal_uart.c> springt. Damit sollte dann auch die lückenlose Abarbeitung von empfangenen Daten abgedeckt sein (was ich in diesem HAL Wust nicht überprüft habe). Mit HAL hat man sich zwar der Sorge entleigt den Empfang von Daten im Low-Level zu handlen aber das Ganze muss langsamer, umständlicher sein da die HAL-Implementierung eine ganze Menge von verschiedenen Fällen abdecken muss. Und der Code wird sicher auch umfangreicher sein als eine selbstgestrickte LL-Implementierung.
Wastl schrieb: > Ich sehe gerade dass beim Generieren des UART Codes mit HAL > ein Interrupt-Handler installiert wird Schau dir doch einfach meinen Code mal an! Wastl schrieb: > Und der Code > wird sicher auch umfangreicher sein als eine selbstgestrickte > LL-Implementierung. Die Anzahl der CodeZeilen hat rein gar nichts mit der Grösse des generierten Binärcode zu tun. Ich glaube kaum, daß du das händisch wirklich deutlich kleiner hinbekommst, aber ganz sicher wird es deutlich unflexibler. Ich hatte auch mit höheren Baudraten (>1Mbit) nie Probleme mit dem HAL-Code. Mag sein, daß du mit Nutzung der LL-Funktionen nochmal 20% im Binärcode einsparen kannst, aber das kann man bei der gesamten Grösse des UART-Code (ca. 1-2 kByte) eigentlich vernachlässigen. Der Code für die Ringbuffer -den man praktisch immer zusätzlich braucht- ist meist genauso groß oder grösser als der HAL-Code für die Grundfunktionen.
:
Bearbeitet durch User
Wie gesagt, wahrscheinlich wäre die Funktion HAL_USART_TransmitReceive() genau das was ich bräuchte aber die HAL_USART*-Funktionen scheinen für den STM32F103 nicht wirklich zu existieren. .. Insofern probier ichs dann wohl doch Low Level.. @Harry, Steve danke für die Links, ich schau da gerade mal rein... Ich mein, auf dem AVR hätt ich das in 2 Minuten gebaut.. auf ARM bin ich halt noch recht neu..
Jens R. schrieb: > Ich mein, auf dem AVR hätt ich das in 2 Minuten gebaut. Auf dem AVR hättest du dich auch um das Puffern durch Interrupt-Receive-Handling kümmern müssen. Wenn du schon HAL verwendest dann muss das auch berücksichtigt werden.
Soo, ich hab jetzt tatsächlich einfach nur die Register beschrieben und gelesen, das tut auch. Jaaa, man müsste eiiiigentlich mehr machen aber es geht hier lediglich um den Test der angeschlossenen Peripherie, was ca. ein Mal passiert. Da will ich nicht noch mehr Zeit investieren.. Hier mal meine Lösung: > uint32_t uart_txrx(UART_HandleTypeDef *uart, uint8_t data) { > /** > * Sendet und empfängt ein Byte. Der Empfangene Wert wird > * auf voller Registerbreite zurück gegeben. > */ > //HAL_UART_Transmit(uart, &data, 1, 100); > if (__HAL_UART_GET_FLAG(uart, UART_FLAG_RXNE)) { > // leere das RX-Register > uint8_t x = 0; > x = uart->Instance->DR - x; > } > // sende sowie die Leitung frei ist > while (!__HAL_UART_GET_FLAG(uart, UART_FLAG_TXE)); > uart->Instance->DR = data; > // empfange Daten > while (!__HAL_UART_GET_FLAG(uart, UART_FLAG_RXNE)); > return uart->Instance->DR; > } Grundsätzlich ist das Leeren des Datenregisters wahrscheinlich nicht notwendig aber so bin ich sicher, keine Halbwahrheiten zu empfangen.
:
Bearbeitet durch User
das ist keine Lösung sondern Murks. Du möchtest Voll Duplex, aber programmierst Halb Duplex. Wenn während des Sendens schon empfangen werden soll, dann muss der Empfang vorher gestartet werden, und für mehrere Zeichen müssen die dann gepuffert werden. Jetzt funktioniert es vielleicht, aber mit kritischem Timing. Die Peripherie im Cortex-M ist asynchron am Bus, das Senden erfolgt also eher mit Glück spät genug nach dem Beschreiben des Registers. Ein UART_TransmitReceive ist Unfug beim UART, das es das nicht als Basisfunktion gibt ist keine Schwäche der HAL. So eine Funktion gibt es nicht mal beim H7 obwohl der Hardware Fifos hat. Gleichzeitiges Senden und Empfangen gibt es nur beim SPI weil das ein Schieberegister hat, ein UART arbeitet komplett anders. Richtige Lösungen wurden mit einer Fifo Implementierung im Interrupt schon genannt, oder DMA wenn es größere Datenblöcke sind. DMA hat dann eine geringere Interruptlast. HAL macht die Nutzung von Interrupt und DMA einfach und die Funktionen haben einfach ein _IT oder _DMA als Suffix, einheitlich bei allen Schnittstellen. Und da muss man sich nicht um einen Interrupthandler kümmern, sondern einen Callback implementieren. HAL wertet auch Fehler aus, deshalb ist der ISR Code aufwändiger. Aber Fehlerbehandlung scheint bei vielen hier ja verpönt zu sein.
J. S. schrieb: > Aber Fehlerbehandlung scheint bei vielen hier ja verpönt zu > sein. Hier gelten die 3 goldenen Programmierer-Regeln: * im vollen Bewusstsein, daß man es sowieso besser kann niemals schauen, wie andere das Problem gelöst haben * erst optimieren - dann programmieren * Flash niemals zu mehr als 20% füllen
@J. S.: An dieser Stelle ist das Timing gar nicht mal so kritisch. Es laufen keine Interrupts die stören könnten und auch sonst tut die Maschine an dieser Stelle nicht wirklich irgendwas. Insofern leere ich das Empfangsregister, beschreibe das Senderegister und warte dann, dass das Empfangsregister beschrieben wurde. Was soll da schief gehen? Theoreeetisch könnte ich vorher noch warten bis der Sendevorgang abgeschlossen ist. Da aber tatsächlich für diesen Fall eine Brücke zwischen Sende- und Empfangspin liegen muss können maximal eine defekte Hardware oder kosmische Bits (aka defekte Hardware) das System stören. Ja, die Lösung ist unelegant- und mir tun unelegante Lösungen auch weh.. aaaber sie funktioniert für den aktuellen Fall besser als alles was ich bisher probiert habe. > Ein UART_TransmitReceive ist Unfug beim UART, das es das nicht als > Basisfunktion gibt ist keine Schwäche der HAL. Es gibt ein USART_TransmitReceive. Zumindest bietet mir die Autovervollständigung von CubeMX das an und eigentlich ist der C-Parser hinter Eclipse doch recht zuverlässig.
Jens R. schrieb: > Es gibt ein USART_TransmitReceive. Zumindest bietet mir die > Autovervollständigung von CubeMX das an Ich kann mir bei bestem Willen nicht vorstellen, wozu das gut sein sollte, und habe auch noch niemals irgendwo Code gesehen, in dem das verwendet wurde. Ohne Interrupts ist das Alles sowieso einfach nur ganz grosser Murks.
Die Diskussion darfst du gern allein weiter führen. Ich werfe noch ein, dass der DMA wirklich viiiiiiiel tollerer ist als Interrupts.. ;)
Prima, daß du meine These bestätigst! Harry L. schrieb: > * im vollen Bewusstsein, daß man es sowieso besser kann niemals > schauen, wie andere das Problem gelöst haben
Jens R. schrieb: > aaaber sie funktioniert für den aktuellen Fall besser als alles was ich > bisher probiert habe. der signifikante Unterschied ist das jetzt nur ein Zeichen gesendet und wieder empfangen wird, im ersten Code waren es drei. Bei den drei Zeichen ist es Abhängig von der Bitrate und Laufzeit welches Zeichen erwischt wird, der UART liefert nur das zuletzt empfangene. Jens R. schrieb: > Es gibt ein USART_TransmitReceive. ja, gibt es für USART tatsächlich. Aber diese schreibt/liest in einer loop genauso nur jeweils 1 Zeichen. Dann sollte man das device auch als u_s_art mit einer Leitung für den synchronen Takt konfigurieren, sonst macht das auch keinen Sinn. Jens R. schrieb: > eigentlich ist der C-Parser > hinter Eclipse doch recht zuverlässig. nur eigentlich, beim analysieren von bedingtem Code ist der nicht perfekt, also wertet defines nicht in der richtigen Reihenfolge aus und zeigt damit nicht korrekt an. Besser ist die compile_commands.json vom Compiler zu nutzen, aber bis CubeMX CMake richtig unterstützt dauert es wohl noch ein bisschen.
:
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.