Forum: Mikrocontroller und Digitale Elektronik stm32f411 USART2 will nicht wie er soll


von Karl K. (leluno)


Lesenswert?

1
extern volatile uint8_t rx_buff[];
2
extern volatile uint8_t rx_buff_ct;
3
void USART2_IRQHandler_kk(void)
4
{
5
  rx_buff[rx_buff_ct++]=USART2->DR;
6
  USART2->CR1 &= ~USART_CR1_RE;
7
  USART2->CR1 |= USART_CR1_RE;//
8
  //_delay_us(15);
9
10
if(rx_buff_ct==7)
11
{
12
  rx_buff_ct=0;
13
  lcd_goto(15,1);//
14
  lcd_int2(rx_buff[0]);//
15
lcd_write(" ");
16
lcd_int2(rx_buff[1]);//
17
lcd_write(" ");
18
lcd_int2(rx_buff[2]);//
19
lcd_write(" ");
20
lcd_int2(rx_buff[3]);//
21
lcd_write(" ");
22
lcd_int2(rx_buff[4]);//
23
lcd_write(" ");
24
lcd_int2(rx_buff[5]);//
25
lcd_write(" ");
26
lcd_int2(rx_buff[6]);//
27
lcd_write(" ");
28
}

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).

Was mache ich falsch?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> Was mache ich falsch?

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.

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Warum schaltest du innerhalb der ISR den Receiver aus und wieder ein?

Beitrag "Re: STM32F4xx UART-State während des Empfangs zurücksetzen"

Sherlock 🕵🏽‍♂️ schrieb:
> Du hast zu viel Arbeit in die ISR gepackt.

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
1
  huart2.Instance = USART2;
2
  huart2.Init.BaudRate = 115200;
3
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
4
  huart2.Init.StopBits = UART_STOPBITS_1;
5
  huart2.Init.Parity = UART_PARITY_NONE;
6
  huart2.Init.Mode = UART_MODE_TX_RX;
7
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
8
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
9
  if (HAL_UART_Init(&huart2) != HAL_OK)
10
  {
11
    Error_Handler();
12
  }
13
14
 /* USER CODE BEGIN USART2_Init 2 */
15
   huart2.Instance = USART2;
16
    huart2.Init.BaudRate = 9600;
17
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
18
    huart2.Init.StopBits = UART_STOPBITS_1;
19
    huart2.Init.Parity = UART_PARITY_NONE;
20
    huart2.Init.Mode = UART_MODE_TX_RX;
21
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
22
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;
23
    if (HAL_UART_Init(&huart2) != HAL_OK)
24
    {
25
      Error_Handler();
26
    }
27
  /* USER CODE END USART2_Init 2 */
kann es ja irgendwie nicht sein?

von Kevin M. (arduinolover)


Angehängte Dateien:

Lesenswert?

Karl K. schrieb:
> Kann mir jemand verraten, wo man bei Cube die Usart-Baudrate einstellt?
> Habe das im ioc nicht gefunden

So versteckt ist die Einstellung jetzt auch nicht....

von Harry L. (mysth)


Lesenswert?

Karl K. schrieb:
> kann es ja irgendwie nicht sein?

Doch, so geht das.

Schau dir meinen Code mal an!
Der funktioniert bei mir in vielen Projekten sehr zuverlässig:

Beitrag "[STM32/HAL] simples U(S)ART-Library"

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Karl K. schrieb:
> kann es ja irgendwie nicht sein?

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.

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Matthias S. schrieb:
> Wenn du zweimal hintereinander USART2 initialisierst, solltest du
> dazwischen ein De_Init auslösen.
Ist beim U(S)ART mit HAL tatsächlich nicht erforderlich.
Ein "beherztes Init" reicht in diesem Fall aus.

Allerdings sollte das die Ausnahme sein.

Im Normalfall stellt man die Parameter einmal im CubeMX ein, und kümmert 
sich nicht weiter darum.

Die Geschwindigkeit oder das Frame-Format im laufenden Betrieb zu 
wechseln, dürfte ein eher exotisches Scenario sein...ist aber auch kein 
Hexenwerk.

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Kevin M. schrieb:
> So versteckt ist die Einstellung jetzt auch nicht....

trotzdem danke

Harry L. schrieb:
> Schau dir meinen Code mal an!

danke - mach ich morgen

von Karl K. (leluno)


Angehängte Dateien:

Lesenswert?

2 x 0xff vom PC gesendet. Das Osci erkennt 0x1f.

Zeit zwischen Zwei steigenden Flanken 1,14ms. Müsste sein 
1sec/9600/(1+8+1)=1,0416ms.

Ich werde jetzt mal versuchen, die Zeit zwischen  zwei Interrupts des 
stm zu messen.

ist
1
  rx_buff[rx_buff_ct++]=USART2->DR;
2
  USART2->CR1 &= ~USART_CR1_RE;
