Forum: Mikrocontroller und Digitale Elektronik empfangene UART Bytes fehlerhaft - STM32


von Tom L. (munzi)


Lesenswert?

Hallo,

ich möchte einen STM32F103CB (Sender) mit einem STM32F103RB (Empfänger) 
mittels UART verbinden. Die Daten werden wie gewünscht aus einem 
Byte-Array Byte für Byte übertragen. Das der Sender die korrekten Daten 
losschickt sehe ich im Terminal und im Logic-Analyzer. Leider kommen am 
Empfänger andere Daten an - allerdings reproduzierbar, d.h. sende ich 
die selben Daten erneut, erhalte ich am Empfänger wieder die selben, 
falschen Daten.

Die Controller sind einfach über ein Kabel vom Tx-Pin des Senders mit 
dem Rx-Pin des Empfängers verbunden.

Hier ein Beispiel. Links die gesendeten und auch über RS232 
mitgeschnittenen Daten, rechts die empfangenen. Das lässt sich wie 
gesagt reproduzieren.

1 - 0
2 - 0
1 - 0
11 - 2
0 - 0
20 - 4
0 - 0
14 - 12
31 - 30
52 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
0 - 0
255 - 254
255 - 254
255 - 254
255 - 254

Beim Empfänger wird ein Rx-Interrupt ausgelöst und dort schreibe ich die 
Daten zu Debugzwecken direkt in einen großen Puffer.

Hier noch die Initialisierung des UARTs der Controler (aus 
Online-Beispiel kopiert):
Sender:
1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, (FunctionalState)ENABLE);
2
    USART_InitTypeDef USART_InitStructure;
3
    USART_TypeDef USART_Structure;
4
5
    USART_InitStructure.USART_BaudRate = 9600UL;
6
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
7
    USART_InitStructure.USART_Parity = USART_Parity_No;
8
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
9
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
10
    USART_Init(USART1, &USART_InitStructure);
11
    USART_Cmd(USART1, (FunctionalState)ENABLE);

und Empfänger:
1
    USART_InitTypeDef USART_InitStructure;
2
    USART_ClockInitTypeDef USART_ClockInitStructure;
3
    NVIC_InitTypeDef NVIC_InitStructure;
4
5
    //enable bus clocks
6
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
7
8
    USART_ClockStructInit(&USART_ClockInitStructure);
9
    USART_ClockInit(USART1, &USART_ClockInitStructure);
10
11
    USART_InitStructure.USART_BaudRate = 9600UL;
12
    USART_InitStructure.USART_Mode = USART_Mode_Rx;
13
    USART_InitStructure.USART_Parity = USART_Parity_No;
14
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
15
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
16
    USART_Init(USART1, &USART_InitStructure);
17
    USART_Cmd(USART1, (FunctionalState)ENABLE);
18
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
19
20
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;        // we want to configure the USART1 interrupts
21
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts
22
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       // this sets the subpriority inside the group
23
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          // the USART1 interrupts are globally enabled
24
    NVIC_Init(&NVIC_InitStructure);

und noch vereinfacht die Empfangs-ISR (USART_ReceiveData() ist aus der 
stm32f10x_usart):
1
volatile u8 u8Buff[150] = {0};
2
volatile u8 u8I;
3
//...
4
        if (USART_GetITStatus(USART1, USART_IT_RXNE) ) { // check if the USART1 receive interrupt flag was set
5
          volatile char u8Data = (USART_ReceiveData (USART1));
6
7
          if (u8I <= 150) {
8
            u8Buff[u8I] = u8Data;
9
            u8I++;
10
          } else {
11
            u8I = 0;
12
          }
13
//...
14
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);

Beide Controller laufen mit 72Mhz internem Takt. Zwischen beiden sind 
etwa 30cm Kabel.

