Hallo und Frohe Weihnachten! Ich versuche gerade mich in STMCubeMX & Co einzuarbeiten und optimal bzw. entsprechend der dahinter liegenden Philosophie zu nutzen. Man hat ja oft folgende Tasks in der while-Schleife in main(): 1. Empfange etwas per UART (variable Länge) 2. Verarbeite die empfangenen Daten 3. Sende irgendetwas zurück (oder an eine andere Schnittstelle) 4. Andere wichtige Dinge Der Empfang mit HAL_Uart_Receive() macht hier keinen Sinn, da es blockiert, bis Daten kommen. Dann fällt 4. hinten runter. Beim Empfang mit HAL_Uart_Receive_IT() wird direkt in den Puffer geschrieben, aber ich weiß nicht - ob überhaupt etwas empfangen wurde, - an welche Stelle im Puffer gerade geschrieben wird, - ob die Sendung beendet wurde (z.B. Zeilenende). Dazu müsste ich ja vorher bereits wissen, wie viele Zeichen empfangen werden sollen. Wie löst man das am besten und innerhalb der Philosophie der HAL? A: In main() mit HAL_UART_GetState prüfen, ob HAL_UART_STATE_BUSY_RX nicht mehr gesetzt ist. Dann erst RxPuffer lesen/kopieren und HAL_Uart_Receive_IT() neu anwerfen. => Ich muss immer noch wissen, wie viele Bytes da kommen sollen. Sonst werden empfangene Daten nicht gelesen, bevor der Puffer voll ist. Immerhin wird der Rest der while Schleife (4.) ausgeführt. B: Empfangspuffer der Größe 1, und HAL_USART_RxCpltCallback() schaufelt jedes empfangene Byte in einen Ringpuffer und startet HAL_Uart_Receive_IT() neu. Wird ein "end of transfer" Zeichen erkannt, wird ein globales Flag gesetzt. => Das hieße ja nichts anderes als "Die HAL Implementierung des Puffers ist Käse. Mach Dir Deine eigene." Und wirklich schlank ist das dann auch nicht, was da alles während der Interrupt-Routine ausgeführt würde... C: Vergiss HAL, nutze libopencm3, ChibiOS, ... Oder denke ich zu kompliziert?
STM32-Einsteiger schrieb im Beitrag #6085897: > Oder denke ich zu kompliziert? Nee, Variante C zeigt in die richtige Richtung. Schreibe dir Lowlevel-Treiber für deine UART's, die den Datenverkehr per Interrupt erledigen und die Daten zwischenspeichern. Und die ein gut zu benutzendes Interface für die höheren Schichten deiner Firmware haben, so daß du dich außerhalb des Treibers nicht um dessen Hardware-Angelegenheiten kümmern mußt. Lies mal da, um einen Eindruck zu kriegen, wie sowas geht: https://www.mikrocontroller.net/attachment/316790/STM32F103C8T6.ZIP Im Prinzip hast du ja in main immer eine Grundschleife, in der sich der µC dreht, wenn es sonst nix zu tun gibt. Also etwa so: immerzu: mach dies mach das wenn X dann mach Y usw. goto immerzu Guck dir im Beispiel dazu mal in cmd.c die Funktion Talk(word wo) an. Die testet mit if (RxAvail(wo)), ob ein Zeichen auf "wo" (UART1 oder UART2 oder sonst ein serieller Kanal) eingetrudelt ist und wenn ja, dann wird das Zeichen abgeholt und verarbeitet. Alternativ wird einfach die Funktion beendet. So im Prinzip wird nichtblockierend geschrieben, so daß man eben nicht auf irgendwas wartend auf der Stelle trampelt, sondern zwischenzeitlich was anderes mit seiner Prozessorzeit machen kann. W.S.
W.S. schrieb: > Guck dir im Beispiel dazu mal in cmd.c die Funktion Talk(word wo) an. > Die testet mit if (RxAvail(wo)), ob ein Zeichen auf "wo" (UART1 oder > UART2 oder sonst ein serieller Kanal) eingetrudelt ist und wenn ja, dann > wird das Zeichen abgeholt und verarbeitet. Hallo W.S. und danke für das Code-Beispiel. Meine eigenen Routinen sehen so ähnlich aus. Nur wie löst man das am besten mit und innerhalb der STM32Cube HAL? Irgendetwas muss sich ja irgendjemand dabei gedacht haben, als er das Zeugs geschrieben hat. Und sehr wahrscheinlich war er dabei auch nicht alleine sondern Teil eines Teams von (embedded) Software-Entwicklern. Ich kann mir jedenfalls nicht vorstellen, dass STM diese Aufgabe einem Hardwareentwickler übertragen hat, weil der zufällig etwas BASIC konnte und deshalb bei seinen Kollegen als "der Programmierer" galt. ;-) Wenn ich Dein Beispiel noch einmal auf die HAL übertrage, dann ähnelt es B: Empfangspuffer für HAL_Uart_Receive_IT() der Größe 1, und HAL_USART_RxCpltCallback() schaufelt jedes empfangene Byte in einen größeren Ringpuffer und startet HAL_Uart_Receive_IT() neu. Die Hauptschleife schaut dann nach, ob etwas im Ringpuffer ist. OK - aber damit "neutralisiere" ich den RxBuffer der HAL, lege meinen eigenen an und schreibe damit einen Teil der Funktionen des HAL IRQHandlers neu. Was irgendwie zart andeutet, dass der HAL Puffer und IRQHandler eine Fehlkonstruktion sind. Und den Umweg UART->DR -> HAL Puffer -> Ringbuffer kann der Compiler noch nicht einmal wegoptimieren. Hmmm - ich könnte den WritePointer des Ringpuffers direkt an HAL_Uart_Receive_IT() übergeben (nach Check, dass der Puffer noch Platz hat). Das eliminiert einen überflüssigen Puffer. Aber trotzdem muss für jedes Byte dann immer noch die ganze Mimik mit Interrupts an/aus/wieder an durchlaufen werden. Und wenn ich HAL_Uart_Receive_IT() nicht in der HAL_USART_RxCpltCallback() sondern erst in der Hauptschleife wieder anwerfe, könnten Daten verloren gehen.
Was willst Du übertragen? Eine Textzeile mit Zeilenende Zeichen, oder beliebige Daten? Der erste Fall ist ganz einfach: -in HAL_UART_RxCpltCallback auf Endzeichen testen, falls nicht, Zeichen in den Puffer, wenn Zeilenende -> Funktion machwasmitdenDaten -braucht keine ständige Kontrolle des Puffer Inhalts, nicht einmal einen Ringpuffer -in der main.c mit wenigen Zeilen erledigt Auf Wunsch zeige ich dir meine Version.
STM32-Einsteiger schrieb im Beitrag #6086194: > Nur wie löst man das am > besten mit und innerhalb der STM32Cube HAL? > Irgendetwas muss sich ja irgendjemand dabei gedacht haben, als er das > Zeugs geschrieben hat. Das ist eben das Problem mit der HAL, sie ist nur sehr knapp dokumentiert.
pegel schrieb: > Der erste Fall ist ganz einfach: > -in HAL_UART_RxCpltCallback auf Endzeichen testen, falls nicht, Zeichen > in den Puffer, wenn Zeilenende -> Funktion machwasmitdenDaten > -braucht keine ständige Kontrolle des Puffer Inhalts, nicht einmal einen > Ringpuffer > -in der main.c mit wenigen Zeilen erledigt OK. Die Funktion machwasmitdenDaten() würde ich gerne in der Hauptschleife lassen. Die Callback Funktion hätte ja so schon einiges zu tun und hält den IRQHandler auf. Da HAL_UART_RxCpltCallback() nur bei RxXferCount == 0 aufgerufen wird, muss also byteweise empfangen werden mit HAL_UART_Receive_IT(huart1, buffer, 1) In der HAL_UART_RxCpltCallback() könnte man dann den buffer Zeiger inkrementieren und mit HAL_UART_Receive_IT(huart1, buffer, 1) das nächste Byte holen lassen. Es sei denn man hat eol. Dann müsste man den buffer erst irgendwo sichern, die Hauptschleife informieren, den Zeiger auf Anfang vom buffer zurück setzen und dann HAL_UART_Receive_IT(huart1, buffer, 1) wieder anwerfen. - Also alles wieder rückgängig machen, was der HAL IRQHandler gerade erst gemacht hat, bevor er HAL_UART_RxCpltCallback() aufruft. (Interrupts an/aus usw.) Das "fühlt" sich ineffizient an. pegel schrieb: > Auf Wunsch zeige ich dir meine Version. Na, aber immer doch. Es ist doch Weihnachten, da darf man sich was wünschen. ;-)
Stefan ⛄ F. schrieb: > Das ist eben das Problem mit der HAL, sie ist nur sehr knapp > dokumentiert. 1165 Seiten würde ich nicht knapp nennen. ;-) Die neuen Funktionen Register/Unregister der Callbacks sind noch nicht einmal drin. Dabei habe ich die Doku erst vor zwei Tagen heruntergeladen. pegel schrieb: > Dafür liefern sie aber zu jeder Funktion gute Beispiele mit. Beispiele ja, aber viel mit blocking delays. Warum warte ich in einem Beispiel für non-blocking Transfer anschließend mit
1 | while (UartReady != SET) |
2 | {
|
3 | }
|
darauf, dass der Kram auch ankommt? Und sollte der Empfänger mehr Bytes erwarten als er bekommt, wartet er (blockierend) ewig. (STM32F103RB-Nucleo/Examples/UART/UART_TwoBoards_ComIT/)
STM32-Einsteiger schrieb im Beitrag #6086306: > 1165 Seiten würde ich nicht knapp nennen. ;-) Für das was sie enthält ist das viel zu wenig Doku. Wenn das PDF 20.000 Seiten hätte, würde es Anfänger abschrecken. Mir wäre das egal, die dürfen bei Arduino bleiben, wenn sie wollen.
Im Anhang meine Version für ein Nucleo-F746 SART3. Eine Text-Zeile wird empfangen und bei Zeilenende als Kleinbuchstaben zurück geschickt.
Die HAL ist nicht knapp dokumentiert. Es ist nur nicht so einfach das richtige Dokument zu finden: https://www.st.com/resource/en/user_manual/dm00154093.pdf
STM32-Einsteiger schrieb im Beitrag #6086194: > Nur wie löst man das am > besten mit und innerhalb der STM32Cube HAL? > Irgendetwas muss sich ja irgendjemand dabei gedacht haben, als er das > Zeugs geschrieben hat. Und sehr wahrscheinlich war er dabei auch nicht > alleine sondern Teil eines Teams von (embedded) Software-Entwicklern. Erstens: man löst das Problem, indem man Cube und HAL einfach aus dieser Sache heraushält. Der LL Treiber serial.c im Beispiel braucht lediglich die HW-Registeradressen laut Refmanual und sonst nix - naja außer der Erklärung was ein Byte ist und so. Alternativ Cube und HAL komplett rausschmeißen. Man erweist sich mir diesem Zeugs auf lange Sicht nur einen Bärendienst. Zweitens: Was sich die Leute dabei gedacht haben? Antwort: HAL wird gebraucht, damit Cube unumgänglich ist. Und Cube wird gebraucht, um dich mit nem Ring durch die Nase an ST's Galeere festzunageln. Mal drastisch ausgedrückt. Ja, man kann sowas dezenter sagen, aber schlußendlich ist es dasselbe. Mit sowas landen dann Bezüge auf herstellerspezifisches Zeugs selbst in main.c und wer sich auf sowas einläßt, hat sich damit selbst festgenagelt. ST ist mit sowas nicht allein, bei Infineon ist es Dave, NXP hat auch seine eigenen Nasenringe vorrätig - es ist in jedem Falle dieselbe Strategie: Anwender von der bei Cortexen ziemlich einheitlichen HW fernhalten und stattdessen an eine herstellerspezifische Softwareschicht gewöhnen, die zwar keinerlei HW-Abstraktion bietet, dafür aber eine feste Kundenbindung bewirkt. Und selbst bei reinen Softwarebuden trifft mal auf sowas. Guck dir mal das an: Beitrag "Makefiles auf Linux für STM32" Da haben sich Leute auf Chibi eingelassen - mit dem Ergebnis, daß ihr Projekt für wirklich alle Leute nutzlos ist, die nicht die exakt gleiche IDE/Toolchain benutzen. Sieht Portabilität so etwa aus? Wohl nicht. W.S.
Harry L. schrieb: > Ich hab dir mal ein funktionierendes Beispiel mit HAL angehängt. Was soll das? Das sind 4.3 Megabyte an Zeugs und es ist kein wirklich funktionierendes Beispiel. Da fehlt es wirklich an allen Ecken und Enden. In meinem Beispiel von ca. 460 K ist eine komplette Firmware dabei, mit Kommandoprozessor und Kommunikation per Seriell und USB, mit Event-Verwaltung, System-Uhr und selbst den zugehörigen Leiterplatten-Dateien für zwei alternative Hardware-Versionen. W.S.
Beitrag #6086614 wurde von einem Moderator gelöscht.
Beitrag #6086634 wurde von einem Moderator gelöscht.
Ja, völlig überbewertet diese Portabilität. USB mit HAL läuft zwar auf L0..H7, aber ich gebe meinen Registern lieber meine eigenen Namen und mache auf die Software anderer einen großen Haufen. Das ist Fortschritt, nur so komme ich weiter. Speicher wird ja immer knapper und teurer bei aktuellen μC, da ist Sparsamkeit die oberste Maxime. OS sind totaler Mist und bei μC völlig überdimensioniert. Prost. Hersteller‘hörigkeit‘: ja, verpönt. Damals, bei den 8051er Derivaten. Weil der eine war schnell, der andere hatte viele serielle, ein wieder anderer I2C. Heute: ST hat alles. NXP auch und viele andere auch. Überhaupt kein Grund mehr die Hunde aus verschiedenen Dörfern zusammenzusuchen.
Beitrag #6086644 wurde von einem Moderator gelöscht.
Guest schrieb im Beitrag #6086644: > Die bekommen eher mehr als weniger Speicher und billiger werden sie auch > :O Echt jetzt? Habe ich in den letzten 30 Jahren tatsächlich was verpasst?
Johannes S. schrieb: > Echt jetzt? Habe ich in den letzten 30 Jahren tatsächlich was verpasst? Anscheinend :D Ich meine µC mit 1MB RAM und 2MB Flash sind jetzt echt keine Seltenheit und kosten nicht gerade ein Vermögen. Selbst wenn man mal etwas tiefer greift und mal 192 oder 320 KB RAM annimmt. Wenn ich da an so manchen Atmega mit 2KB denke ;)
Dieter schrieb: > Wenn ich da > an so manchen Atmega mit 2KB denke ;) Denk ruhig. Der leistet damit -effizient programmiert- oft das Gleiche!
Richard schrieb: > Denk ruhig. Der leistet damit -effizient programmiert- oft das Gleiche! Geht jetzt hier wieder ein Glaubenskrieg los? Effizient programmieren ist nicht nur ein möglichst kleines Programm zu haben. Es kommt doch immer auf die Anwendung an. Wenn ich große Datenmengen verarbeite brauche ich halt mehr Speicher das ist eben so und die meisten µC die es mittlerweile gibt haben doch wirklich genug davon. Das ist doch das gleiche zu sagen ich Bitbange jetzt mein UART weil ich das schon immer so gemacht habe obwohl mein µC 4 UART besitzt. Warum soll man sich den Stress antun auf jedes Byte achten zu müssen wenn der µC für unwesentlich mehr Geld sowieso genug Speicher hat. Ich meine ok, wenn du jetzt Millionenstückzahlen produzierst bei denen es sich lohnt 50 Cent zu sparen lass ich mir das noch gefallen aber grade für den Hobby Mensch oder fürs Prototyping ist das wirklich kein Grund mehr. Das ist das gleiche mit der HAL natürlich kann ich darauf beharren das alles selber zu machen besser ist. Und das mag auch Teilweise weniger Overhead haben. Aber sind wir mal ehrlich, wenn man nur mit STM arbeitet und alle 2 Wochen was anderes auf dem Tisch hat und irgendeine neue Hardware des µC verwendet dann ist es grade für die Entwicklung wirklich praktisch. Und auch als Hobby Programmierer ist das sehr dankbar, da man fürs erste, schnell Ergebnisse erzielt. Besser und alles auf LL ebene selber machen kann man im Anschluss immer noch. Im Übrigen bietet ST für so ziemlich alle Peripherie Beispiele für die HAL.
Guest schrieb: > Und auch als Hobby Programmierer ist das sehr dankbar, da man > fürs erste, schnell Ergebnisse erzielt. Um schnelle Ergebnisse zu erzielen wollen Abstrahier-Monster wie die HAL in ihrer Philosophie erst einmal selbst durchdrungen werden. Man sieht es ja an Hilfe-Rufen wie die des TO hier. Und stellt sich der Erfolg "fürs erste" ein sieht man dann auf den zweiten Blick, wieviel umständlicher und aufgeblasener die HAL Lösung letztlich ist. Unter dem Strich hätte man lieber gleich lernen sollen, die MCU samt Peripherie zu verstehen und direkt anzusprechen. Dann plötzlich hätte oh Wunder der Aufgabe überraschenderweise oft auch ein ATMega gelangt...
Richard schrieb: > Man sieht > es ja an Hilfe-Rufen wie die des TO hier. Ganz ehrlich es gibt nichts Einfacheres als mit der HAL_Uart_Recive_IT irgendwas zu empfangen. Im Callback schiebt man das empfangene Byte in einen Puffer und benutzt einen scheiß Pointer um die Position zu markieren. Das Ende der Nachricht kann man dann entweder durch Prüfen eines bestimmten Patterns, durch eine vorgegebene Länge, oder durch einen Empfangstimeout mit einem Timer. Danach kann man den String verarbeiten.
Um wieder aufs Thema zurückzukommen, die HAL ist an dieser (und auch an anderen Stellen) leider murks. Lustigerweise durchläuft fast jeder, der mit den STMs und UART arbeiten will bzw. muss folgenden Zyklus: -"Ich möchte Daten unbestimmter Länge empfangen, aber nicht ewig blocken wenn doch nicht alles da ist" -Versuch mit dem HAL im blocking mode -Versuch mit der HAL im interrupt mode und 1 byte buffer -Aufgeben und selber schreiben im IRQ-Handler Hier sieht man ein brauchbares Beispiel: https://blog.the78mole.de/stm32-uart-continuous-receive-with-interrupt/ been there. done that.
Transmitbuffer schrieb: > Um wieder aufs Thema zurückzukommen, die HAL ist an > dieser (und auch an anderen Stellen) leider murks. Was ist daran murks. Man scheibt seinen IRQ Handler im receive Callback und schiebt seine Daten in den Puffer. Wenn man das Terminationszeichen empfängt oder was weiß ich man als Endbedingung haben möchte, setzt man eine Flag und verarbeitet den String. Das sind, wenn man es ganz billig anstellt vielleicht 5 Zeilen Code plus das was die String Verarbeitung am Ende braucht.
@pegel: Danke für das Code-Beispiel. Ich hatte Dich also richtig verstanden. Harry L. schrieb: > Ich hab dir mal ein funktionierendes Beispiel mit HAL angehängt. Auch an Dich ein Dankeschön. Auch bei Dir passiert allerdings einiges in der ISR (bzw. im Callback, was ja dasselbe ist), und ich habe mal gelernt, dass man die ISR so kurz wie möglich halten soll. Nun muss man ja an altem Gelernten nicht religiös festhalten, und die Cortex-M haben ja auch einen State "Active and pending" für Exceptions, d.h. es ist (fast) egal, ob dieser Code in der ISR oder in main ausgeführt wird. Immerhin weiß man in der ISR wenigestens, dass tatsächlich ein Byte angekommen ist. Aber irgendwie bleibt ein "schlechtes Gewissen". ;-) Martin schrieb: > Ganz ehrlich es gibt nichts Einfacheres als mit der HAL_Uart_Recive_IT > irgendwas zu empfangen. Im Callback schiebt man das empfangene Byte in > einen Puffer und benutzt einen scheiß Pointer um die Position zu > markieren. Also meine Lösung B. Den HAL Puffer "neutralisieren", weil der Mist ist. Transmitbuffer schrieb: > die HAL ist an > dieser (und auch an anderen Stellen) leider murks. > > Lustigerweise durchläuft fast jeder, der mit den STMs > und UART arbeiten will bzw. muss folgenden Zyklus: Vielen Dank für die Bestätigung. Ich hatte schon die Befürchtung, ich übersehe etwas Wesentliches...
Zu dem Streit "Abstraktion oder nicht", den ich hier unabsichtlich vom Zaun gebrochen habe: Natürlich ist Portabilität schön. Wenn ich feststelle, dass dem F0, den ich gewählt habe, doch irgendetwas fehlt, was der F1 hätte, dann freue ich mich, wenn ich so einfach wechseln kann. Portabilität habe ich aber mit libopencm3 oer ChibiOS auch. Natürlich ist es auch schön, wenn ich mir mit der Maus ein fertig initialisiertes, lauffähiges System zusammenklicken und einfach anfangen kann, ohne erst sämtliche RMs und PMs auswendig gelernt zu haben. Man kann sich aber mit ein paar Klicks auch kräftig in den Fuß schießen und weiß dann nicht, was eigentlich passiert ist. So habe ich mich gestern beinahe ausgesperrt: Ich habe einen der SWD-Pins versehentlich deaktiviert und zwar gleich wieder aktiviert - aber da waren beide nur noch gelb, da jetzt Debug = No Debug in "SYS Mode and Configuration" gewählt war. Ich hab's nicht gesehen oder nicht gleich begriffen - und schon lies sich der kleine Kerl nur noch mit Klimmzügen über OpenOCD programmieren. War aber lehrreich... ;-)
Harry L. schrieb im Beitrag #6086634: > W.S. schrieb: >> Harry L. schrieb: >>> Ich hab dir mal ein funktionierendes Beispiel mit HAL angehängt. >> >> Was soll das? Das sind 4.3 Megabyte an Zeugs und es ist kein wirklich >> funktionierendes Beispiel. Da fehlt es wirklich an allen Ecken und >> Enden. > > You made my day... > > Du bist einfach ein verbitterter aler Sack, der schon lange die > Verbindung zuR Lebenswirklichkeit verloremn hat, und daher hab ch hab > nicht das geringste Interesse daran, mit dir zu diskutieren. Danke für die Zusammenfassung Harry, dann muss ich das diesmal nicht machen ;) Im Vergleich zu seiner 80er Jahre Programmierung mit Magic Numbers und für UART 1-5 denselben Code kopieren. Dagegen ist der HAL doch echt ein Segen! Aber in der Realität sollste man sich irgendwo dzwischen aufhalten.
:
Bearbeitet durch User
Mw E. schrieb: >> Du bist einfach ein verbitterter aler Sack, der schon lange die >> Verbindung zuR Lebenswirklichkeit verloremn hat, und daher hab ch hab >> nicht das geringste Interesse daran, mit dir zu diskutieren. > > Danke für die Zusammenfassung Harry, dann muss ich das diesmal nicht > machen ;) Ah, von den Stinkstiefeln gibt es einen rechten und einen linken. Trotzdem hinkt der Läufer. Transmitbuffer schrieb: > Hier sieht man ein brauchbares Beispiel: > https://blog.the78mole.de/stm32-uart-continuous-receive-with-interrupt/ Wie krank ist das denn? Einen IRQ-Handler allein mit HAL-Funktionen zu schreiben? Da schreibt man doch gleich direkt die paar Zugriffe auf USARTx-Register. Die eierlegende Wollmilchsau hat diverse Gendefekte!
Immer die gleich HAL gut oder pfui Diskussion. Immer die gleiche Antwort dazu: Man kann auch mischen! Es verbietet einem niemand seine Register Befehle im HAL Grundgerüst zu benutzen. Wenn man dann möchte, kann man auch alle HAL Funktionen bis auf Registerebene einsehen und direkt "klauen". Also, wo genau ist das Problem?
pegel schrieb: > Man kann auch mischen! > Es verbietet einem niemand seine Register Befehle im HAL Grundgerüst zu > benutzen. Volle Zustimmung! Und das STM32 Grundgerüst von CubeMX zu nehmen, um die Takterzeugung transparent einzustellen, finde ich ebenfalls gut. Wenn das jemand anders sieht ist das allerdings kein Grund, persönlich beleidigend zu werden; auch nicht von angemeldeten Trollen.
pegel schrieb: > Also, wo genau ist das Problem? Das Problem besteht darin, daß gar viele Leute gern Programmierer sein wollen, obwohl sie mental dafür zu klein sind. Also lernen sie irgend etwas auswendig, was man ihnen mal vorgesetzt hat und halten sich eisern genau daran - ohne die Sinnhaftigkeit jemals zu hinterfragen. Das sind genau die richtigen Kunden für Cobe, HAL, XPresso, Dave und wie die alle heißen mögen. Es sind aber auch die gutgläubigen Anfänger, die da meinen, daß derartige Hersteller-Libs tatsächlich eine Hardware-Abstraktion seien und daß diese zu ihrem Wohl geschrieben seien. Nein, sind sie nicht. Und sie sind nicht einmal einfacher oder gar benutzerfreundlicher: Martin schrieb: > Ganz ehrlich es gibt nichts Einfacheres als mit der HAL_Uart_Recive_IT > irgendwas zu empfangen. Im Callback schiebt man das empfangene Byte in > einen Puffer und benutzt einen scheiß Pointer um die Position zu > markieren. Das Ende der Nachricht kann man dann entweder durch Prüfen > eines bestimmten Patterns, durch eine vorgegebene Länge, oder durch > einen Empfangstimeout mit einem Timer. Danach kann man den String > verarbeiten. Ach ja? Also ne Callback-Funktion, einen "scheiss Pointer", Pattern prüfen, mit vorgegebenen Längen und Empfangstimeout arbeiten? Sowas nennst du "nichts Einfacheres"? Und du meinst, sowas sei eine Hardware-Abstraktion? Lies mal das:
1 | char c; |
2 | |
3 | if (RxAvail(UART1)) |
4 | { c = GetChar(UART1); |
5 | Char_Out(c, UART1); |
6 | }
|
Bei sowas ist ne echte HW-Abstraktion dahinter. Das ist Code, der bei Vorhandensein ordentlicher LL-Treiber auf so ziemlich allen Plattformen läuft, für die es einen C Compiler gibt. Nochwas: Gerade bei UART's mit vorgegebenen Längen oder Timeouts arbeiten zu wollen, ist eine ausgesprochen dämliche Idee. Es ist nämlich immer ein Spiel zwischen zwei unabhängigen Geräten. W.S.
Guest schrieb: > Was ist daran murks. Man scheibt seinen IRQ Handler im receive Callback > und schiebt seine Daten in den Puffer. Murks ist daran, - dass ich einen eigenen IRQ Handler schreiben muss, obwohl die HAL schon einen implementiert. - dass ich einen Teil dessen, was der HAL IRQHandler macht, anschließend wieder neutralisieren muss. - dass aber der HAL IRQHandler trotzdem ausgeführt wird und ich ihn nicht einfach überladen kann (solange ich CubeMX benutze). Hier haben sich ein paar Leute (auch bei STM) ein paar mehr Gedanken zu dem Problem gemacht: https://stm32f4-discovery.net/2017/07/stm32-tutorial-efficiently-receive-uart-data-using-dma/ https://github.com/MaJerle/stm32-usart-dma-rx-tx https://github.com/akospasztor/stm32-dma-uart pegel schrieb: > Man kann auch mischen! > Es verbietet einem niemand seine Register Befehle im HAL Grundgerüst zu > benutzen. Ja, kann man. Man kann den autogenerierten Code ja einfach als Ausgangsbasis nehmen und dann verwenden oder auch nicht. Oder einfach ändern. Solange man CubeMX benutzt, unterliegt man aber gewissen Einschränkungen. Daher wollte ich einfach wissen, wie man das Problem UART Empfang variabler Länge am besten und innerhalb der Philosophie der HAL und CubeMX löst. Gans Gebraten schrieb: > Wenn das jemand anders sieht ist das allerdings kein Grund, persönlich > beleidigend zu werden Volle Zustimmung. Zumal es bei so einer offenen Frage ja nicht um "Ja oder Nein" geht sondern darum, verschiedene Sichtweisen zu einem Problem zu sammeln. Davon profitieren doch alle Forumsteilnehmer viel mehr als von "Meine Meinung ist die einzig Richtige. Es darf nur eine geben!" Am Ende kann sich jeder das aussuchen, was zu seinem Projekt und zu seinen Bedürfnissen am besten passt.
W.S. schrieb: > Gerade bei UART's mit vorgegebenen Längen oder Timeouts arbeiten zu > wollen, ist eine ausgesprochen dämliche Idee. Es ist nämlich immer ein > Spiel zwischen zwei unabhängigen Geräten. Achsooo! Die Leute von Modbus haben keine Ahnung von dem was sie tuen, weil sie Timeouts definiert haben! W.S. schrieb: > Das Problem besteht darin, daß gar viele Leute gern Programmierer sein > wollen, obwohl sie mental dafür zu klein sind. Meinste dich selbst?
STM32-Einsteiger schrieb im Beitrag #6085897: > C: Vergiss HAL, nutze libopencm3, ChibiOS, ... genau. Ich würde es so machen wie im Anhang. Ohne Codegenerator, ohne Unmengen generierter Kommentarblöcke die man nicht anrühren darf. Auf welchem Target es laufen soll sage ich im compile Aufruf, ohne alles wieder neu konfigurieren zu müssen.
Guest schrieb: > Das sind, wenn man es ganz billig > anstellt vielleicht 5 Zeilen Code plus das was die String Verarbeitung > am Ende braucht. Ja, mit HAL. Und ohne wären es auch nicht wesentlich mehr Zeilen.
Mw E. schrieb: > Die Leute von Modbus haben keine Ahnung von dem was sie tuen, > weil sie Timeouts definiert haben! Du verwechselst da eine konkrete Anwendung mit dem generischen (sein sollenden) Ansatz der HAL.
> Was ist daran murks es ist zumindest soviel Murks dass sie nur beim STM32 so gemacht wurde und beim STM8 ganz anders (um Resourcen zu sparen)
Hier mal eine HAL-konforme Lösung aus einem laufenden Projekt: Ich nutze DMA im zyklischen Modus zum Empfangen (und im Single Shot Modus zum Senden), konfiguriert in CubeMX mit Priorität auf Empfangen. Um das nach der Konfiguration in Gang zu stoßen reicht ein Aufruf von:
1 | HAL_UART_Receive_DMA(&huart2, uart_rx_buffer, UART_RX_BUFFER_SIZE); |
Durch Auslesen des DMA_CNDTRx Registers lässt sich die Position des zuletzt empfangenen Datenbytes im Buffer bestimmen (Buffergröße minus DMA_CNDTR, da dieses herunter zählt). Wer möchte kann da einen Ringbuffer (Siehe Anhang) drüber stülpen, DMA_CNDTR liefert wie gesagt sofort den Head-Index, während der Tail-Index beim Auslesen erhöht wird:
1 | // RBUF_modOptimized -> Modulo Operator optimiert für Cortex-M0 und kleine Werte |
2 | uart_rx_ringbuffer.head = RBUF_modOptimized(UART_RX_BUFFER_SIZE - hdma_usart2_rx.Instance->CNDTR, UART_RX_BUFFER_SIZE); |
3 | [...] |
4 | int32_t available = RBUF_getReadableSize(&uart_rx_ringbuffer); |
5 | [...] |
6 | // Wenn nötig Daten aus dem Ringbuffer auslesen um einen Überlauf zu verhindern... |
Das ist natürlich nicht mehr an den USART Interrupt gekoppelt, dafür läuft das Ganze vor sich hin ohne die CPU bei einzelnen empfangenen Bytes zu beanspruchen, man kann sich aussuchen wann und wie oft man den Zähler überprüft, halt den Anforderungen entsprechend so oft, dass nichts verloren geht. Das kann auch in einem Timer Interrupt gemacht werden, die Intervalldauer kann man gut anhand der Buffergröße und der UART Geschwindigkeit dimensionieren. Wer mit der zusätzlichen Latenz (zwei bis dreistelliger us-Bereich, je nach Abfrage-Intervall) leben kann, für den wäre dieser Ansatz eine Lösung. Ich würde dem TO wirklich empfehlen das Reference Manual dazu zu nehmen wenn er denn schon die HAL nutzt. Das ist wichtig um zu verstehen was da intern abgeht, man sollte es auch ohne HAL machen können und vor allem verstehen was jeder Aufruf für Operationen ausführt, ansonsten ist das ein gefährlicher Blindflug, egal welche Abstraktionsebene man nun nutzt.
Kleiner Nachtrag, die Verzögerung die durch das nicht Interrupt basierte Abarbeiten entsteht ist in meinem Fall ~28 us bei 48 MHz Takt. Der Windows VSerial-Treiber fügt da nochmal eine Millisekunde Latenz hinzu, da sieht man mal wo die Performance flöten geht...
Hallo Florian, danke für Deine Lösung. Inzwischen habe ich hier noch eine weitere Möglichkeit gefunden, die ebenfalls mit der HAL kompatibel ist und von CubeMX beim Update nicht platt gemacht wird: https://blog.ghmit.com.au/2019/07/simple-dynamic-length-uart-comms-with.html https://stm32f4-discovery.net/2017/07/stm32-tutorial-efficiently-receive-uart-data-using-dma/ https://github.com/MaJerle/stm32-usart-dma-rx-tx https://github.com/akospasztor/stm32-dma-uart Ich hatte mich schon geärgert, dass es den idle Interrupt zwar gibt aber er in der ganzen HAL nicht benutzt wird und dass man an den HAL_UART_IRQHandler nicht dran kann, aber meine Aussage von oben: STM32-Einsteiger schrieb im Beitrag #6086902: > - dass aber der HAL IRQHandler trotzdem ausgeführt wird und ich ihn > nicht einfach überladen kann (solange ich CubeMX benutze). war falsch. Tatsächlich kommt man eine Ebene vorher an alles heran, nämlich im USART1_IRQHandler. Dort könnte man den HAL_UART_IRQHandler sogar ganz ersetzen, zumindest aber ergänzen.
STM32-Einsteiger schrieb im Beitrag #6090147: > und dass man an den > HAL_UART_IRQHandler nicht dran kann, warum nicht? Vectortable ins Ram kopieren und mit NVIC_SetVector() mit eigenem überschreiben.
STM32-Einsteiger schrieb im Beitrag #6090147: > Ich hatte mich schon geärgert, dass es den idle Interrupt zwar gibt aber > er in der ganzen HAL nicht benutzt wird und dass man an den > HAL_UART_IRQHandler nicht dran kann, aber meine Aussage von oben: > STM32-Einsteiger schrieb im Beitrag #6086902: >> - dass aber der HAL IRQHandler trotzdem ausgeführt wird und ich ihn >> nicht einfach überladen kann (solange ich CubeMX benutze). > war falsch. > Tatsächlich kommt man eine Ebene vorher an alles heran, nämlich im > USART1_IRQHandler. Dort könnte man den HAL_UART_IRQHandler sogar ganz > ersetzen, zumindest aber ergänzen. Das ist doch vollkommener Blödsinn! Genau dafür gibt es die ganzen Callback-Funktionen, und die sind alle weak deklariert. D.h.: man kann die mit eigenen Funktionen überschreiben. Ich hab dir doch oben ein Beispiel mit HAL angehängt in dem genau das passiert: Beitrag "Re: STM32Cube HAL UART Einstieg" Da sieht man doch, wie das funktioniert. Ausserdem solltest du das HAL-Referenz-Manual mal genauer studieren!
:
Bearbeitet durch User
Harry L. schrieb: > Das ist doch vollkommener Blödsinn! > Genau dafür gibt es die ganzen Callback-Funktionen, und die sind alle > weak deklariert. Ja, genau. Die Callback-Funktion. Da gibt es genau eine, die hier interessant ist: HAL_UART_RxCpltCallback. Wann die aufgerufen wird, bestimmen der HAL_UART_IRQHandler und UART_Receive_IT. Wenn Dir das nicht passt, kannst Du das nicht ändern, denn die sind nicht weak. Deshalb rufst Du ja HAL_UART_Receive_IT immer mit Puffergröße 1 auf, damit für jedes einzelne popelige Byte der Interrupt getriggert wird und Du es mit Deiner langen Callbackfunktion bearbeiten kannst. Das kann man ja machen. Genau das war ja oben auch meine erste Idee B. Es geht aber auch anders. Nämlich mit DMA und ohne jedes Byte einzeln dreimal anzufassen. Das kann man doch in aller Ruhe und mit Freude zur Kenntnis nehmen, ganz ohne "Blödsinn" und andere Agressionen.
Dafür musst Du dann eben den Inhalt des Puffers und auch noch dessen Länge prüfen. Es kommt eben darauf an was man übertragen will. Hatten wir schon.
STM32-Einsteiger schrieb im Beitrag #6090277: > Deshalb rufst Du ja HAL_UART_Receive_IT immer mit Puffergröße 1 auf, > damit für jedes einzelne popelige Byte der Interrupt getriggert wird Ja, wie denn sonst, wenn ich nicht wissen kann, wann und wie viele Bytes kommen? STM32-Einsteiger schrieb im Beitrag #6090277: > Du es mit Deiner langen Callbackfunktion bearbeiten kannst. > Das kann man ja machen. Code lesen und verstehen sind 2 Dinge. Letzteres scheint dir nicht zu liegen... Was ist an der Funktion "lang"? STM32-Einsteiger schrieb im Beitrag #6090277: > Es geht aber auch anders. Nämlich mit DMA und ohne jedes Byte einzeln > dreimal anzufassen. Achso! Und der DMA erkennt auch, wann die Eingabe zu Ende ist usw.... Na, dann viel Spaß! Du mußst noch sehr, sehr viel lernen!
STM32-Einsteiger schrieb im Beitrag #6090277: > Es geht aber auch anders. Nämlich mit DMA und ohne jedes Byte einzeln > dreimal anzufassen. Unfug. Versuche doch bitte, wenigstens EINMAL logisch und von Grund auf zu denken. Du weißt hoffentlich, daß ein DMA nichts anderes kann, als Daten von A nach B zu transportieren. So ein DMA kann keine Entscheidungen fällen, kann keine Antworten über einen asynchronen Datenfluß geben und kann keinerlei Sendefluß steuern. Sowas alles mußt du in jedem Falle selbst mit der CPU erledigen. Genau deshalb ist das Verwenden von DMA beim USART herzlich sinnlos. Du muß trotz DMA jedes Byte zweimal anfassen. Für die Empfangsrichtung: Da mußt du in der ISR das Byte aus dem Rx-Register abholen und in deinen Ringpuffer stopfen. Dabei mußt du auch drauf achten, was du tun willst, falls kein Platz mehr im Ringpuffer ist. Das Ausdenken der Reaktion auf sowas kann dir niemand abnehmen. Außerhalb der ISR mußt du möglichst einfach feststellen können, ob ein Empfangsbyte vorliegt oder nicht. Die Bytes kommen nämlich nicht planbar, sondern asynchron und unplanbar herein. Und wenn was vorliegt, mußt du es auch möglichst einfach abholen können. Für die Senderichtung: Da mußt du in der ISR feststellen, ob es noch was zu senden gibt oder nicht. Wenn ja dann senden, wenn nicht dann mußt du den Senderequest der Hardware auf eine möglichst sinnvolle Weise abstellen - aber so, daß man ihn von außerhalb der ISR ohne Konurrenzprobleme wieder aktivieren kann. Außerhalb der ISR mußt du: - feststellen können, ob noch Platz ist im Ringpuffer. - Daten in den Ringpuffer schreiben und den HW-Senderequest aktivieren können - sinnvoll reagieren können, wenn der Sendepuffer noch voll ist. (das ist fast immer der Fall, da der µC regelmäßig schneller ist als eine Serielle). Das alles mußt du im Lowlevel-Treiber tun, ganz egal, ob du nun obendrein auch noch DMA benutzen willst oder nicht. Und deshalb ist der Overhead durch DMA eben so nützlich wie ein Kropf - nämlich garnicht. Was bleibt, ist die Frage, warum bloß du so insistierend auf HAL bestehen willst. Dieses Zeugs erledigt keine einzige der o.g. Aufgaben für dich, sondern erschwert selbige nur. W.S.
W.S. schrieb: > Was bleibt, ist die Frage, warum bloß du so insistierend auf HAL > bestehen willst. Die HAL verleitet zu der Annahme, dass man das Referenzhandbuch (mit den Registern und Beschreibung der I/O Funktionen) nicht braucht, weil sie ja alles abstrahiert. Wenn man sich als Anfänger mit den über 1000 Seite Doku herum schlagen muss, ist man damit erstmal genug belastet. Allerdings ist der Abstraktionsgrad der HAL nicht so hoch wie bei Arduino und weit von Betriebssystemen wie Linux/Windows/MacOS entfernt. Will sagen: Man muss zusätzlich zur HAL eben doch die Funktionseinheiten detailliert kennen, sonst kann man die HAL nicht korrekt anwenden. Solange ich nur eine einzige STM32 Mikrocontroller Serie (z.B. STM32F1) verwende, muss ich mich dann schon fragen, wo dann der Mehrwert der HAL ist. Warum soll ich zuerst den Chip und seine Register lernen, und dann oben drauf nochmal so viele Seiten zur HAl lesen? Macht auf den ersten Blick keinen Sinn. Zwei Gründe sprechen allerdings für die HAL: a) Sie enthält umfangreichen Code für einige Sachen, die man als Einzelkämpfer sonst nicht hinbekommen würde: zum Beispiel USB b) Wenn man auf eine andere STM32 Serie umsteigt, kann man weite Teile des Quelltextes unverändert übernehmen. Für a gibt es Alternativen (W.S. und Niklas Gürtler sei Dank), und b trifft auf viele Bastler schlicht nicht zu - mich zum Beispiel. Mir reicht die STM32F1/F3 Serie für alles, was ich machen will. Wenn die nicht mehr lieferbar sind, bin ich längst zu alt für was auch immer danach kommt (schätze ich). Jedem Anfänger empfehle ich allerdings, wenigstens einen STM32 erstmal ohne HAL zu erforschen, um dessen Grundlagen kennen zu lernen. Das ist Voraussetzung, um die HAL zu verstehen.
Pauschal zu sagen "DMA und UART ist sinnlos" ist schon ne gewagte These: Bei geringen Geschwindigkeiten und/oder sporadischem Empfang von Nachrichten stimmt das Gesagte natürlich, Interrupt-getriebenes UART deckt die meisten Anwendungsfälle ab. Das geht aber alles den Bach runter wenn man das UART Interface mal ein wenig ausreizt, da ist DMA ganz schnell vorne was CPU-Entlastung und Performance angeht, denn es erlaubt einem das Füllen der Buffer und das Auswerten der Daten vollständig parallel laufen zu lassen. Die zeitkritische Operation (Empfangenes Byte in Buffer kopieren) wird vom DMA Controller übernommen und es sinkt die Chance Daten zu verlieren wenn man keine Flusskontrolle nutzt. Außerdem spart man sich den Interrupt-Eintritts+Austritts-Overhead von ca 22~26 Zyklen plus die Zeit die man braucht um das Byte zu kopieren und die Flags zu löschen, dass können schon mal ~50 Zyklen sein. Bei einem 48 MHz Cortex-M0 sind das ~1us Overhead pro Empfangenen Byte. Empfängst du jetzt mit 921600 bit/s (inklusive Start/Stopp Bit) dann kannst du alle ~11us ein Byte rein bekommen. Es geht also knapp 10% der verfügbaren Rechenzeit nur auf das Entgegennehmen der Daten drauf, mit DMA kann man sich das sparen. Würde man das UART Interface mit mehr als einem MBit/s betreiben, wird der Effekt dann nochmal verstärkt.
Florian schrieb: > Das geht aber alles den Bach runter wenn man das UART Interface mal ein > wenig ausreizt, da ist DMA ganz schnell vorne was CPU-Entlastung und > Performance angeht Stimmt doch garnicht, denn man muß die Daten ja ohnehin bereitstellen und obendein auch noch den DMA einrichten. Und bei UART's mit Fifo (NXP) kann man bis zu 16 Bytes in einem ISR-Lauf in die HW schaffen. Wir reden hier von einem UART und nicht von einer SPI-Schnittstelle, die bei manchen Displays zum Übertragen der anzuzeigenden Display-Inhalte benutzt wird. Bei so einem Display steht von vornherein fest, wieviel Bytes für die Anzeige transferiert werden müssen und all die Zeichenvorgänge auf den Canvas im µC sind bereits vorbei. Für sowas von vornherein Feststehendes geht dann auch DMA. Bei einem UART haben wir hingegen völlig asynchronen Verkehr in beiden Richtungen. Das ist das Kern-Kennzeichen des UART's - und ein knappes MBit/s ist für nen UART auch nicht die wirklich passende Verwendung: Florian schrieb: > Empfängst du jetzt mit 921600 bit/s (inklusive Start/Stopp Bit) dann > kannst du alle ~11us ein Byte rein bekommen. Und kann man das dann auch alle 11 µs auswerten? hehe? Es ist doch eine völlige Fehlannahme, sich ausschließlich auf das Übertragen zu konzentrieren und dabei ganz zu vergessen, daß Sendedaten auch erzeugt und Empfangsdaten ausgewertet sein wollen. Machen das heuer die Heinzelmännchen oder eben doch der µC, der dafür so seine Zeit braucht? W.S.
Die Entscheidung DMA vs. Interrupt hängt recht empfindlich vom Anwendungsfall ab. (Unvorhersehbar empfangene) Daten im DMA-Puffer können durchaus schwieriger und zeitaufwendiger auszuwerten sein und es wird in jedem Falle eine bestimmte Mindest-Speichermenge für den Puffer verlangt. Im Interrupt kann man hingegen auf bestimmte Daten SOFORT reagieren, gleich auswerten und verwerfen. Das kann allen Overheads zum Trotz effizienter sein. Man braucht im Extremfall dazu nicht mal einen Puffer. Fürs Senden ist allerdings immer DMA -so vorhanden- zu bevorzugen.
W.S. schrieb: > Florian schrieb: > Das geht aber alles den Bach runter wenn man das UART Interface mal ein > wenig ausreizt, da ist DMA ganz schnell vorne was CPU-Entlastung und > Performance angeht > > Stimmt doch garnicht, denn man muß die Daten ja ohnehin bereitstellen > und obendein auch noch den DMA einrichten. Natürlich stimmt das. Die UART im Interrupt-Modus betrieben kann die MCU gerade bei viel Speed und ein paar Anweisungen zuviel im Handler schnellstens in die Knie zwingen- und man wundert sich über undurchsichtige Fehlerbilder, die auf zu schmale verbliebene Zeitscheibchen für andere (Interrupt)Funktionen zurückgehen. Die Daten-Bereitstellung und DMA Einrichtung sind hingegen schnell erledigt und im Performance-Bedarf kaum der Rede wert.
> Stimmt doch garnicht, denn man muß die Daten ja ohnehin bereitstellen > und obendein auch noch den DMA einrichten. Das macht man einmal, während des Setups, danach läuft das Ganze ohne weitere Einflussnahme vor sich hin bis der Controller resettet wird, dafür gibt's doch den zyklischen Betriebsmodus. > Bei so einem Display steht von vornherein fest, wieviel Bytes für die > Anzeige transferiert werden müssen und all die Zeichenvorgänge auf den > Canvas im µC sind bereits vorbei. Für sowas von vornherein Feststehendes > geht dann auch DMA. Bist du zu starsinning zu checken dass man auch mit DMA auf unterschiedlich große zufällige Nachrichten eingehen kann? Das wurde doch schon x-mal beschrieben und lässt sich problemlos umsetzen wenn die DMA Peripherie die entsprechenden Schnittstellen offenlegt. > Und kann man das dann auch alle 11 µs auswerten? hehe? > Es ist doch eine völlige Fehlannahme, sich ausschließlich auf das > Übertragen zu konzentrieren und dabei ganz zu vergessen, daß Sendedaten > auch erzeugt und Empfangsdaten ausgewertet sein wollen. Machen das heuer > die Heinzelmännchen oder eben doch der µC, der dafür so seine Zeit > braucht? In meinem realen Anwendungsfall kommt es häufig vor, dass ein kleiner Header ausgewertet werden muss und dann kommt eine ewig lange Payload welche vom Controller nicht angefasst werden muss/soll, bis sie komplett eingetroffen ist, dann aber möglichst schnell verarbeitet werden soll. Da die DMA Hardware keine CPU-Zeit klaut während die Bytes reinpurzeln kann sich der ARM-Kern voll auf die Weiterverarbeitung der Payload konzentrieren, auch wenn das nächste Paket sofort im Anschluss kommt. Und das Kopieren in den Arbeitsbuffer, die Verschlüsselung und der Versand dürfen gerne mehr als 10us dauern da der Buffer das auffängt. Wenn ich dafür Interrupts einsetzen würde ginge das auch, nur würde ich dann zu Fuß genau das machen was der DMA-Controller in Hardware und entkoppelt von dem ARM-Kern macht. Es gibt natürlich auch Einsatzzwecke bei denen es keinen Sinn macht DMA zu nutzen, wurde aber auch schon durchgekaut und ist mir bekannt.
Florian schrieb: > Bist du zu starsinning zu checken dass man auch mit DMA auf > unterschiedlich große zufällige Nachrichten eingehen kann? Das wurde > doch schon x-mal beschrieben und.. ..und du meinst, hier beleidigend werden zu müssen. Nein, es ist nicht so, wie du schreibst. EInen DMA muß man zuerst einrichten und dann kann es an das Transferieren gehen. Das ist das exakte Gegenteil dessen, was eine asynchrone Schnittstelle leisten soll. Dort kommen nicht nur die Empfangsdaten unvorhersehbar, sondern auch die Sendedaten kommen ebenso unvorhersehbar für den Treiber aus irgendwelchen Teilen der restlichen Firmware oder gar über andere Ports von woanders her. Man muß sich also bei einem UART immer darauf einrichten, daß die Daten in beiden Richtungen immer in Anzahl und Zeitpunkt unvorhersehbar hereinkommen. Das schließt ein zuvoriges Setzen der Übertragungsmenge bei einem DMA aus. Klaro? W.S.
W.S. schrieb: > Florian schrieb: >> Bist du zu starsinning zu checken dass man auch mit DMA auf >> unterschiedlich große zufällige Nachrichten eingehen kann? Das wurde >> doch schon x-mal beschrieben und.. > > ..und du meinst, hier beleidigend werden zu müssen. Wie oft sollen wirs dir denn noch sagen? Da du hier andauernd mit dem selben Stuss kommst und nach freundlichen Diskussionen dank deiner borniertheit nach einiger Zeit dann wieder anfängst bläst der Gegenwind eben langsam stärker. Zudem ist "starrsinnig" keine Beleidigung, sondern eine passende Zustandsbeschreibung. Inzwischen hat dir hier im Forum eine 2 stellige Anzahl an Mitgliedern verklickert, dass du nur Müll schreibst und keine Ahnung von C hast. Inzwischen fangen sogar einige an einen "W.S. Disclaimer" unter ihre Posts zu schreiben, damit du die nicht volltextest! So wie es Florian beschrieben hat machen das übrigens zB Bluetoothstacks. (HCI über UART). Da kommen durchaus Baudraten von 1 bis 4 Mbaud über den UART mit HW Handshake zusammen und die Daten willste dir auf der unteren Ebene nicht ansehen, sondern 1zu1 zum BT Stack schaufeln. Die Länge ließt man aus dem Header (mehr guckt man sich nicht an), der ist trotz unterschiedlichen Pakettypen immer der Gleiche mit der Längenangabe an derselben Stelle. Also sachste dem DMA, dass er 5 Zeichen lesen soll, dann ließte die Länge aus und dann ließte nochmal 500+ Bytes per DMA. Bei manchen MCUs kann der DMA sogar die UART Handshakeleitung direkt betreiben, auch ne schöne Sache. Aber mach mal deinen UART schön weiter mit IRQs, wie in den 80ern in denen du mit deinen Magic Numbers und 3 mal denselben Code für 3 UARTS kopieren statt structs zu nutzen stecken geblieben bist!
W.S. schrieb: > Dort kommen nicht nur die Empfangsdaten unvorhersehbar, sondern auch die > Sendedaten kommen ebenso unvorhersehbar für den Treiber aus > irgendwelchen Teilen der restlichen Firmware oder gar über andere Ports > von woanders her. Du hast wirklich Alzheimer oder? In einem Thread wo du selbst auch deinen Müll mal wieder zum Besten gegeben hast hat doch genau jemand sowas gebaut für den TX. "Unvorhersehbare" Sendedaten aus der FIFO per DMA senden. Wenn ein DMA Transfer fertig ist guckt er eben ob noch was in der FIFO ist oder nicht un sendet den nächsten Block. Wenn nur 1 Byte in der FIFO ist gibts eben einen 1 Byte DMA. Aber das tut icht weh, das ist dann genauso "aufwändig" wie ein IRQ Transfer.
Mw E. schrieb: > Wie oft sollen wirs dir denn noch sagen? Lass ihn doch und spare Dir die Energie für Bettsport auf. Das gilt auch für die anderen Streithähne hier.
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.