3
  USART2->CR1 |= USART_CR1_RE;//

für Abholen des Bytes und Rücksetzen auf Lesezustand ausreichend und 
richtig?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Du resettest den Receiver nach jedem einzelnen Byte während er das 
nächste Byte empfängt. Du verpasst bzw. verwirfst also jedes zweite 
Byte.

Was du vermutlich machen wolltest:

Erst NACH dem Empfang des siebten Bytes den Receiver disablen, dann dir 
7 Bytes verarbeiten/anzeigen, und DANACH den Receiver wieder enablen.

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Du resettest den Receiver nach jedem einzelnen Byte während er das
> nächste Byte empfängt. Du verpasst bzw. verwirfst also jedes zweite
> Byte.


Ist das so? RXNE wir ausgelöst zum Zeitpunkt "Anfang bis Mitte 
Stoppbit". Es ist dann zumindest Zeit bis zum nächsten Startbit.

Ich habe leider vergeblich versucht herauszufinden, welche Register-Bits 
in den HAL-UART-Routinen gesetzt und geschrieben werden.

Allein das Lesen von USART2->DR führt jedenfalls nicht dazu, dass DR für 
das Lesen des nächsten Bytes freigegeben wird.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> 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?

Karl K. schrieb:
> Allein das Lesen von USART2->DR führt jedenfalls nicht dazu, dass DR für
> das Lesen des nächsten Bytes freigegeben wird.

Beim F1, F3 und L0 ist das aber ganz sicher so.

Und im Referenzhandbuch vom F4 steht:
"In single buffer mode, clearing the RXNE bit is performed by a software 
read to the USART_DR register. "

https://www.st.com/resource/en/reference_manual/rm0383-stm32f411xce-advanced-armbased-32bit-mcus-stmicroelectronics.pdf

von Harry L. (mysth)


Lesenswert?

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!

RTFM !

https://oku.ozturkibrahim.com/docs_stm32f4/UM1725_User_manual_rev6.pdf

: Bearbeitet durch User
von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> 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.

: Bearbeitet durch User
von Mi N. (msx)


Lesenswert?

Karl K. schrieb:
> Was mache ich falsch?

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.

Harry L. schrieb:
> Im Normalfall stellt man die Parameter einmal im CubeMX ein, und kümmert
> sich nicht weiter darum.

Im 'Normalfall' braucht man CubeMX dafür garnicht ;-)

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Mi N. schrieb:
> Im 'Normalfall' braucht man CubeMX dafür garnicht

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.

von Karl K. (leluno)


Lesenswert?

Mi N. schrieb:
> 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.



Harry L. schrieb:
> 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.

Sherlock 🕵🏽‍♂️ schrieb:
> Und im Referenzhandbuch vom F4 steht:
> "In single buffer mode, clearing the RXNE bit is performed by a software
> read to the USART_DR register. "

Das Löschen des RXNE funktioniert auch - nur das DR-Register wird nicht 
geleert oder freigegeben.

von Werner P. (werner4096)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Karl K. schrieb:
>> 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.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> 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;
ja

> nur dann hört es mit dem Empfangen auf.

OK, verstanden. Hast du inzwischen meinen Korrekturvorschlag 
ausprobiert?

> 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.

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.

: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Karl K. schrieb:
> 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.
1
    if (LL_USART_IsActiveFlag_RXNE(USART1) != 0)
2
    {
3
      //ch_temp = USART_ReceiveData(USART1);
4
      buff[idx] = (USART1->DR & (uint16_t)0x01FF);
5
      idx++;
6
      ..... etc
7
    }

von Wastl (hartundweichware)


Lesenswert?

Karl K. schrieb:
> Das Problem ist m.E. das Timing des Senders. Das haut die
> STM-Fehlerabfragen zu und dann geht rx halt nicht mehr.

Käse! Sobald du das RX Register gelesen hast ist es automatisch
frei für den nächsten Empfang.

Karl K. schrieb:
> 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.

Brauchst du nicht, wie gerade vorher beschrieben.

Karl K. schrieb:
> Das Problem ist m.E. das Timing des Senders.

Nein! Das Problem ist dass du viel zu viel Zeit in der
ISR verschwendest. Es ist nicht egal wo man ein und
dieselbe Aufgabe erledigt.

von Wastl (hartundweichware)


Lesenswert?

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.

Harry L. schrieb:
> Schau dir meinen Code mal an!
> Der funktioniert bei mir in vielen Projekten sehr zuverlässig:
>
> Beitrag "[STM32/HAL] simples U(S)ART-Library"

.... ist durchaus empfehlenswert!

von J. S. (jojos)


Lesenswert?

Eine Tücke ist das es beim Cortex-M mehrere Busse gibt und die Devices 
asynchron laufen, das ist nicht so einfach wie bei AVR.

von Mi N. (msx)


Angehängte Dateien:

Lesenswert?

