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.
Best Answer
It turns out that the code was fine, and it was all hardware issues. Firstly, the USART2 TX/RX pins on that board's connector are by design not connected to anything. The MCU pins are only connected to the ST-Link. (There are solder bridges to change this configuration.) So that's why I didn't get anything on the scope.
As for why I didn't get any data on the USB port, I think the ST-Link was not compatible with USB 3.0. When I upgraded its firmware, suddenly I saw my data.