Forum: Mikrocontroller und Digitale Elektronik Mehrere UARTs mit Interrupts


von Tom P. (tom_p89)


Lesenswert?

Hallo,
ich möchte auf meinem STM32f401C-Discovery zwei UARTs mit Interrupts 
betreiben. Konkret USART1 und USART6. Einzeln funktionieren sie beide 
aber zusammen nicht. Der Coocox Debugger kann mir bei dem Problem auch 
nicht weiter helfen. Ich bin gerade dabei eine Funktion zu schreiben, 
die mir beide USARTs konfiguriert.
Die GPIO Konfigurationen stammen aus dem Datenblatt und funktionieren 
einzeln auch. Vermutlich steckt irgendwo ein ganz trivialer Fehler im 
Code. Ich bin relativ neu im C programmieren.

Vielen Dank für eure Hilfe!

Tom

Hier ist der Code:
1
void USART_SETUP(void){
2
3
  GPIO_InitTypeDef GPIO_InitStruct; // this is for the GPIO pins used as TX and RX
4
  USART_InitTypeDef USART_InitStruct; // this is for the USART1 initilization
5
  NVIC_InitTypeDef NVIC_InitStructure1; // this is used to configure the NVIC (nested vector interrupt controller)
6
  NVIC_InitTypeDef NVIC_InitStructure6; // this is used to configure the NVIC (nested vector interrupt controller)
7
8
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_USART6, ENABLE);
9
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
10
11
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;     // the pins are configured as alternate function so the USART peripheral has access to them
12
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    // this defines the IO speed and has nothing to do with the baudrate!
13
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;    // this defines the output type as push pull mode (as opposed to open drain)
14
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;    // this activates the pullup resistors on the IO pins
15
16
  //------------USART1 PIN SETTINGS----------------------------------
17
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;   // Pins 6 (TX) and 7 (RX) are used
18
  GPIO_Init(GPIOB, &GPIO_InitStruct);      // now all the values are passed to the GPIO_Init() function which sets the GPIO registers
19
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
20
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
21
22
  //------------USART6 PIN SETTINGS----------------------------------
23
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;   // Pins 6 (TX) and 7 (RX) are used
24
  GPIO_Init(GPIOC, &GPIO_InitStruct);      // now all the values are passed to the GPIO_Init() function which sets the GPIO registers
25
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
26
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);
27
28
29
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;      // we want the data frame size to be 8 bits (standard)
30
  USART_InitStruct.USART_StopBits = USART_StopBits_1;        // we want 1 stop bit (standard)
31
  USART_InitStruct.USART_Parity = USART_Parity_No;        // we don't want a parity bit (standard)
32
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   // we don't want flow control (standard)
33
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;       // we want to enable the transmitter and the receiver
34
35
  //----------------USART1 aktivieren-----------------------------
36
  USART_InitStruct.USART_BaudRate = 115200;          // the baudrate is set to the value we passed into this init function
37
38
    //----Interrupt USART1---
39
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // enable the USART1 receive interrupt
40
41
    NVIC_InitStructure1.NVIC_IRQChannel = USART1_IRQn;     // we want to configure the USART1 interrupts
42
    NVIC_InitStructure1.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts
43
    NVIC_InitStructure1.NVIC_IRQChannelSubPriority = 0;     // this sets the subpriority inside the group
44
    NVIC_InitStructure1.NVIC_IRQChannelCmd = ENABLE;       // the USART1 interrupts are globally enabled
45
    NVIC_Init(&NVIC_InitStructure1);          // the properties are passed to the NVIC_Init function which takes care of the low level stuff
46
47
    USART_Init(USART1, &USART_InitStruct);            // again all the properties are passed to the USART_Init function which takes care of all the bit setting
48
    USART_Cmd(USART1, ENABLE);
49
50
51
  //----------------USART6 aktivieren-----------------------------
52
  USART_InitStruct.USART_BaudRate = 38400;          // the baudrate is set to the value we passed into this init function
53
54
    //----Interrupt USART1---
55
    USART_ITConfig(USART6, USART_IT_RXNE, ENABLE); // enable the USART1 receive interrupt
56
57
    NVIC_InitStructure6.NVIC_IRQChannel = USART6_IRQn;     // we want to configure the USART1 interrupts
58
    NVIC_InitStructure6.NVIC_IRQChannelPreemptionPriority = 1;// this sets the priority group of the USART1 interrupts
59
    NVIC_InitStructure6.NVIC_IRQChannelSubPriority = 0;     // this sets the subpriority inside the group
60
    NVIC_InitStructure6.NVIC_IRQChannelCmd = ENABLE;       // the USART6 interrupts are globally enabled
