Forum: Mikrocontroller und Digitale Elektronik STM32 USART: es wird nichts gesendet


von har (Gast)


Lesenswert?

Liebes Forum,

ich habe das Eval-Board "STM32F3DISCOVERY". Darauf befindet sich der 
STM32F303. Ich möchte die USART2 in Betrieb nehmen, daher war mein 
erstes Ziel die TX und RX Pins verbinden und die Zahl 0x55 zu senden und 
gleichzeitig zu empfangen.
Da ich dabei nicht erfolgreich war, wollte ich sehen, ob überhaupt etwas 
gesendet wird.
Ich habe ein Oszilloskop an den TX-Pin gehängt und habe bemerkt, dass 
nichts gesendet wird. Ich habe das ausprobiert, in dem die Zahl 0x55 in 
einer Endlosschleife permanent gesendet wird.
Dieser Pin geht lediglich auf High.

Hier ist mein Programm-Code:
1
#include <stm32f30x.h>
2
#include <stm32f30x_gpio.h>
3
#include <stm32f30x_rcc.h>
4
#include <stm32f30x_usart.h>
5
6
7
void InitializeUSART()
8
{
9
    USART_InitTypeDef usartConfig;
10
11
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
12
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
13
 
14
    USART_Cmd(USART2, ENABLE);
15
16
    usartConfig.USART_BaudRate = 9600;
17
    usartConfig.USART_WordLength = USART_WordLength_8b;
18
    usartConfig.USART_StopBits = USART_StopBits_1;
19
    usartConfig.USART_Parity = USART_Parity_No;
20
    usartConfig.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
21
    usartConfig.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
22
    USART_Init(USART2, &usartConfig);
23
24
25
    GPIO_InitTypeDef gpioConfig;
26
27
    //PB3 = USART2.TX => Alternative Function Output
28
    gpioConfig.GPIO_Mode = GPIO_Mode_AF;
29
    gpioConfig.GPIO_Pin = GPIO_Pin_3;
30
    gpioConfig.GPIO_Speed = GPIO_Speed_2MHz;
31
    GPIO_Init(GPIOB, &gpioConfig);
32
33
    //PB4 = USART2.RX => Input
34
    gpioConfig.GPIO_Mode = GPIO_Mode_IN;
35
    gpioConfig.GPIO_Pin = GPIO_Pin_4;
36
    GPIO_Init(GPIOB, &gpioConfig);
37
}
38
39
40
unsigned char USART_ReadByteSync(USART_TypeDef *USARTx)
41
{
42
    while (USART_GetFlagStatus(USARTx, USART_IT_RXNE) == RESET)       
43
    {
44
45
    }
46
47
    return (unsigned char)USART_ReceiveData(USARTx);
48
}
49
50
51
52
int main ()
53
{
54
    SystemInit();
55
    InitializeUSART();
56
57
    for (;;)
58
    {
59
        while(1)
60
        {
61
            USART_SendData(USART2, 0x55);
62
            asm("nop");
63
        }
64
        USART_SendData(USART2, 0x55);
65
        unsigned char byte = USART_ReadByteSync(USART2);
66
67
        asm("nop");
68
    }
69
}

von W.S. (Gast)


Lesenswert?

Und nun?

RCC (Takte) richtig aufgesetzt?
GPIO's richtig aufgesetzt?
AFIO auch richtig aufgesetzt?

Und auch den USART richtig aufgesetzt? Als USART oder UART?
Woher soll unsereiner wissen, was die ominöse USART_Init alles macht? 
Und was macht USART_Senddata denn? Wartet das auf das Sendeende des 
vorherigen Zeichens? Wozu soll das asm(NOP) gut sein?

Kurzum, aus deinem Post dir einen Rat zu geben, fällt schwer.

Außer: gehe systematisch vor, laß die ganze ST-Lib usw. bleiben und lies 
im RefManual, was zum Takte aufsetzen und verteilen nötig ist, wie man 
die Portpins richtig ausetzt und die Peripheriecores richtig benutzt.

W.S.

von STMQuerleser (Gast)


Lesenswert?

W.S. schrieb:
> Woher soll unsereiner wissen, was die ominöse USART_Init alles macht?

Indem du die Funktion InitializeUSART() anschaust.

har schrieb:
> Hier ist mein Programm-Code:

