Forum: Mikrocontroller und Digitale Elektronik STM32F4 - RCC Register Problem


von SUNP (Gast)


Lesenswert?

Guten Morgen,

auf einem STM32F439 möchte ich gerne den USART1 verwenden.
Mein bisheriger Code funktioniert auch und tut das, was er soll aber 
leider nur im Debugger bzw. wenn ich einen Breakpoint ab einer 
bestimmten Stelle ich Code habe. Ohne Debugger bzw. Breakpoint habe ich 
ein für mich unerklärliches Verhalten.
1
RCC->APB2ENR |= ((uint32_t)1) << 4;
2
3
// Port PA9  -> Transmitter Out
4
GPIOA->MODER |= ((uint32_t)1) << 19; // Alternate Function UART-TX
5
GPIOA->OSPEEDR |= ((uint32_t)1) << 18; // Output Speed -> Medium
6
GPIOA->PUPDR |= ((uint32_t)1) << 18;   // Pull-Up Enable
7
GPIOA->AFR[1] |= ((uint32_t)7) << 4;   // Alternate Funktion 8 UART-TX 
8
   
9
// Port PA10 -> Receiver In
10
GPIOA->MODER |= ((uint32_t)1) << 21; // Alternate Function UART-RX     
11
GPIOA->PUPDR |= ((uint32_t)1) << 20;   // Pull-Up Enable
12
GPIOA->AFR[1] |= ((uint32_t)7) << 8;   // Alternate Funktion 8 UART-RX
13
   
14
// Port PC9 -> RS485 Treiber Enable
15
GPIOC->MODER |= ((uint32_t)1) << 18;   // Output
16
GPIOC->OSPEEDR |= ((uint32_t)1) << 18; // Output Speed -> Medium
17
GPIOC->PUPDR |= ((uint32_t)1) << 18;   // Pull-Up Enable
18
   
19
// Allgemeine USART-1-Tx-Rx Einstellungen
20
USART1->CR1 = 0x3800; // 9 Datenbits, UART Peripherie enable 
21
                      // aber Transmitter und Receiver disable, keine 
22
                      // Parity Control. Oversampling by 16.
23
USART1->CR2 = 0x00;   // 1 Stop Bit
24
USART1->CR3 = 0x808;  // CTS/RTS abgestellt, Half-Duplex Mode
25
26
// Baudrate einstellen
27
USART1->BRR = 0x0000222E; // 9600 Baud. Bei einem 84 MHz USART1
28
29
// Außgänge richtig setzen.
30
GPIOA->ODR |= ((uint32_t)1)<<9; // Transmitter und Receiver abgeschaltet. 
31
                                // Tx bin wird auf High gestellt.
32
  
33
GPIOC->ODR &= ~(((uint32_t)1)<<9); // RS485 Treiber Disable

Das war die Initialisierung vom USART 1.
Im zweiten Teil mache ich ein paar Einstellungen, damit der USART so 
funktioniert, wie ich es gerne hätte.
1
//UART ist eine von mir angelegte Struktur
2
// Alle USART1 Interupts werden zur Sicherheit abgeschaltet
3
USART1->CR1 &= ~(0x000001F0);
4
UART.TxData = stdata;
5
UART.TxLength = -1; // wegen den Dummy Daten
6
// Tx PortPin auf GPIO setzen, damit die Dummydaten nicht 
7
// an den Treiber übertragen werden.
8
// Port PA9  -> Transmitter Out
9
GPIOA->MODER &= ~(((uint32_t)1) << 19); // Alternate Function ausgestellt
10
GPIOA->MODER |= ((uint32_t)1) << 18;   // GPIO Mode für UART-TX PinA9
11
12
  
13
GPIOC->ODR |= ((uint32_t)1)<<9; // RS485 Treiber Enable
14
USART1->DR = 0x111;   // Nur ein Dummybyte
15
USART1->CR1 |= 0x00000088;   // TXE und TXE Interupt enable


Setze ich an einer beliebigen Stelle ! nach ! der Befehlszeile
RCC->APB2ENR |= ((uint32_t)1) << 4;
einen Breakpoint, dann funktioniert mein Code wie gewünscht. Habe ich am 
Oszi nachgemessen. Fehlt dieser Breakpoint kommt es zu einem 
Vehlverhalten.
Folgende IF-Bedinung wird in der USART1 Interuptroutine nur erfüllt, 
wenn irgendwo zuvor kurz an einem Breakpoint angehalten wurde.
1
volatile uint32_t ulInterrupt = USART1->SR;
2
if((ulInterrupt &  UART_TXE_FLAG) && !(ulInterrupt & UART_TC_FLAG))

Im Errata Sheet habe ich folgendes gelesen:

A delay between an RCC peripheral clock enabling and the effective 
peripheral enabling should be taken into account in order to manage the 
peripheral read/write to registers.

Setze ich ein __asm("DSB");  oder zwei __NOP(); hinter RCC->APB2ENR |= 
((uint32_t)1) << 4;  bringt das auch nicht das gewünschte Ergebniss.

Könnt ihr mir vielleicht weiterhelfen ?

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


Lesenswert?

Wie soll man - wir als Erstseher des Codes sowieso - diesen Code denn 
verstehen? Mit direkten Bits blickst du selber nach 1 Monat nicht mehr 
durch und der Code ist auch kein bisschen portierbar.

Ich bin ja oft selber kein Freund von vorgekautem Kram, aber bei den 
STM32 ist zumindest CMSIS problemlos, schnell und funktioniert - es muss 
ja nicht gleich Cube sein.
Schreib wenigstens statt
1
GPIOA->MODER |= ((uint32_t)1) << 19; // Alternate Function UART-TX
sowas wie
1
GPIOA->MODER |= (GPIO_MODE_AF << (GPIO_PinSource9 * 2); // Alternate Function UART-TX
Ist zwar immer noch nicht schön, aber wenigstens ein bisschen lesbar.
Die Initialisierung der UARTs mit CMSIS ist jedenfalls ein Spaziergang:
1
void USARTInit(uint32_t baudrate) {
2
GPIO_InitTypeDef GPIO_InitStructure;
3
USART_InitTypeDef USART_InitStructure;
4
// Clock Enable of usart pins
5
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
6
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
7
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, ENABLE);
8
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, DISABLE);
9
GPIO_PinAFConfig(USART_PORT, USART_RX_SOURCE, GPIO_AF_USART2);
10
GPIO_PinAFConfig(USART_PORT, USART_TX_SOURCE, GPIO_AF_USART2);
11
// the USART Pin config
12
GPIO_InitStructure.GPIO_Pin = USART_TX_PIN;
13
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
14
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
15
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
16
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
17
GPIO_Init(GPIOA, &GPIO_InitStructure);
18
GPIO_InitStructure.GPIO_Pin =  USART_RX_PIN;
19
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
20
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
21
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
22
GPIO_Init(GPIOA, &GPIO_InitStructure);
23
/* Configure USART
24
 *
25
 */
26
USART_DeInit(USART);
27
USART_StructInit(&USART_InitStructure);
28
USART_InitStructure.USART_BaudRate = baudrate;
29
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
30
USART_InitStructure.USART_StopBits = USART_StopBits_1;
31
USART_InitStructure.USART_Parity = USART_Parity_No;
32
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
33
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
34
USART_Init(USART,&USART_InitStructure);
35
/* Enable USART */
36
USART_Cmd(USART, ENABLE);
37
}

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.