61
    NVIC_Init(&NVIC_InitStructure6);          // the properties are passed to the NVIC_Init function which takes care of the low level stuff
62
63
  USART_Init(USART6, &USART_InitStruct);
64
  USART_Cmd(USART6, ENABLE);
65
66
}

von Топ торкнилх (Gast)


Lesenswert?

Mit einem Oszilloskop einen Debugpin ueberwachen ?

von Tom P. (tom_p89)


Lesenswert?

Damit habe ich noch nie gearbeitet und auch erst Mitte nächster Woche 
wieder ein Oszilloskop zur Verfügung. Ich bin mir eigentlich ziemlich 
sicher, dass mir in der Funktion ein Fehler unterlaufen sein muss.

von Carl D. (jcw2)


Lesenswert?

Chinesischer 8€ LA + sigrok, damit kann man via "Wackel-Pins" den Ablauf 
der ISR's verfolgen. Auch 20m neben den Oszi-Schirm ;-)

von Tom P. (tom_p89)


Angehängte Dateien:

Lesenswert?

Hier ist auf jeden Fall schon mal die Fehlermeldung vom Debugger. 
Vielleicht kann jemand etwas damit anfangen.

von Bernd K. (prof7bit)


Lesenswert?

Tom P. schrieb:
> GPIO_InitStruct

Mal so am Rande: Ist das automatisch generierter Code oder warum um 
alles in der Welt gibst Du dieser lokalen Variablen so einen langen 
Namen, warum nennst Du sie nicht gis, uis, nis oder dergleichen?

--
Und an ST-Microsystems gerichtet hab ich auch noch zwei, drei brennende 
Fragen: warum haben die Members eurer Structs alle noch mal diesen 
bescheuerten redundanten Prefix, also zum Beispiel warum fangen alle 
Members des GPIO_InitTypeDef mit GPIO_ an? Warum heißt der überhaupt 
GPIO_InitTypeDef, warum nicht GPIO_init_t oder noch besser struct 
GPIO_init, was soll das dümmliche TypeDef überall in den Namen? Seid Ihr 
Masochisten oder einfach nur bösartig und wollt daß der Code dann 
maximal Scheiße und unübersichtlich aussieht? Werden die Entwicker bei 
ST nach kilobyte bezahlt? Das wollt ich schon immer mal wissen.

von Sascha W. (sascha-w)


Lesenswert?

@Tom,

kann es vielleicht sein das USART_InitStruct nicht für beide UARTs 
zugleich verwendet werden kann? Evl. musst du für jeden UART eine eigene 
Struct definieren.

Sascha

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Sascha W. schrieb:
> @Tom,
>
> kann es vielleicht sein das USART_InitStruct nicht für beide UARTs
> zugleich verwendet werden kann? Evl. musst du für jeden UART eine eigene
> Struct definieren.
>
> Sascha

Nein, der Code ist soweit ok.

Was fehlt ist der ISR Code, mglw. werden je nach Codierung anstehende 
Interrupts nicht richtig gelöscht.

@TE: Du versuchst nicht so Dinge zu tun wie aus einem Rx ISR einen 
output auf den Anderen UART zu machen? Das mag der ST nicht & kommt 
damit durcheinander.

von Softbreak (Gast)


Lesenswert?

Tom P. schrieb:
> STM32f401C-Disco

Du hast zuviele Brakepoints gesetzt. Lösche alle und breake erst nur an 
einer Stelle oder führe den Code aus dem RAM aus.

von Softbreak (Gast)


Lesenswert?

Ruediger A. schrieb:
> Das mag der ST nicht & kommt
> damit durcheinander.

Na, oder sich einmal mit der Prioritäten und Subprioritäten 
beschäftigen. ;-)

von W.S. (Gast)


Lesenswert?

Bernd K. schrieb:
> was soll das dümmliche TypeDef überall in den Namen?

Es ist eine Hommage an die Benutzer. Sieh's positiv!

W.S.

von Tom P. (tom_p89)


Lesenswert?

Ich habe den Fehler jetzt gefunden. In dem Projekt in dem ich USART1 und 
USART6 zusammengeführt habe wurde ein Pin von USART6 für eine andere 
Aufgabe verwendet.
Für USART6 kommen nur zwei mögliche Konfigurationen in Frage. Eine ist 
auf dem STM Board nicht durchkontaktiert und die andere wird von einem 
Peripheriemodul auf dem STM Board benutzt. Insofern fällt der USART6 
erst einmal aus.
Als Alternative bleibt der USART2 übrig. Den bekomme ich jedoch auch 
nicht zum laufen. Auch nicht in einem einzelnen Projekt ohne weiteren 
USART oder andere Konfliktmöglichkeiten. Der RX Pin ist auch noch nicht 
belegt. Ich möchte lediglich ein Testsignal ausgeben.