Das ist zwar nicht der Fehler den du suchst (und den ich momentan
auch nicht sehe) aber

har schrieb:
> //PB4 = USART2.RX => Input
>     gpioConfig.GPIO_Mode = GPIO_Mode_IN;
>     gpioConfig.GPIO_Pin = GPIO_Pin_4;
>     GPIO_Init(GPIOB, &gpioConfig);

der RX-Pin muss sicher auch auf Alternate Function programmiert
werden sonst wirst du nichts empfangen können (der Datenstrom
wird nicht zum USART geleitet).

von STMQuerleser (Gast)


Lesenswert?

har schrieb:
> USART_Cmd(USART2, ENABLE);

Ich habe das für diesen Fall nicht weiter verifiziert aber
manche Peripherie-Blöcke in ARM-/STM-Controllern können nur
offline initialisiert bzw. umprogrammiert werden.

Für diesen Fall wäre obige zitierte Zeile möglichst ans Ende
aller Initialisierungen des USART zu setzen und nicht schon
zu Beginn .....

von W.S. (Gast)


Lesenswert?

STMQuerleser schrieb:
> der RX-Pin muss sicher auch auf Alternate Function programmiert
> werden sonst wirst du nichts empfangen können (der Datenstrom
> wird nicht zum USART geleitet).

Gilt nicht immer. Beim STM32F10x zum Beispiel sagt das Refman, daß 
Alternativfunktionen, die aus einem Input bestehen, auch den Pin als 
Input benötigen. Bei Altfu's die ein Ausgang sind, muß man hingegen das 
Bit für Alternativausgang wählen. Für die 'F3xx muß der TO halt das 
Manual zu Rate ziehen.

W.S.

von har (Gast)


Lesenswert?

Ich habe leider den Fehler noch nicht gefunden...

Mit ist aber beim googeln folgendes aufgefallen:
Beim Einschalten der Clocks habe ich immer wieder folgenden Code 
gesichtet:
1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

Wenn ich diese Zeile zu meinem Code hinzufüge, ist der Compiler damit 
nicht einverstanden: "undeclared"

Weiß jemand, wofür "RCC_APB2Periph_AFIO" steht bzw. ob ich das ev auch 
benötige?

Vielen Dank für eure Hilfe!

von Nico W. (nico_w)


Lesenswert?

Reference Manual angesehen?
B3 und B4 sind debug pins. Könnte hier auch ein Problem sein. Da muss 
man den AFR explizit vorher zurück setzen. Keine Ahnung ob das deine HAL 
macht.

Hast du denn nun auch RX als alternate function konfiguriert?

von har (Gast)


Lesenswert?

Nico W. schrieb:
> Reference Manual angesehen?
> B3 und B4 sind debug pins. Könnte hier auch ein Problem sein. Da muss
> man den AFR explizit vorher zurück setzen. Keine Ahnung ob das deine HAL
> macht.
Habe es nun auch mit anderen Pins probiert. Bin leider noch immer 
erfolglos...

Nico W. schrieb:
> Hast du denn nun auch RX als alternate function konfiguriert?
Hab ich, aber um nur mal etwas zu senden, sollte das egal sein!

von Little B. (lil-b)


Lesenswert?

Ich kenne mich mit der HAL nicht aus, da ich für gewöhnlich auf 
Register-Ebene arbeite. Jedoch fallen mir ein paar Sachen auf, die du 
fixen solltest:

- USART erst aktivieren, wenn er fertig initialisiert ist.
- Rx Pin muss für deinen Chip auch AF sein, sonst empfängst du nix (zum 
senden ists aber wurst)
- Alternate Functions müssen auch konfiguriert werden. Das fehlt bei dir 
noch komplett. Setze gpioConfig.Alternate auf 7.
- Du überfährst gnadenlos den Tx Buffer. Warte auf freien Buffer mit dem 
codeschnipsel "while (USART_GetFlagStatus(USARTx, USART_IT_TXE) == 
RESET);"

btw: das nop ist wirklich überflüssig

von har (Gast)


Lesenswert?

Zu folgendem Punkt hätte ich eine Frage:

Little B. schrieb:
> Alternate Functions müssen auch konfiguriert werden. Das fehlt bei dir
> noch komplett. Setze gpioConfig.Alternate auf 7

