Forum: Mikrocontroller und Digitale Elektronik [STM32F4 ] Usart sendet erst nach 1024 Bytes


von usart (Gast)


Lesenswert?

Hallo

Ich möchte auf dem STM32F4 den USART6 verwenden und habe ihn als Sender 
konfiguriert. Das Problem dabei ist, dass der USART die Daten nicht 
sofort versendet, sondern erst wenn er 1024 Bytes gesammelt hat (das 
Programm sendet jede Sekunde ein Zeichen und nach 1024 Sekunden kommen 
alle auf einmal). Wie bringe ich denn den USART dazu die Daten sofort zu 
versenden?

Hier noch meine Initialisierung:
1
void usart_init(int baudrate)
2
{
3
  GPIO_InitTypeDef GPIO_InitStructure;
4
  USART_InitTypeDef USART_InitStructure;
5
  
6
  // Enable clocks
7
  RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC, ENABLE);
8
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
9
10
  // Enable alternate pin function
11
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
12
13
  // Init Tx pin
14
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
15
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
16
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
17
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
18
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
19
  GPIO_Init(GPIOC, &GPIO_InitStructure);
20
21
  // Init USART
22
  USART_InitStructure.USART_BaudRate = baudrate;
23
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
24
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
25
  USART_InitStructure.USART_Parity = USART_Parity_No;
26
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
27
  USART_InitStructure.USART_Mode = USART_Mode_Tx;
28
  USART_Init(USART6, &USART_InitStructure);
29
  USART_Cmd(USART6, ENABLE);
30
}
31
32
void PrintChar(char c)
33
{
34
  while (USART_GetFlagStatus(USART6, USART_FLAG_TC) == RESET);
35
    USART_SendData(USART6, c);
36
}

von m.n. (Gast)


Lesenswert?

usart schrieb:
> while (USART_GetFlagStatus(USART6, USART_FLAG_TC) == RESET);
>     USART_SendData(USART6, c);

Man müßte wissen, was diese Routinen machen.
TC abzufragen, ist eher ungeschickt, zumal es auch irgendwo gelöscht 
werden müßte.
TXE zu verwenden, dürfte geschickter sein, da es nach der Datenausgabe 
automatisch wieder gesetzt wird.

von M. K. (sylaina)


Lesenswert?

usart schrieb:
> Das Problem dabei ist, dass der USART die Daten nicht
> sofort versendet, sondern erst wenn er 1024 Bytes gesammelt hat (das
> Programm sendet jede Sekunde ein Zeichen und nach 1024 Sekunden kommen
> alle auf einmal).

Klingt so als würde erst ein Buffer voll laufen und dann würde gesendet 
werden. Mal ganz unabhängig davon (kenne des STM nur vom Namen) warum 
überträgst du denn nur mit einer Baudrate von 1? Das erscheint mir wenig 
sinnvoll zu sein.

von Jim M. (turboj)


Lesenswert?

usart schrieb:
> USART die Daten nicht
> sofort versendet, sondern erst wenn er 1024 Bytes gesammelt ha

Der USART hat keinen so großen Puffer, aber ein eventuell vorhandener 
USB2UART oder USB2RS232 Wandler könnte solches Verhalten zeigen. Was für 
ein Gerät nutzt Du an dieser Stelle?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

usart schrieb:
> nach 1024 Sekunden kommen alle auf einmal
Wie merkst du das? Hast du die TX Leitung mit dem Oszilloskop 
kontrolliert?

: Bearbeitet durch Moderator
von usart (Gast)


Lesenswert?

Michael Köhler schrieb:
> Klingt so als würde erst ein Buffer voll laufen und dann würde gesendet
> werden. Mal ganz unabhängig davon (kenne des STM nur vom Namen) warum
> überträgst du denn nur mit einer Baudrate von 1?

Die Baudrate ist nicht 1, ich sende nur ein Zeichen pro Sekunde. Die 
Baudrate beträgt 2 MBaud.

@Jim und Lothar
Ich habe die Leitung mit dem Logikanalyser kontrolliert. Die Daten 
bleiben wirklich im µC bis er seinen Puffer leert.

m.n. schrieb:
> TXE zu verwenden, dürfte geschickter sein, da es nach der Datenausgabe
> automatisch wieder gesetzt wird.

Ich habe folgendes getestet mit gleichem Ergebnis:
1
void PrintChar(char c)
2
{
3
  USART_ClearFlag(USART6, USART_FLAG_TXE);
4
  USART_SendData(USART6, c);
5
  while (USART_GetFlagStatus(USART6, USART_FLAG_TXE) == RESET);
6
}

von holger (Gast)


Lesenswert?

>Ich habe die Leitung mit dem Logikanalyser kontrolliert. Die Daten
>bleiben wirklich im µC bis er seinen Puffer leert.

Der STM hat keinen internen Buffer der 1024 Byte gross ist.
Das Problem wird die Routine sein die Printchar() aufruft.

von usart (Gast)


Lesenswert?