Ich kann mir die fehlerhaften Daten am Empfänger nicht erklären, da ja 
Sender und Empfänger bezügl. des UART gleich initialisiert wurden. Habe 
ich einen Denkfehler? Kann mir jemand helfen?

von Stefan F. (Gast)


Lesenswert?

Da ist was faul. Der Puffer hat 150 bytes, deren Indizies von 0 bis 149 
gehen. In der Interrupt Routine beschreibts Du die Indizies 0 bis 150, 
also ein Byte zuviel. Dadurch überschreibst Du ungewollt andere Daten im 
RAM.

Bist Du sicher, dass Du beim Auslesen des Puffers an der richtigen 
Stelle liest? Denn nach dem schreiben wird der Index u8I erhöht, er 
zeigt also nicht auf das zuletzt empfangene Byte.

Ein anständiger Ringpuffer benötigt zwei Zeiger, nämlich einen auf das 
erste noch nicht gelesenen Byte und einen auf das letzte geschrieben 
Byte. Die Differenz der beiden Zeiger ist die Anzahl der nocht nicht 
ausgelesenen Bytes im Puffer.

Zum Debugging würde ich die Interrupt Routine mal so umschreiben, dass 
sie jedes empfangene Byte auf ein Display ausgibt. Den Sender müsstest 
DU dann natürlich etwas ausbremsen, weil die Display Ausgabe relativ 
viel zeit in Anspruch nimmt.

von Tom L. (munzi)


Angehängte Dateien:

Lesenswert?

Ich habe die Daten jetzt über ein Display ausgegeben und ein Foto davon 
angehängt.

Das Array wird tatsächlich über seine Grenze hinaus beschrieben - 
allerdings liegt da nicht das Problem da ich nur die obenstehenden 22 
Byte hineingeschrieben hatte.

Ich habe nun ein paar Bytes zum Testen übertragen und am Sender direkt 
im Interrupthandler auf ein Display ausgegeben. Das Ergebnis bleibt das 
Gleiche:

(Sender)   - (Empfänger)
0   (0x00) - 0   (0x00)
1   (0x01) - 0   (0x00)
2   (0x02) - 0   (0x00)
3   (0x03) - 2   (0x02)
4   (0x04) - 4   (0x04)
5   (0x05) - 0   (0x00)
6   (0x06) - 4   (0x04)
7   (0x07) - 6   (0x06)
8   (0x08) - 8   (0x08)
15  (0x0F) - 14  (0x0E)
16  (0x10) - 0   (0x00)
51  (0x33) - 34  (0x22)
85  (0x55) - 0   (0x00)
170 (0xAA) - 0   (0x00)
172 (0xAC) - 12  (0x0C)
202 (0xCA) - 192 (0xC0)
241 (0xF1) - 240 (0xF0)
254 (0xFE) - 252 (0xFC)
255 (0xFF) - 254 (0xFE)

Ich habe immer noch keine Ahnung was das Problem der fehlerhaften Daten 
am Empfänger sein könnte.

von Patrick B. (p51d)


Lesenswert?

Mhm, das ist ja komisch. Zeig mal den ganzen Code (Main-Funktion, alle 
Interrupt-Funktionen), nicht nur Fragmente.

Kleiner Tip: Nutze die InitStruct-Funktionen um Fehler zu verhindern 
(ungewollte Initialisierungen...).

Hast du Oversampling eingeschaltet? 9600 Baut sollten absolut kein 
Problem sein, selbst bei 3m Kabel.

von Tom L. (munzi)


Lesenswert?

Habe das Problem jetzt gerade nach Tagen des Rätselns selbst gelöst.

Ich hatte die GPIO-Pins direkt vor der Initialisierung des UART in der 
Funktion CUART::m_vInit initialisiert. Verschiebe ich die 
Initialisierung in die zuvor aufgerufene CGPIO::m_vInit, die auch andere 
GPIO-Pins und Ports initialisiert funktioniert alles wunderbar. Warum 
auch immer.

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