J. S. schrieb:
> Eine Tücke ist das es beim Cortex-M mehrere Busse gibt und die Devices
> asynchron laufen, das ist nicht so einfach wie bei AVR.

Nur darum muß man sich hier garnicht kümmern, außer die passende 
Bustaktfrequenz für die Baudrateneinstellung zu verwenden.

Wastl schrieb:
> 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.

'HAL'frei und vegan! ;-)

von Karl K. (leluno)


Lesenswert?

Mi N. schrieb:
> 'HAL'frei und vegan! ;-)

Danke, das war es wohl:
1
void clr_rx3_buf()
2
{
3
  USART3->CR1 &= ~(USART_CR1_RXNEIE);   // RXIE abschalten
4
  __ISB();
5
  usart3_rx_lese_zeiger = 0;
6
  usart3_rx_schreib_zeiger = 0;
7
  USART3->CR1 |= (USART_CR1_RXNEIE);    // RXIE einschalten
8
}

statt
1
  rx_buff[rx_buff_ct++]=USART2->DR;
2
  USART2->CR1 &= ~USART_CR1_RE;
3
  USART2->CR1 |= USART_CR1_RE;

läuft es mit
1
  rx_buff[rx_buff_ct++]=USART2->DR;
2
  USART2->CR1 &= ~(USART_CR1_RXNEIE);
3
  USART2->CR1 |= (USART_CR1_RXNEIE);

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> 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?

Bei mir sehen die ISR ganz schlicht so aus:
1
void USART2_IRQHandler()
2
{
3
    char c = USART2->DR;
4
    // do something with c
5
}

Weitere Registerzugriffe finden dort nicht statt.

Das vollständige Beispiel ist auf: 
http://stefanfrings.de/stm32/stm32f1.html#usart

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Karl K. schrieb:
>> 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?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> 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
extern uint8_t  console_rx_byte;
2
extern uint8_t  console_rx_irq;
3
4
void USART2_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.
10
11
    // Store incoming byte
12
    console_rx_byte = USART2->RDR;
13
    console_rx_irq = 1;
14
  }
15
}
https://www.pomad.fr/tutorials/stm32/uart_tx_interrupts

: Bearbeitet durch User
von Gregor J. (Firma: Jasinski) (gregor_jasinski)



Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> 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.

von Wastl (hartundweichware)


Lesenswert?

Gregor J. schrieb:
> 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.

: Bearbeitet durch User
von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Ü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.

von Karl K. (leluno)


Lesenswert?

Wastl schrieb:
> 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.


Sherlock 🕵🏽‍♂️ schrieb:
> 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.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Gregor J. schrieb:
> Ü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.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> Der Professor greift statt des DR das RDR-Register ab

Weil das ein Beispiel für den STM32F072 ist, der hat kein DR Register 
(stattdessen RDR und TDR).

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> 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.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Gregor J. schrieb:
> Die meisten AVRs haben für RX und TX getrennte Interruptvektoren

Na und? Erstens diskutieren wir hier nicht über AVR, und zweitens hast 
du unabhängig davon geschrieben:

> wer zusätzlich den Sende-Interrupt aktiviert ... ist selber schuld

von Karl K. (leluno)


Lesenswert?

Karl K. schrieb:
> Der Professor Laurent Latorre sieht das sieht vielen Jahren genau so:

ausprobiert:
1
   if ((USART2->SR & USART_SR_RXNE) == USART_SR_RXNE)
2
    {
3
      // RXNE flags automatically clears when reading RDR.
4
      // Store incoming byte
5
    rx_buff[rx_buff_ct++] = USART2->DR;
6
            //console_rx_byte = USART2->RDR;
7
      //console_rx_irq = 1;
8
    }

liest immer das erste Byte - und dann ist Schluss. Mag bei einem F0 
funktionieren - bei meinem F4 nicht.

von Wastl (hartundweichware)


Lesenswert?

Karl K. schrieb:
> ausprobiert:

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 .....

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

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.

von Wastl (hartundweichware)


Lesenswert?

Gregor J. schrieb:
> .............

Das ist zuviel des Guten für einen Troll.

von Karl K. (leluno)


Lesenswert?

Gregor J. schrieb:
> USART1->DR = USART1->DR;

daran hab ich keine Zweifel. Das ist so und das bleibt so.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Mi N. schrieb:
>> Im 'Normalfall' braucht man CubeMX dafür garnicht
>
> 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.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

>> 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.

Andreas S. schrieb:
> Unsinn.

Sage das keinem Bauch :-)

Spaß beiseite: Ich würde mich natürlich freuen, wenn das noch lange 
weiter gepflegt wird.

von Karl K. (leluno)


Lesenswert?

Gregor J. schrieb:
> 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.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Karl K. schrieb:
> 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.

von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Karl K. schrieb:
> 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.

: 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
Noch kein Account? Hier anmelden.