Der Fehler lag gar nicht beim STM32 sondern beim printf Befehl. Aus 
irgendwelchen Gründen wurde da ein Puffer aktiviert. Nach einem
1
setvbuf(stdout, NULL, _IONBF, 0);
 funktioniert es.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

usart schrieb:
> Der Fehler lag gar nicht beim STM32 sondern beim printf Befehl.

Was mal wieder zeigt, dass das Problem meist nicht im gezeigten Code 
steckt, sondern ganz woanders. printf hattest Du bis dato noch nichtmals 
erwähnt.

Ich habe keine Ahnung vom STM, aber wenn es ein stdio-ähnliches printf() 
gibt, dann vielleicht auch ein fflush(), mit dem man die Ausgabe 
erzwingen kann? Das könnte unter bestimmten Umständen effizienter sein 
als den Ringbuffer komplett abzuschalten.

von usart (Gast)


Lesenswert?

Frank M. schrieb:
> Was mal wieder zeigt, dass das Problem meist nicht im gezeigten Code
> steckt, sondern ganz woanders. printf hattest Du bis dato noch nichtmals
> erwähnt.

Richtig. Allerdings funktionierte printf auch schon seit Tagen mit 
Uart3. Ich hab keine Ahnung durch welche Änderung das jetzt plötzlich 
gepuffert ist.

Ich wüsste eigentlich nicht was der Puffer überhaupt bringen sollte. Ob 
man es in einen Puffer schreibt oder direkt dem USART übergibt ist 
eigentlich egal, außer man verwendet DMA.

von FIFO (Gast)


Lesenswert?

usart schrieb:
> ch wüsste eigentlich nicht was der Puffer überhaupt bringen sollte. Ob
> man es in einen Puffer schreibt oder direkt dem USART übergibt ist
> eigentlich egal

Nö, direkt in den USART passt nur ein Byte, in den Puffer halt mehr. 
Der Vorteil vom Puffer, man braucht sich nicht um jedes Zeichen einzeln 
kümmern.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

usart schrieb:
> Ich wüsste eigentlich nicht was der Puffer überhaupt bringen sollte. Ob
> man es in einen Puffer schreibt oder direkt dem USART übergibt ist
> eigentlich egal, außer man verwendet DMA.

Nehmen wir an, Du müsstest 1000 Bytes schreiben. Wenn Du keinen 
Ringbuffer hast, musst Du nach jedem Zeichen warten, bis es gesendet 
wurde, bis Du das nächste Zeichen dem USART übergeben kannst[1]. 
Währenddessen etwas anderes zu machen, damit Dein µC die ganze Zeit 
während der Übertragung nicht brachliegt, ist dann schon etwas knifflig 
zu bewerkstelligen.

Wenn Du die 1000 Byte in einen Ringbuffer schreibst, brauchst Du dafür 
einen Bruchteil der Zeit und hast den Rest der Zeit frei, etwas anderes 
zu tun.

Wenn Du nur ein "Hello, World"-Programm schreibst, dann gebe ich Dir 
recht. Dann brauchst Du tatsächlich keinen Buffer. Aber diese Art von 
Programmen schreibt man recht selten für µCs ;-)

[1] Diese Aussage stimmt nicht ganz, beschreibt es aber grob.

: Bearbeitet durch Moderator
von M. K. (sylaina)


Lesenswert?

usart schrieb:
> Die Baudrate ist nicht 1, ich sende nur ein Zeichen pro Sekunde. Die
> Baudrate beträgt 2 MBaud.

Also ein Baudrate von 1 würde dir genügen? Ich frag nur aus Interesse. 
Ich war noch nie in der "Bedrängnis" nur ein Zeichen pro Sekunde zu 
übertragen. Daher meine Neugierde.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael Köhler schrieb:
> Ich war noch nie in der "Bedrängnis" nur ein Zeichen pro Sekunde zu
> übertragen. Daher meine Neugierde.
Könnte sein, dass das ein "Alive" Signal ist, mit dem eine Komponente 
mitteilt, dass sie noch da ist, aber gerade keine Daten hat...

Manchmal kann es sogar sein, dass eine serielle Schnittstelle ein halbes 
Jahr lang gar nichts überträgt. Und dann ganz schnell wieder viele 
Daten, wenn ich z.B. meine Telefonanlage wieder umkonfiguriere.

von usart (Gast)


Lesenswert?

Frank M. schrieb:
> Wenn Du die 1000 Byte in einen Ringbuffer schreibst, brauchst Du dafür
> einen Bruchteil der Zeit und hast den Rest der Zeit frei, etwas anderes
> zu tun.

Das ist richtig. Die gleiche Zeit brauche ich dann aber für den 
blockierenden Transfer. Ich finde ein Buffer macht nur Sinn wenn der 
Transfer DMA oder Interrupt basiert ist.

Das eine Zeichen pro Sekunde war übrigens ein Startzeichen für kommende 
Debugausgaben. Die waren aber bei dem Test ausgeschalten. Daher wurde 
immer nur das Startzeichen alleine gesendet.

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.