Es sollen immer sieben Zeichen gesendet werden. Das erste Byte wird per isr angesprungen und richtig in den buffer geschrieben. Danach wird die isr nicht mehr ausgeführt. Im Debugger - langsam - funktioniert es alle 7 bytes durch (natürlich nicht mit einer Sendefolge).
Warum schaltest du innerhalb der ISR den Receiver aus und wieder ein?
Du hast zu viel Arbeit in die ISR gepackt. So verpasst du während der Ausgabe due nächsten Bytes.
Die ISR sollte die empfangenen Daten nur in den Puffer schreiben. Deren Verarbeitung gehört außerhalb von ISR in die main loop.
Wenn das 7.byte empfangen ist ist das Empfangen beendet und die isr wird nicht mehr gebraucht. Zwecks Fehlersuche habe ich da die tft-Ausgabe eingebaut. fliegt wieder raus wenn das ganze funktionieren sollte. In meiner ISR sind 4 Takte - das ist sehr viel kürzer als das hal-Gedöns.
Der code scheint prinzipiell auch zu funktionieren. Wenn ich mit dem avr sende, werden Zeichen - zum Teil richtig - angezeigt. Vielleicht ist das Ganze nur ein Timing-Problem.
Kann mir jemand verraten, wo man bei Cube die Usart-Baudrate einstellt? Habe das im ioc nicht gefunden. Hal generiert
Wenn du zweimal hintereinander USART2 initialisierst, solltest du dazwischen ein De_Init auslösen.
Aber generell reicht tatsächlich ein einmaliges Init mit den richtigen Settings.
Lass die ISR nur ein Flag setzen und steuere das LCD aus dem Hauptprogramm.
RXNE wir ausgelöst zum Zeitpunkt "Anfang bis Mitte
Stoppbit". Es ist dann zumindest Zeit bis zum nächsten Startbit.
Ich habe auf die Schnelle keine Info gefunden, wie schnell der Receiver nach dem enablen empfangsbereit wird. Vielleicht dauert das länger, als bis zum Beginn des nächsten Start-Bit. Kannst du das Timing deines Test-Senders ändern, um dieses Deal zu erforschen?
Deine Versuche, HAL und direkte Registerzugriffe zu mischen ist einfach eine ganz schlechte Idee (so lange man nicht wirklich versteht, was man tut), und zudem vollkommen unnötig!
Ich habe leider vergeblich versucht herauszufinden, welche Register-Bits
in den HAL-UART-Routinen gesetzt und geschrieben werden.
Der HAL Code ist wirklich scheer zu durchschauen, vor allem für Anfänger.
Ich denke, das ist ST durchaus bewusst. Für die F0 und L0 Modelle stellt die Firma immer noch reichlich Code-Beispiele mit direkten Register-Zugriffen bereit. Ich denke, diese Serien eignen sich besser, um sich mit STM32 vertraut zu machen.
Eigentlich alles.
In der ISR schreibt man die Bytes nur in einen Puffer und mehr nicht. Das aber auch erst, wenn das Statusregister den Empfang anzeigt. Diese Abfrage fehlt.
Spätestens wenn der federführende Student wo anders einen besseren Job gefunden hat kommt das nächste inkompatible Framework. Mein Bauch sagt mir, dass es bald wieder so weit sein wird.
Eigentlich alles.
In der ISR schreibt man die Bytes nur in einen Puffer und mehr nicht.
Das aber auch erst, wenn das Statusregister den Empfang anzeigt. Diese
Abfrage fehlt.
Sorry - wenn im Statusregister der Empfang angezeigt wird wird der Interrupt ausgelöst. Was soll ich da in der zugehörigen isr noch abfragen ob der Empfang erfolgt ist?
In der ISR schreibt man die Bytes nur in einen Puffer und mehr nicht. Das macht ja wohl
rx_buff[rx_buff_ct++]=USART2->DR;
nur dann hört es mit dem Empfangen auf. Das Problem wurde hier
Beitrag "Re: STM32F4xx UART-State während des Empfangs zurücksetzen"
diskutiert und mit
USART2->CR1 &= ~USART_CR1_RE;
USART2->CR1 |= USART_CR1_RE;//
gelöst.
Mehr hab ich bei den ersten bytes nicht drin und kürzer ist kaum denkbar. Vergleich das mal mit den Hal-Usart-Abfragen. Es hat ja auch ein paar mal funktioniert.
Das Problem ist m.E. das Timing des Senders. Das haut die STM-Fehlerabfragen zu und dann geht rx halt nicht mehr.
Deine Versuche, HAL und direkte Registerzugriffe zu mischen ist einfach
eine ganz schlechte Idee (so lange man nicht wirklich versteht, was man
tut), und zudem vollkommen unnötig!
Ich versuche, das ohne Hal registernah zu programmieren. Dafür müsste ich nur wissen, wie man den Empfang nach auslesen von DR wieder freigibt.
Ich habe leider vergeblich versucht herauszufinden, welche Register-Bits
in den HAL-UART-Routinen gesetzt und geschrieben werden.
Der HAL Code ist wirklich scheer zu durchschauen, vor allem für
Anfänger.
Ich denke, das ist ST durchaus bewusst. Für die F0 und L0 Modelle stellt
die Firma immer noch reichlich Code-Beispiele mit direkten
Register-Zugriffen bereit. Ich denke, diese Serien eignen sich besser,
um sich mit STM32 vertraut zu machen.
Nein, da ging es um ein ganz anderes Problem. Dort sollte der Mikrocontroller nach einem einem Framing Fehler "den nächsten Low-Pegel wieder als Startbit (und nicht als x-tes Datenbit) erkennen".
Bei dir geht es nicht um Framing Fehler, und vermutlich um ein engeres Timing.
Sorry - wenn im Statusregister der Empfang angezeigt wird wird der
Interrupt ausgelöst. Was soll ich da in der zugehörigen isr noch
abfragen ob der Empfang erfolgt ist?
Sorry, du hast noch sehr wenig Ahnung ....
Wenn ein Interrupt ausgelöst wird ist das ein Signal dass sich
etwas im Status verändert hat, und das ist nun mal nicht nur
das Received-Bit welches sich ändern kann.
Sorgfältigerweise muss man noch abfragen ob das richtige Bit
gesetzt ist (hier RXNE) sonst greift man evtl. ins Leere.
Schaue dir um Gottes Willen endlich ein vernünftiges Beispiel
an und lerne daraus, oder "Copiere und Paste" Teile daraus
bevor du spekulierst (nicht verstehst) was mit den Registern
passiert.
Schaue dir um Gottes Willen endlich ein vernünftiges Beispiel
an und lerne daraus,
Gut, dann hänge ich mal etwas an, was bei mir auf einem F407 läuft und USART3 verwendet. Das kann man ja auf USART2 ändern. Die Sende- und Empfangspuffer kann man jederzeit löschen.
es läuft mit
rx_buff[rx_buff_ct++]=USART2->DR;
USART2->CR1 &= ~(USART_CR1_RXNEIE);
USART2->CR1 |= (USART_CR1_RXNEIE);
Das glaube ich dir, aber welchen Sinn macht es, innerhalb der ISR diesen
einen Interrupt zu deaktivieren und wieder aktivieren?
bis
rx_buff[rx_buff_ct++]=USART2->DR;
sind wir uns alle einig. DR ist jetzt not empty (RXNE) und muss für den nächsten Lesevorgang freigegeben werden. Lesen von DR löscht RXNE, DR bleibt aber trotzdem gesperrt. Gesucht werden die Register, die für das Lesen des nächsten Bytes gehandelt werden müssen. Ich habe sie nicht gefunden. Das Manual hilft nicht weiter. Der Hal-Code ist kryptisch. In dem hier geposteten Code habe ich auch nichts gefunden.
USART_CR1_RXNEIE ist vielleicht der Holzhammer - aber zumindest bei 9600 Baud wirkt er perfekt. Kürzer geht es nicht. Was spricht also gegen den Holzhammer?
DR ist jetzt not empty (RXNE) und muss für den
nächsten Lesevorgang freigegeben werden.
Lesen von DR löscht RXNE, DR bleibt aber trotzdem gesperrt
Ich weiß 100% sicher, dass man auf L0, F1 und F3 nichts extra freigeben muss. Wenn das beim F4 entgegen seinem Referenzhandbuch plötzlich anders ist, fresse ich einen Besen. Im Errata steht auch nichts dazu.
Der Professor Laurent Latorre sieht das sieht vielen Jahren genau so:
2.2 Basic USART RX interrupt handler
1
externuint8_tconsole_rx_byte;
2
externuint8_tconsole_rx_irq;
3
4
voidUSART2_IRQHandler()
5
{
6
// Test for RXNE pending interrupt
7
if((USART2->ISR&USART_ISR_RXNE)==USART_ISR_RXNE)
8
{
9
// RXNE flags automatically clears when reading RDR.
Ich weiß 100% sicher, dass man auf L0, F1 und F3 nichts extra freigeben
muss. Wenn das beim F4 entgegen seinem Referenzhandbuch plötzlich anders
ist, fresse ich einen Besen. Im Errata steht auch nichts dazu.
Beim F411 muss auch nichts „freigegeben werden” – für einfache (Test)Zwecke reicht es aus, es so mit einer Zeile zu machen wie Du es vorhin geschrieben hast. Das Lesen des Datenregisters löscht das RXNE-Flag. Wenn man es besser machen will, dann sollte man die drei Haupt-Error-Flags (ORE, NF/NE und FE) überprüfen. Die Sequenz, diese zu löschen, ist etwas anders, aber auch nicht schwer: Statusregister lesen, danach Datenregister lesen und fertig – ist alles im Reference Manual beschrieben. Was hier mit dem F411 gemacht wird, gleicht einer Comedy.
Was hier mit dem F411 gemacht wird, gleicht einer ...
.... Troll-Comedy par Excellence. Hingeworfene, zusammenhang-lose
Code-Fragmente und Unbelehrbarkeit, Beratungsresistenz (Hinweise
werden gnadenlos ignoriert) zeigen wo es lang geht. Das TO-
Verhalten kann eigentlich nur durch Dummheit und/oder Wahrnehmungs-
störungen entschuldigt werden.
Übrigens, wer zusätzlich den Sende-Interrupt aktiviert oder ihn abfragt, obwohl dieser deaktiviert ist, ist selber schuld und hat meistens seine Hausaufgaben nicht gemacht – diesen Interrupt braucht man normalerweise nicht, denn was man zu welchem Zeitpunkt sendet, weiß man ja in der Regel selbst – der Zeitpunkt des Empfangs ist dagegen unbekannt und muss daher per Interrupt abgefangen werden – das ist ja auch der Witz an der Geschichte. Durch den aktivierten Sendeinterrupt verschenkt man ferner auch unnötig Rechenzeit der CPU, denn die Interruptroutine wird bei jedem Senden (Überschreiben der Sendedaten in das Output-Schieberegister) immer sinnlos in voller Montur angesprungen – mit Prolog und Epilog – obwohl nichts angekommen ist. Vollführt man dann auch noch nur eine einzige Fließkommaberechnung in derselben, so werden auch diese Spezial-Register von der CPU real auf dem Stack gerettet und das dauert dann gleich 2-3x so lange als der übliche Prolog und Epilog. Ist nur der Interrupt für den Empfang aktiviert, muss man auch nicht immer stupide abfragen, was nun passiert ist, denn das ist dann völlig klar – im Empfangsbuffer ist etwas angekommen. Ob es verwertbar ist oder nicht, kann man dann anhand der Error-Flags entscheiden – das hat aber erstmal mit dem ersten Sachverhalt nichts zu tun, sondern ist nur eine zusätzliche Luxusaufgabe. Wer wirklich den Sendeinterrupt braucht und ihn deswegen explizit einschaltet, der wird in der Regel auch wissen, wie das mit dem Lesen und Löschen der Flags und dem Empfang von Daten vonstattengeht und dass man das vorab auch abzufragen braucht. Es gibt noch den TC-Interrupt – hier gilt eigentlich das gleiche – was nicht nötig ist, wird auch nicht aktiviert und braucht deswegen in der Interruptroutine auch nicht abgefragt zu werden. Ferner gibt es bei den STM32 noch gebündelte Interrupts – hier muss man dann ggfs. vorher die Instanz, von der der Interrupt kommt, abfragen.
HAL, LL und selbstgeschriebene Registerzugriffe miteinander zu verbinden, ist eigentlich gar nicht so schwer – jedes Kind kann das, welches z.B. mit 6 Jahren angefangen hat, seine – ihm vom Schicksal vorher bestimmte – Geige zu spielen. Wer aber sehr fleißig mit dem Studieren der Datenblätter ist, schafft es auch mühelos im Laufe der Jahre trotz seines Alters. Aufholen wird er das Kind aber vermutlich nicht.
Das TO-
Verhalten kann eigentlich nur durch Dummheit und/oder Wahrnehmungs-
störungen entschuldigt werden.
Dummheit muss man nicht entschuldigen. Es gibt halt nicht nur kluge sondern auch dumme Menschen. Ich muss al dummer Mensch Probleme bewältigen, die kluge Menschen vielleicht gar nicht erst haben.
Der Professor Laurent Latorre sieht das sieht vielen Jahren genau so:
if ((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE)
{
// RXNE flags automatically clears when reading RDR.
// Store incoming byte
console_rx_byte = USART2->RDR;
console_rx_irq = 1;
}
Ist ein interessanter Ansatz:
During an USART reception, data shifts in least significant bit first through the RX pin. In this mode, the USART_DR register consists of a buffer (RDR) between the internal bus and the received shift register.
Der Professor greift statt des DR das RDR-Register ab. Das soll funktionieren? Muss man erst mal drauf kommen. Ich werde das ausprobieren.
Es gibt hier verschiedene stm-Uart-threads wo zunächst was nicht ging - was eigentlich hätte gehen müssen - und dann auf einmal doch ging: STM-Mysterium.
Übrigens, wer zusätzlich den Sende-Interrupt aktiviert oder ihn abfragt,
obwohl dieser deaktiviert ist, ist selber schuld und hat meistens seine
Hausaufgaben nicht gemacht – diesen Interrupt braucht man normalerweise
nicht, denn was man zu welchem Zeitpunkt sendet, weiß man ja in der
Regel selbst
Wenn man ungepuffert sendet: ja
Das ist aber eher Anfänger-Niveau. Selbst Arduino ist darüber hinweg.
Wenn man ungepuffert sendet: ja
Das ist aber eher Anfänger-Niveau. Selbst Arduino ist darüber hinweg.
Die meisten AVRs haben für RX und TX getrennte Interruptvektoren und genau darum geht es – also am besten nochmal darüber nachsinnen. Besser noch – immer vor dem Schreiben diese Aufgabe sorgfältig mehrmals tätigen.
Was soll das? Einfach irgendwas hingerotzt ohne Zusammenhänge
zu zeigen.
Entweder bist du ein hartnäckiger Troll oder du musst noch
sehr viel (vieeeeel) lernen.
Fang am besten mal hier an (falls du kein Troll
sein willst: Netiquette
Besonders Punkt drei gilt es stark zu beherzigen.
Aber eigentlich bist du zu lange hier angemeldet (mehr als
13 Jahre) um das nicht zu wissen. Also doch eher Troll(iges)
Verhalten .....
Folgender auf ein Minimum reduzierter Code funktioniert mit einem STM32F411RET6 ohne Probleme:
1
void USART1_IRQHandler(void)
2
{
3
USART1->DR = USART1->DR;
4
}
Ich kann vom PC aus über ein Terminal sowohl einzelne Zeichen als auch lange Textpassagen versenden – alles kommt ordnungsgemäß zum Terminal zurück und es blockiert sich nichts, ich kann anschließend immer wieder erneut etwas schicken und bekomme es ordnungsgemäß zurück. Die Interruptroutine wird auch nicht fehlerhaft mehrfach ausgeführt, da das besagte RXNE-Flag durch das Lesen des Datenregisters gelöscht wird, so wie es im Datenblatt steht. Die USART-Verbindung läuft über ST-LINK-2V1 und dann über USB-Kabel zum PC – das Terminalprogramm ist HTerm, würde aber auch mit anderen, vergleichbaren Programmen funktionieren. Genommen wurde meine Standardbaudrate 115200, das F411-Board selbst stammt aus meinen Entwürfen, die ich offiziell verkaufe, mit einem F411RE-Nucleo wird es aber genauso funktionieren. Aktiviert ist in so einem Fall natürlich nur der Empfangsinterrupt.
Spätestens wenn der federführende Student wo anders einen besseren Job
gefunden hat kommt das nächste inkompatible Framework. Mein Bauch sagt
mir, dass es bald wieder so weit sein wird.
Unsinn. STM32CubeMX ist mittlerweile ein ziemliches leistungsfähiger Konfigurator für so ziemlich alles geworden und wird immer weiter ausgebaut. Neue Features sind zwar anfangs manchmal etwas fehlerhaft (wie bei fast jeder Software), aber ein, zwei Versionen später recht brauchbar. Da es das Programm schon seit deutlich über zehn Jahre gibt, dürfte "der federführende Student" entweder schon längst bei ST fest angestellt sein, oder es steckt wohl mittlerweile längst ein ganzes Team dahinter.
Spätestens wenn der federführende Student wo anders einen besseren Job
gefunden hat kommt das nächste inkompatible Framework. Mein Bauch sagt
mir, dass es bald wieder so weit sein wird.
Folgender auf ein Minimum reduzierter Code funktioniert mit einem
STM32F411RET6 ohne Probleme:
Das glaube ich dir. Ich habe nur einen STM32F411CEU6 - mit dem funktioniert das fortlaufende Lesen nur mittels Auslesen von USART2->DR; nicht. Das habe ich jetzt genügend getestet. Ich verstehe den hier teilweise auftretenden Unmut, weil es wohl eigentlich funktionieren müsste. Das hilft mir mit meinem speziellen CEU6 nicht weiter. Ihr erklärt mir, wie es normalerweise laufen müsste. Ich probiere es aus und es geht nicht und frage nach wie es funktionieren soll weil die Erklärungen zum normalen Verlauf nicht zum erwarteten Ergebnis führen. Wir reden aneinander vorbei.
Liegt vielleicht an dem speziellen chip. Kommt bei stm wohl schon mal vor.
Das hilft mir mit meinem speziellen CEU6 nicht weiter.
Da im Errata nichts dazu steht, würde ich dazu mal ein minimales Testprogramm erstellen und ST zur Analyse schicken. Vielleicht wird dann das Errata aktualisiert.
Liegt vielleicht an dem speziellen chip. Kommt bei stm wohl schon mal
vor.
Es ist sehr unwahrscheinlich, dass es am Chip liegt, den Fehler solltest Du in erster Linie bei Dir selbst suchen, das ist zu 99% immer so – Code, Aufbau, Design, Testmethode etc. So speziell ist der CEU6 außerdem auch wieder nicht wie man von außen denken könnte – hier ist das Siliziumplättchen vermutlich einfach nur in einem anderen Gehäuse mit weniger Bonding eingekapselt, aber wenn Du Zweifel daran hast, kannst Du Dich mit diesem Anliegen direkt an STM wenden. Viel wichtiger ist außerdem die Revisionsnummer des Chips, aber als ich meine Boards entwickelt habe, habe ich damals nichts Besorgniserregendes zu den F411 und F446 in den Erratas gefunden – die üblichen Fehler halt, die sich in den Kernen von Familie zu Familie wiederholen. Beim STM32F303CCT6 war das z.B. anders – hier ist es wichtig, die richtige Revision beim Kauf erwischt zu haben.