Mit USART1 und USART6 funktioniert das auch einzeln.

Hier der Code:
1
void init_USART2(uint32_t baudrate){
2
3
  /* This is a concept that has to do with the libraries provided by ST
4
   * to make development easier the have made up something similar to
5
   * classes, called TypeDefs, which actually just define the common
6
   * parameters that every peripheral needs to work correctly
7
   *
8
   * They make our life easier because we don't have to mess around with
9
   * the low level stuff of setting bits in the correct registers
10
   */
11
  GPIO_InitTypeDef GPIO_InitStruct; // this is for the GPIO pins used as TX and RX
12
  USART_InitTypeDef USART_InitStruct; // this is for the USART2 initilization
13
  NVIC_InitTypeDef NVIC_InitStructure; // this is used to configure the NVIC (nested vector interrupt controller)
14
15
  /* enable APB2 peripheral clock for USART1
16
   * note that only USART1 and USART6 are connected to APB2
17
   * the other USARTs are connected to APB1
18
   */
19
  RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
20
21
  /* enable the peripheral clock for the pins used by
22
   * USART1, PB6 for TX and PB7 for RX
23
   */
24
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
25
26
  /* This sequence sets up the TX and RX pins
27
   * so they work correctly with the USART1 peripheral
28
   */
29
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6; // Pins 6 (TX) and 7 (RX) are used
30
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;       // the pins are configured as alternate function so the USART peripheral has access to them
31
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;    // this defines the IO speed and has nothing to do with the baudrate!
32
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;      // this defines the output type as push pull mode (as opposed to open drain)
33
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;      // this activates the pullup resistors on the IO pins
34
  GPIO_Init(GPIOD, &GPIO_InitStruct);          // now all the values are passed to the GPIO_Init() function which sets the GPIO registers
35
36
  /* The RX and TX pins are now connected to their AF
37
   * so that the USART2 can take over control of the
38
   * pins
39
   */
40
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2); //
41
  GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);
42
43
  /* Now the USART_InitStruct is used to define the
44
   * properties of USART2
45
   */
46
  USART_InitStruct.USART_BaudRate = baudrate;        // the baudrate is set to the value we passed into this init function
47
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;// we want the data frame size to be 8 bits (standard)
48
  USART_InitStruct.USART_StopBits = USART_StopBits_1;    // we want 1 stop bit (standard)
49
  USART_InitStruct.USART_Parity = USART_Parity_No;    // we don't want a parity bit (standard)
50
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
51
  USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // we want to enable the transmitter and the receiver
52
  USART_Init(USART2, &USART_InitStruct);          // again all the properties are passed to the USART_Init function which takes care of all the bit setting
53
54
55
  /* Here the USART1 receive interrupt is enabled
56
   * and the interrupt controller is configured
57
   * to jump to the USART1_IRQHandler() function
58
   * if the USART2 receive interrupt occurs
59
   */
60
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // enable the USART1 receive interrupt
61
62
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;     // we want to configure the USART1 interrupts
63
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART2 interrupts
64
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     // this sets the subpriority inside the group
65
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;       // the USART2 interrupts are globally enabled
66
  NVIC_Init(&NVIC_InitStructure);               // the properties are passed to the NVIC_Init function which takes care of the low level stuff
67
68
  // finally this enables the complete USART2 peripheral
69
  USART_Cmd(USART2, ENABLE);
70
}
Und hier der Code für die UART Ausgabe:
1
void USART_puts(USART_TypeDef* USARTx, volatile char *s){
2
3
  while(*s){
4
    // wait until data register is empty
5
    while( !(USARTx->SR & 0x00000040) );
6
    USART_SendData(USARTx, *s);
7
    *s++;
8
  }
9
}

Beim Debuggen landet er halt immer in der USART_puts Funktion und hat in 
SR ne 0 drin stehen. Der Aufruf sieht folgendermaßen aus:
1
USART_puts(USART2, "ABCDEFG\r\n");
Initialisiert habe ich den USART natürlich auch.

Der Unterschied zu USART1 und USART6 besteht im wesentlichen darin, dass 
USART2 an APB1 dran hängt und darin, dass der GPIO_Speed maximal 42 MHz 
betragen kann (laut Datenblatt).

: Bearbeitet durch User
von Tom P. (tom_p89)


Lesenswert?

So Problem gelöst...
Der Fehler liegt in dieser Zeile:
1
RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

Ich habe die Codestelle X mal überflogen und den Fehler nicht gesehen.
Es muss natürlich:
1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

heißen.

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.