Hallo, ich bin noch neu auf dem Gebiet der STM32 Programmierung. Aktuell habe ich ein kleines Evalboard mit dem STM32L051, welches ich bereits etwas Leben eingehaucht habe (Clock source auf externen Quarz und PLL umgestellt, GPIO initialisiert und UART initialisiert). Programmiert wird bare metal, sprich ohne jegliche HAL (nur die CMSIS) wird benutzt. Meine nächsten Schritte sind die anderen Peripherals (I2C und SPI) zum Laufen zu bringen. Aktuelles Thema ist jedoch die UART. Die UART Übertragung funktioniert bei mir so, dass ich einen RX-Interrupt aktiviere und in der UART ISR dann auf bestimmte Zeichen abfrage und entsprechende Aktionen auslöse (z.B. LED ein/aus, String senden). Das funktioniert auch, sprich die Basisfunktionalität ist gegeben. Anstatt des UART Tests möchte ich jedoch in serial.write Arduino-Manier einfach Log - Messages während der Entwicklung über die UART ausgeben und da komme ich irgendwie nicht weiter. Meine Idee war einfach printf zu benutzen, da man hier alle Formatierungsoptionen hat. Dazu muss man aber wohl eine Funktion (_write) umbiegen, damit printf die UART als standard output verwendet. Das scheint doch alles komplex zu werden - für eine "triviale" Aufgabe. Generell: ist es eine gute Idee mit UART RX / TX Interrupts zu arbeiten oder ist einfaches Polling völlig in Ordnung? Anbei der Code zur ISR und zur TX-Routine, der ursprünglich von R. Jesse stammt: void USART2_IRQHandler(void) { uint16_t received = 0; if (USART2->ISR & USART_ISR_RXNE) { received = USART2->RDR & 0x01FF; if (received == 'a') { LED_PC13_ON; } if (received == 'b') { LED_PC13_OFF; } /* Filter fuer zulaessige Zeichen */ if (((received >= 'A') && (received <= 'Z')) || ((received >= 'a') && (received <= 'z')) || (received == ' ') || (received == CR) || (received == LF) || (received == '*')) { USART2->RDR = received; } if (received == 'c') { USART2->CR1 |= USART_CR1_TXEIE; // Tx-Interrupt nur aktivieren, wenn Daten gesendet werden sollen! } } if ((USART2->ISR & USART_ISR_TXE) && (USART2->CR1 & USART_CR1_TXEIE)) { if (*outString != '\0') { USART2->TDR = *outString++; // Text zeichenweise ausgeben, bis das 0-Byte (= Textende) erkannt wird } else // 0-Byte gefunden --> Text wurde vollstaendig ausgegeben { outString = saveString; // Neu: Urspruenglichen Text wiederherstellen USART2->CR1 &= ~USART_CR1_TXEIE; } } }
:
Bearbeitet durch User
Heinz K. schrieb: > Meine Idee war einfach printf zu benutzen, da man hier alle > Formatierungsoptionen hat. Dazu muss man aber wohl eine Funktion > (_write) umbiegen, damit printf die UART als standard output verwendet. > Das scheint doch alles zu komplex zu sein. Das ist gar nicht schwierig. Dort ist ein Beispiel (ohne Sendepuffer): http://stefanfrings.de/stm32/stm32l0.html#usart Wenn du das mit einem Puffer machen willst, würde ich aber nicht '\0' als Ende-Markierung benutzen, denn das funktioniert nur mit Strings in denen das Zeichen nicht vorkommt. Ich würde das eher mit einem Ringpuffer machen. Wie das geht, wurde hier schon ziemlich oft diskutiert. Du findest die Beiträge bestimmt mit der Suchfunktion. Oder auch dort: https://www.youtube.com/watch?v=teCQ8dosFts
Heinz K. schrieb: > Generell: ist es eine gute > Idee mit UART RX / TX Interrupts zu arbeiten oder ist einfaches Polling > völlig in Ordnung? Interrupts haben den Vorteil, dass das restliche Programm quasi weiterläuft und nicht blockiert wird. Boards von ST (NUCLEO, Discovery etc) haben doch den ST-Link zum Programmieren drauf. Damit kann man auch debuggen.
Heinz K. schrieb: > Generell: ist es eine gute > Idee mit UART RX / TX Interrupts zu arbeiten oder ist einfaches Polling > vällig in Ordnung? Also generell ist es schonmal gut, wenn Du mit Bare Metal anfängst, um Dir einen etwas tieferen Einblick in den Microcontroller zu verschaffen. Allerdings haben wir 'zu meiner Zeit' immer erstmal versucht einen 8 Bit Controller (ATmega8) zum laufen zu bringen. Das ist dann doch etwas einfacher. Was den UART bzw. die Interrupts betrifft ist es keine gute Idee, darin die Daten auszuwerten. Du sollstest einfach einen globulen Byte Array nutzen und diesen mit den empfangenen Daten füllen (z.B. uartDataRx[i] = ...). Dann kannst du noch ein (globales ) Flag sezten, z.B. uartReceived = true. In der main() wird das ganze dann ausgewertet und ggf. auch was zurückgeschickt. Gruß Peter
Heinz K. schrieb: > ich bin noch neu auf dem Gebiet der STM32 Programmierung. Aktuell habe > ich ein kleines Evalboard mit dem STM32L051, welches ich bereits etwas > Leben eingehaucht habe (Clock source auf externen Quarz und PLL > umgestellt, GPIO initialisiert und UART initialisiert). Du bist ein Held! UNd wenn du mit dem Benutzen des UART (Universeller Asynchroner Empfänger und Sender) nicht allein zu Potte kommst, dann lade dir mal das: http://www.mikrocontroller.net/attachment/316790/STM32F103C8T6.ZIP herunter und lies darin. Oder schaue dir den folgenden Thread an: Beitrag "Einstieg in STM32 : STM32F103C8T6 --> Kompilieren und Flashen?" Das Zeug im Zipfile ist zwar für den STM32F103C8T6, aber zum einen ist vieles darin plattformunabhängig (läuft also auch auf z.B. Fujitsu-Controllern) und zum anderen sind die Peripheriecores bei den diversen STM32 oftmals ziemlich ähnlich, sodaß sich auch Lowlevel-Treiber ohne allzu große Hürden auf einen anderen Chip umschreiben lassen. W.S.
Stefan F. schrieb: > Das ist gar nicht schwierig. Dort ist ein Beispiel (ohne Sendepuffer): > > http://stefanfrings.de/stm32/stm32l0.html#usart Vielen Dank Stefan für den Link. Ich kenne die Seite eigentlich, mmh. scheinbar habe ich den Artikel nicht gefunden ... In der _write Funktion nutzt Du normales Polling, wenn ich das richtig sehe (Abfrage Bit USART_ISR_TXE). In der UART Initialisierungsroutine werden sowohl TX und RX Interrupt gleichzeitig aktiviert. Ist das gut so? Sollte TX Interrupt nicht erst frigegeben werden, wenn etwas im TX Sendebuffer steht?
Peter schrieb: > Allerdings haben wir 'zu meiner Zeit' immer erstmal versucht einen 8 Bit > Controller (ATmega8) zum laufen zu bringen. Das ist dann doch etwas > einfacher. ich kenne die 8bit AVR Controller recht gut und habe schon einiges programmiert. Nun wollte ich einfach den Schritt gehen und auf die STM32 umschwenken. Mein Ziel ist wirklich ein harter Wechsel - sonst beschäftige ich mich nur halb mit dem STM32 ;-)
W.S. schrieb: > Das Zeug im Zipfile ist zwar für den STM32F103C8T6, aber zum einen ist > vieles darin plattformunabhängig (läuft also auch auf z.B. > Fujitsu-Controllern) und zum anderen sind die Peripheriecores bei den > diversen STM32 oftmals ziemlich ähnlich, sodaß sich auch > Lowlevel-Treiber ohne allzu große Hürden auf einen anderen Chip > umschreiben lassen. Danke für den Link! Das werde ich mir bei Gelegenheit zu Gemüte führen. Zu den Peripherie-Cores und der Ähnlichkeit kann ich nur sagen - es stimmt nur bedingt. Die Familien sind doch sehr unterschiedlich und man kommt um das Studium des Referenzmanuals nicht herum. Beispiel: ich habe das Buch von R. Jesse "STM32 ARM Mikrocontroller programmieren - das umfassende Handbuch" (keine Werbung!!). Hier wird ein STM32F446 verwendet und die Bare Metal Beispiele muss man häufig auf den STM32L0x1 umschreiben, da die Registernamen anders sind. ImPrinzip sind diese aber schon sehr ähnlich, da gebe ich Dir völlig Recht.
Heinz K. schrieb: > Sollte TX Interrupt nicht erst > frigegeben werden, wenn etwas im TX Sendebuffer steht? Ähem... naja. Also bei vielen Chips ist es so, daß der Interrupt statisch ist, also solange ansteht, bis entweder etwas zum Senden in den Sender geschrieben wurde oder bis man ihn sperrt. Das bedeutet, daß der Sendeinterrupt immer dann von der ISR gesperrt werden muß, wenn sie gerade nix zum Senden vorfindet. Und von der Routine, die ein Zeichen zum Senden entgegennimmt und in einen Ringpuffer stopft, wird der Interrupt freigegeben, damit die ISR loslegen oder ihn wieder sperren kann (wenn es nix zu senden gibt). W.S.
Heinz K. schrieb: > In der UART Initialisierungsroutine werden sowohl TX und RX Interrupt > gleichzeitig aktiviert. Ist das gut so? Sollte TX Interrupt nicht erst > frigegeben werden, wenn etwas im TX Sendebuffer steht? Sorry Stefan, da habe ich Deinen Code auf Deiner Seite falsch gelesen. // Enable transmitter, receiver and receive-interrupt of USART1 USART1->CR1 = USART_CR1_UE + USART_CR1_TE + USART_CR1_RE + USART_CR1_RXNEIE; Du schaltest NUR den RX Interrupt frei. TX benutzt keinen Interrupt und damit nur Polling, richtig? Ist das so die "gängige" Methode?
Stefan F. schrieb: > http://stefanfrings.de/stm32/stm32l0.html#usart Hallo Stefan, Dein Code gefällt mir! kurz und prägnant. Meine Fragen hierzu. 1) Du verwendet puts() statt printf(). Benötigt puts() weniger Speicher oder was ist der Hintergrund für die Verwendung von puts? Wenn ich das richtig verstanden habe, kennt puts() keine format specifiers. In der Regel will man beim Loggen ja einen kleinen erklärenden Text und dann (Roh)Daten ausgeben - also eigentlich schon das was printf() bietet. Wäre eine Möglichkeit statt printf() die Kombination von sprintf() und puts() zu verwenden? Dann würde man erst einmal den String zusammensetzen und dann als String per puts() ausgeben. By the way. mein Code wird bei Verwendung von printf() ca. 5 kB gegenüber der Nichtverwendung aufgebläht...
Heinz K. schrieb: > By the way. mein Code wird bei Verwendung von printf() ca. 5 kB > gegenüber der Nichtverwendung aufgebläht... printf ist ja auch ziemlich mächtig. puts gibt doch nur Zeichen aus. printf übersetzt auch (rationale) Zahlen in strings.
Heinz K. schrieb: > In der UART Initialisierungsroutine werden sowohl TX und RX Interrupt > gleichzeitig aktiviert. Ist das gut so? Falls du diese Zeilen meinst, schau nochmal genau hin:
1 | // Enable transmitter, receiver and receive-interrupt of USART1
|
2 | USART1->CR1 = USART_CR1_UE + USART_CR1_TE + USART_CR1_RE + USART_CR1_RXNEIE; |
Das Senden läuft bei diesem Beispielprogramm wie gesagt ohne Puffer, also auch ohne Interrupt. Mir ging es darum, dir ein einfaches verständliches Beispiel zu geben, wie man die _write() Funktion implementiert. Puffern ist ein davon unabhängiges Thema. Heinz K. schrieb: > Du verwendet puts() statt printf(). Benötigt puts() weniger Speicher > oder was ist der Hintergrund für die Verwendung von puts? Printf ist zum formatieren von Ausgaben gedacht. Puts ist für einfache Strings. Zumindest der avr-gcc ist allerdings so schlau, ein printf("...\n") durch puts("...") zu ersetzen. Ob der arm-gcc auch so clever ist, weiß ich nicht. > Wäre eine Möglichkeit statt printf() die Kombination von > sprintf() und puts() zu verwenden? Kannst du auch machen. Effizienter ist das am Ende aber vermutlich nicht, als gleich printf() zu verwenden. > By the way. mein Code wird bei Verwendung von printf() > ca. 5 kB gegenüber der Nichtverwendung aufgebläht... Das steht auch auf meiner Seite: http://stefanfrings.de/stm32/stm32l0.html#gccopt Die ganzen Formatier-Funktionen von printf bekommt man halt nicht umsonst. Und ja, ich weiß dass printf() beim AVR deutlich schlanker ist.
Beitrag #7323831 wurde von einem Moderator gelöscht.
Danke an alle für die Infos. Leider gibt mein printf auf dem Terminal nichts aus. Ich habe es so gemacht wie Stefan auf seiner Webseite implementiert hat: // Redirect standard output to the serial port int _write(int file, char *ptr, int len) { for (int i=0; i<len; i++) { while(!(USART1->ISR & USART_ISR_TXE)); USART1->TDR = *ptr++; } return len; } Hat jemand eine Idee woran es liegen kann?
Heinz K. schrieb: > Leider gibt mein printf auf dem Terminal nichts aus. > Hat jemand eine Idee woran es liegen kann? Funktioniert denn direkte (herkömmliche Ausgabe) ohne die C-Bibliotheksfunktionen zu verwenden? Hast du die Zeile mit \n abgeschlossen? Das ist bei ARM wichtig, weil die Bibliothek Ausgaben bis zum Zeilenumbruch zurück hält. Hast du Schnittstelle richtig initialisiert, insbesondere den Transmitter eingeschaltet und die Baudrate eingestellt? Da du PLL verwendest: hast du die Flash Latency eingestellt? Ich könnte noch 20 weitere Fragen stellen. Besser du zeigst mal deinen ganzen Code.
Stefan F. schrieb: > Hast du die Zeile mit \n abgeschlossen? Das ist bei ARM wichtig, weil > die Bibliothek Ausgaben bis zum Zeilenumbruch zurück hält. Danke Stefan, das war die Lösung! Ich hatte das \n im printf vergessen. Dieses Verhalten war mir nicht bewusst. Der Unterschied zu Deiner Implementierung war, dass Du das printf("Hello World") in der Endlosschleife hattest und ich davor. Meine Endlosschleife war leer. Interessant ist auch, dass OHNE abschliessendes \n die Code Size um gut 1.5kByte grösser ist als mit dem \n. Anbei der jetzt so funktionierende (Minimal-)Code: int main(void) { SystemCoreClockInit(); // PLL using HSE with 32MHz clock out GpioInit(); // GPIO configuration Usart2Init(); // GPIOC->ODR |= GPIO_ODR_OD13; // GPIOC: PC13 -> 1 // GPIOC->BSRR = GPIO_BSRR_BS_13; // GPIOC: PC13 -> 1; w/o read-modify-write printf("Hello World\n"); LED_PC13_ON; while(1) { } } ISR (IRQ Handler) und _write Funktion sind identisch zu Deiner Implementierung, ausser dass ich USART1 durch USART2 ersetzt habe.
Stefan F. schrieb: >> Hast du die Zeile mit \n abgeschlossen? Das ist bei ARM wichtig, weil >> die Bibliothek Ausgaben bis zum Zeilenumbruch zurück hält. Heinz K. schrieb: > Danke Stefan, das war die Lösung! Das steht übrigens auch auf der Webseite. Am besten liest du sie mal komplett durch. Ich habe da alle Knackpunkte aufgeschrieben, auf die ich beim Wechsel von AVR nach STM32 gestoßen war.
Heinz K. schrieb: > Interessant ist auch, dass OHNE abschliessendes \n die Code Size um gut > 1.5kByte grösser ist als mit dem \n. Wohl deswegen: Stefan F. schrieb: > Zumindest der avr-gcc ist allerdings so schlau, ein printf("...\n") > durch puts("...") zu ersetzen. Ob der arm-gcc auch so clever ist, weiß > ich nicht. Heinz K. schrieb: > dass Du das printf("Hello World") in der Endlosschleife hattest Wo hast du das gesehen? Ich würde das dann korrigieren.
Hi Stefan, ich will so höflich sein, Deine anderen Fragen auch zu beantworten. Stefan F. schrieb: > Funktioniert denn direkte (herkömmliche Ausgabe) ohne die > C-Bibliotheksfunktionen zu verwenden? Ja, funzt > Hast du die Zeile mit \n abgeschlossen? Das ist bei ARM wichtig, weil > die Bibliothek Ausgaben bis zum Zeilenumbruch zurück hält. siehe Antwort von gerade eben. (nein, hatte ich nicht) > Hast du Schnittstelle richtig initialisiert, insbesondere den > Transmitter eingeschaltet und die Baudrate eingestellt? Ja, eingestellt und getestet mit meinem Minimal-Code > > Da du PLL verwendest: hast du die Flash Latency eingestellt? Ja, auch das habe ich korrekt gemacht.
Heinz K. schrieb: > ich will so höflich sein, Deine anderen Fragen auch zu > beantworten. Ach, ist doch gar nicht mehr nötig, nachdem der Fehler gefunden wurde.
Stefan F. schrieb: > Wo hast du das gesehen? Ich würde das dann korrigieren. http://stefanfrings.de/stm32/stm32l0.html#usart while (1) { // LED on WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BS_5); delay(500); puts("Hello"); // LED off WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BR_5); delay(500); } Du schreibst selbst auch über dem Quelltext: "Das folgende Beispielprogramm sendet regemäßig "Hello World!" aus." -> Beschreibung passt zum Code für mich.
Heinz K. schrieb: > puts("Hello"); Da habe ich puts() verwendet, nicht printf(). Puts hängt immer einen Zeilenumbruch an die Ausgabe an. Heinz K. schrieb: > Du schreibst selbst auch über dem Quelltext: "Das folgende > Beispielprogramm sendet regemäßig "Hello World!" aus." -> Beschreibung > passt zum Code für mich. Da sehe ich jetzt aber einen Fehler. Die Ausgabe lautet "Hello", nicht "Hello World!".
Peter schrieb: > Was den UART bzw. die Interrupts betrifft ist es keine gute Idee, darin > die Daten auszuwerten. Du sollstest einfach einen globulen Byte Array > nutzen und diesen mit den empfangenen Daten füllen (z.B. uartDataRx[i] = > ...). Dann kannst du noch ein (globales ) Flag sezten, z.B. uartReceived > = true. Das finde ich eine gute Idee. Frage meinerseits: wie gross dimensioniert man so ein Array? Hast Du Code-Beispiele für mich (oder einen Link) für eine entsprechende Implementierung? Mir geht es nur um den Ansatz und die grobe Struktur. Beim Thema Buffer bin ich ehrlich gesagt auch Newbie. Das Prinzip des Ring-Buffers habe ich verstanden, habe aber im Moment keine Idee, das kompakt in C umzusetzen ...
Heinz K. schrieb: > wie gross dimensioniert man so ein Array Das kommt ganz auf deine Anwendung an. Beim Empfangen musst du dir überlegen, wie viele Bytes sich maximal im Puffer aufstauen, während dein µC gerade nicht empfangsbereit ist weil er anderweitig beschäftigt ist. Das hängt auch von der Quelle der Daten ab. Beim Senden musst du dir überlegen, ob du überhaupt puffern willst. Wenn ja, dann würde ich mir überlegen, wie viele Daten dein Programm quasi am Stück erzeugt, die dann aber später nach und nach gesendet werden. Viele Programme warten nach dem Senden, bis das letzte Byte raus ist, bevor sie (mit was auch immer) weiter machen. In diesem Fall mach ein Puffer die Sache bloß unnötig kompliziert. In anderen Programm kann ein Sendepuffer aber hilfreich sein, damit dein Programm nach dem Erzeugen einer Ausgabe sofort weiter arbeiten kann, ohne auf die relativ langsame serielle Kommunikation warten zu müssen.
> Programmiert wird bare metal
Debugausgaben sollte man gar nicht puffern oder dabei Funktionen
benutzen die das doch tun. Warum das so ist, da solltest du
selber drauf kommen.
Debugausgaben sollten ohne Interrupt auskommen.
Global den Interrupt sperren ist dann natuerlich noetig.
Es kann lohnenswert sein, Debugausgaben mit einem Soft-UART
auszugeben. Der kann u.U. ein mehrfaches der Geschwindigkeit
eines HW-UART erreichen. Warum das fuers Debugging gut ist,
auch darauf solltest du selber kommen.
printf hat nun gar nichts von "bare metal".
Mehr als Zeichen, (kurze) Zeichenketten, und Hex und Dezimal in
Byte, 16/32 bit-Word braucht man da eigentlich nicht.
Ich kannte mal jemanden, der versuchte eine *zeitkritische"
Software mit solchem "printf"-Germurkse zum Laufen zu bringen.
Dabei haben schon die Debugausgaben sein Programm zeitlich
so ruiniert, dass das nicht mehr funktionierte.
STK500-Besitzer schrieb: > printf ist ja auch ziemlich mächtig. Sagen wir's mal direkt: mit printf wird Übersetzungsarbeit vom Übersetzungszeitpunkt in die Laufzeit des µC verlagert. Das printf ist im Wesentlichen ein Textinterpreter, der zum Übersetzen des Formatstrings gebraucht wird und da er nicht ahnen kann, was der jeweilige Programmierer dort hineingeschrieben hat, muß er obendrein auch noch alle möglichen (und unmöglichen) Ausgabe-Konverter vorhalten. Das macht ihn so dick. Aber als Programmierer der Firmware weiß man eigentlich, was man an Ausgabekonvertern braucht und kann diese dann auch selbst aufrufen, ohne dafür einen Textinterpreter zu benötigen. W.S.
blubdidup schrieb: > Es kann lohnenswert sein, Debugausgaben mit einem Soft-UART > auszugeben. Der kann u.U. ein mehrfaches der Geschwindigkeit > eines HW-UART erreichen. Ok, gibt es dafür bereits Beispiel-Implementierungen? So ganz ist mir auch nicht klar, warum eine Soft-UART viel schneller ist als eine HW UART sein sollte. Ich stimme zu, das printf nicht unbedingt zu bare metal passt. Wie bewerkstelligt man denn nun konkret die Ausgaben auf die serielle Schnittstelle zu Debug-Zwecken? Was mich etwas irritiert ist, dass es für ein solches Standardthema (Log Ausgaben via UART) scheinbar keine vernünftige Lösung gibt.
:
Bearbeitet durch User
Heinz K. schrieb: > Was mich etwas irritiert ist, dass es für ein solches Standardthema (Log > Ausgaben via UART) scheinbar keine vernünftige Lösung gibt. Weil da jeder eine andere Vorstellung davon hat, wie man das richtig macht.
Heinz K. schrieb: > Ok, gibt es dafür bereits Beispiel-Implementierungen? So ganz ist mir > auch nicht klar, warum eine Soft-UART viel schneller ist als eine HW > UART sein sollte. Löse dich einfach mal von der Vorstellung, daß man für alles, was irgendwie 'debug' genannt werden kann, dieselbe Signalisierung und dann noch per genormten Parametern machen kann. Ich hab selbe auch schon Einpin-Ausgaben gemacht, die dazu da sind, per Oszi angeschaut zu werden. Sowas ist sinnvoll an Stellen, wo noch kein definierter Takt vorliegt, also bei der Grundkonfiguration mittendrin, wo die PLL noch nicht fertig meldet. Ich hab auch schon eine zweistufige Debug-Ausgabe gemacht, zum Beispiel in der ISR des USB. Zuerst alles in einen RAM-Puffer und später dann von dort aus gemütlich per UART auf die Reise geschickt. Es kommt eben immer darauf an, was man wo machen will. > Ich stimme zu, das printf nicht unbedingt zu bare metal passt. Wie > bewerkstelligt man denn nun konkret die Ausgaben auf die serielle > Schnittstelle zu Debug-Zwecken? Es sind ja nicht nur Debug-Zwecke, sondern die Kommunikation insgesamt. Dazu sollte man sich eine vernünftige für den µC geeignete Schnittstelle zwischen Lowlevel-Treiber und den anderen Teilen der Firmware machen. Sowas wie printf gehört nicht dazu. Ich halte es so, daß der Treiber sowas wie char_out(char C) anbietet, wo dann je nach Bedarf ein String_Out(...) oder ein Long_Out(...) oder ein Float_Out(...) aufsetzen können. Eben je nachdem, was man tatsächlich braucht. > Was mich etwas irritiert ist, dass es für ein solches Standardthema (Log > Ausgaben via UART) scheinbar keine vernünftige Lösung gibt. Es gibt (s.o.) keine Standard-Methode für's Debuggen und folglich auch keine Standard-Mitteilungs-Methode. Und für ein langsames (da durch den Menschen am Terminalprogramm auf dem PC zu beobachten) Verfahren reichen die bereits genannten auf Char_Out(...) aufsetzenden Methoden völlig aus. Aber die Programmier-Kinder, die nix anderes als printf gezeigt bekommen haben und selbst keine Lust oder keine Fähigkeit haben, sich etwas effizienteres selbst auszudenken oder gar von der Hochmut-Kuh gebissen sind (neulich: "ich programmiere NICHT auf Registerebene"), schielen eher darauf, als Ersatz für printf irgendwas aus der C++ Kiste nehmen zu wollen. Ohne auch nur einen einzigen Gedanken darauf zu verwenden, was sie sich damit einbrocken. Hauptsache, es gibt da eine fertige Lib für. W.S.
W.S. schrieb: > Ich hab selbe auch schon > Einpin-Ausgaben gemacht, die dazu da sind, per Oszi angeschaut zu > werden. Sowas ist sinnvoll an Stellen, wo noch kein definierter Takt > vorliegt, also bei der Grundkonfiguration mittendrin, wo die PLL noch > nicht fertig meldet. Den ersten Teil kenne ich als HW Entwickler, das ist absolut Low-Level und geht, ist aber mühsam. > Ich hab auch schon eine zweistufige Debug-Ausgabe > gemacht, zum Beispiel in der ISR des USB. Zuerst alles in einen > RAM-Puffer und später dann von dort aus gemütlich per UART auf die Reise > geschickt. Das finde ich eine gute Idee. Dazu fehlt mir allerdings die Erfahrung so etwas zu implementieren. > Es sind ja nicht nur Debug-Zwecke, sondern die Kommunikation insgesamt. > Dazu sollte man sich eine vernünftige für den µC geeignete Schnittstelle > zwischen Lowlevel-Treiber und den anderen Teilen der Firmware machen. > Sowas wie printf gehört nicht dazu. Ich halte es so, daß der Treiber > sowas wie char_out(char C) anbietet, wo dann je nach Bedarf ein > String_Out(...) oder ein Long_Out(...) oder ein Float_Out(...) aufsetzen > können. Eben je nachdem, was man tatsächlich braucht. Mit dem Ansatz gehe ich durchaus mit. printf() hat halt den "Charme", das man alles mit einer Funktion erschlägt. Ich habe mir auch schon andere Tools / Instrumentierungen angeschaut, wie z.B. Trice (https://github.com/rokath/trice). Leider habe ich das nicht zum Laufen bekommen ... Ein letzter Aspekt: Debug via UART ist für mich Mittel zum Zweck - ich will z.B. ADC RAW Daten sehen. Ich möchte da ungern ein eigenes Projekt daraus machen.
:
Bearbeitet durch User
Wir haben einen Artikel mit Codebeispielen zur Implementierung von Ring-Puffern https://www.mikrocontroller.net/articles/FIFO#2n-Ringpuffer_-_die_schnellste_L%C3%B6sung
> Ok, gibt es dafür bereits Beispiel-Implementierungen? So ganz ist mir > auch nicht klar, warum eine Soft-UART viel schneller ist als eine HW > UART sein sollte. Weil ein HW-UART das Signal gerne N-fach ueberabtasten will. Das gilt zwar eigentlich nur fuer den RX-Teil, trifft aber den TX des UARTs genauso. Die Senderoutine eines Soft-UART in Assembler(!) zu schreiben, ist eine gute Fingeruebung. Bereits 8-bitter schaffen bei einem internen CPU-Takt von 2 MHz Geschwindigkeiten von 230 kbit. Wer will, kann bei einem Soft-UART auch gleich Fast-IRDA auf eine (IR-)LED ausgeben. Da ist dann Potentialtrennung gleich inklusiv. Sicher gibt es "Beispiel-Implementierungn" die aber fuer diesen Zweck genau alle nicht taugen, weil sie interruptgesteuert sind. Und natuerlich viel zu langsam. Wenn man sich nicht an die Standardbaudraten halten will, kann den seriellen Text ja auch im LA mitlesen. Viele serielle USB-Adapter gestatten auch die Einstellung arbitraerer Baudraten. Wenn es "ueberall" funtionieren soll, sind die Standardbaudraten schon im Vorteil. Ueber > Debugausgaben sollte man gar nicht puffern und > Debugausgaben sollten ohne Interrupt auskommen. scheinst du ja auch noch nicht nachgedacht zu haben. Ein Debugprint ist auch noch etwas anderes als ein Debuglog. > Ich möchte da ungern ein eigenes Projekt daraus machen. Ein anderer schreibt dazu immer: "Keine Arme, keine Kekse."
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.