I'm trying to manually* configure a USART on a Nucleo F401RE to transmit over the USB virtual COM port, which means using USART2 on PA2 (TX) and PA3 (RX). Not only am I not receiving any characters, but the TX pin is never high, which I believe it should be when idle.
Here's what I've done:
PLL is running at 84MHz (confirmed using MCO), and the APB1 prescaler is set to /2:
RCC_CFGR =
(2 << RCC_CFGR_SW_BIT) // Use PLL as clock source
| (0b100 << RCC_CFGR_PPRE1_BIT) // Prescale APB1 clock /2
;
GPIOA peripheral clock is enabled:
// Enable GPIOA peripheral clock
RCC_AHB1ENR = RCC_AHB1ENR_GPIOAEN;
Then the USART configuration:
GPIOA_MODER |= 0b1010 << 4; // PA2, PA3 to AF
GPIOA_OSPEEDR |= 0b1111 << 4; // PA2, PA3 to high speed
GPIOA_AFRL |= (7 << 8) | (7 << 12); // Set PA2, PA3 to AF7 (USART2)
RCC_APB1ENR |= RCC_APB1ENR_USART2EN; // Enable peripheral clock for USART2
// Baud rate 115k2 with SYSCLK 84MHz (BRR = 45.5625)
USART2_BRR = (45 << 4) | 9;
USART2_CR1 = USART_CR1_UE | USART_CR1_TE;
I believe at this point, TX should be high, but it isn't. I send with:
while ((USART2_SR & USART_SR_TXE) == 0);
USART2_DR = c;
Turning on the LED within the while
shows that the transmit buffer is initially filled. Turning it on after the while
shows that it successfully empties. Using TC
instead of TXE
shows it is considered successfully transmitted.
What have I missed?
All the code is here: https://github.com/danellis/zeptos/tree/usart-fail
* Please don't try to persuade me to use CMSIS or mbed; it's a learning exercise.