Kannst du mir genauer sagen, wie ich die Alternate auf 7 setze?
Als Anfänger kenne ich mich zu wenig aus, dass ich das jetzt umsetzen 
kann...

Danke im Voraus

von greg (Gast)


Lesenswert?

har schrieb:
> Kannst du mir genauer sagen, wie ich die Alternate auf 7 setze?

Siehe Datenblatt, da ist eine große Tabelle zur Zuordnung von Pins zu 
Alternate Functions... AF0 bis AF15.

von har (Gast)


Lesenswert?

Hab jetzt folgende Zeile eingefügt:
GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_7)

Und es funktioniert, es wird gesendet!! Vielen Dank an euch alle für 
eure Hilfe!


Nun das nächste Problem: Nachdem ich TX- und RX-Pin miteinander 
verbunden habe, empfange ich leider nichts.

Der Code für die Konfiguration zum Empfangen lautet:
1
    //PB4 = USART2.RX => Input
2
    gpioConfig.GPIO_Mode = GPIO_Mode_AF;
3
    gpioConfig.GPIO_Speed = GPIO_Speed_10MHz;
4
    gpioConfig.GPIO_Pin = GPIO_Pin_4;
5
    GPIO_Init(GPIOB, &gpioConfig);

Und zum Empfangen:
1
byte = USART_ReadByteSync(USART2);
2
3
4
unsigned char USART_ReadByteSync(USART_TypeDef *USARTx)
5
{
6
    while (USART_GetFlagStatus(USARTx, USART_IT_RXNE) == RESET)
7
    {
8
9
    }
10
11
    return (unsigned char)USART_ReceiveData(USARTx);
12
}

von STMQuerleser (Gast)


Lesenswert?

har schrieb:
> Hab jetzt folgende Zeile eingefügt:
> GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_7)

Naja .... das gleiche wirst du für den Rx-Pin auch machen müssen.

har schrieb:
> Nun das nächste Problem:

von har (Gast)


Lesenswert?

STMQuerleser schrieb:
> Naja .... das gleiche wirst du für den Rx-Pin auch machen müssen.

Das habe ich bereits probiert.

Das komische dabei ist, dass sobald ich diese Zeile einfüge:
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_7);

auf einmal nichts mehr gesendet werden kann. (GPIOB4 ist der Pin zum 
empfangen und sollte eigentlich nichts mit dem senden zu tun haben).
Beim Debuggen bleibt er nämlich in folgender while-schliefe hängen:
1
while(USART_GetFlagStatus(USART2, USART_IT_TXE) == RESET);
2
            {
3
                USART_SendData(USART2, 0x53);
4
            }

von Philipp H. (swissrookie)


Lesenswert?

Ich hatte vor kurzem auch Anlaufschwierigkeiten mit UART und STM32. 
Mittlerweile funktioniert alles wie gewünscht.

Was mir hier aufgefallen ist: Du wartest auf das TX-Interrupt Flag 
(USART_IT_TXE), hast aber keinen Interrupt konfiguriert? Willst du nur 
den Eingangsbuffer überprüfen? Dann wäre es doch das hier?
1
(#) USART_FLAG_RXNE: to indicate the status of the receive buffer register.

Und in deiner Main-Routine wird momentan ohne um Erlaubnis zu fragen auf 
das Datenregister der UART eingehämmert. Kann das damit zu tun haben? In 
meinen Sendefunktionen kommt immer zuerst die Abfrage.
1
// wait until data register is empty
2
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
3
USART_SendData(USARTx, *s);

edit:
.. und die AF für UART muss für beide Pins aktiviert werden. Etwas in 
dieser Richtung. Bei mir ist es ein STM32F0 mit der UART1
1
// Beide IO's der AF zuweisen
2
// (Wichtig: nicht zusammenfassen wie bei GPIO_InitStructure.GPIO_Pin sondern einzeln aufrufen!)
3
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
4
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);

: Bearbeitet durch User
von har (Gast)


Lesenswert?

Vielen Dank Philipp H.

Die Punkte die du genannt hast waren entscheidend. Es funktioniert 
jetzt!!
Jetzt habe ich wieder Anhaltspunkte, wo ich mich mehr einlesen muss.

Das sind halt die Nachteile, wenn man mittels "Copy Paste" versucht zu 
lernen...

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.