2025-08-04 6:30 AM - edited 2025-08-04 6:51 AM
I'm trying to set up a simple UART debug just for transmission from the the NUCLEO board.
uart.c
#include "uart.h"
#define GPIOAEN (1U<<0)
#define UART2EN (1U<<17)
#define CR1_TE (1U<<3)
#define CR1_UE (1U<<13)
#define SR_TXE (1U<<7)
#define SYS_FREQ 16000000
#define APB1_CLK SYS_FREQ
#define UART_BAUDRATE 115200
static void uart2_set_baudrate(uint32_t periph_clk, uint32_t baudrate);
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate);
static void uart2_write(int ch);
int __io_putchar(int ch)
{
uart2_write(ch);
return ch;
}
void uart2_tx_init(void)
{
/*** Configure UART GPIO pin ***/
/* Enable clock access to GPIOA */
RCC->AHB1ENR |= GPIOAEN;
/* Set PA2 mode to alternate function mode */
GPIOA->MODER &=~ (1U<<4);
GPIOA->MODER |= (1U<<5);
/* Set PA2 alt function to UART tx (AF07) */
GPIOA->AFR[0] |= (1U<<8);
GPIOA->AFR[0] |= (1U<<9);
GPIOA->AFR[0] |= (1U<<10);
GPIOA->AFR[0] &=~ (1U<<11);
/*** Configure the UART ***/
/* Enable clock access to UART2 */
RCC->AHB1ENR |= UART2EN;
/* Configure baudrate */
uart2_set_baudrate(APB1_CLK, UART_BAUDRATE);
/* Configure transfer direction */
USART2->CR1 = CR1_TE;
/* Enable UART module */
USART2->CR1 |= CR1_UE;
}
static void uart2_write(int ch)
{
/* Ensure transmit data register empty */
while(!(USART2->SR & SR_TXE)){}
/* Write to the transmit data register */
USART2->DR = (ch & 0xFF);
}
static void uart2_set_baudrate(uint32_t periph_clk, uint32_t baudrate)
{
USART2->BRR = compute_uart_bd(periph_clk, baudrate);
}
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate)
{
return ((periph_clk + (baudrate / 2U)) / baudrate);
}
uart.h
#ifndef __UART_H__
#define __UART_H__
#include "stm32f4xx.h"
#include <stdint.h>
void uart2_tx_init(void);
#endif
main.c
#include "stm32f4xx.h"
#include <stdio.h>
#include "uart.h"
static void psuedo_delay(int dly);
int main(void)
{
/* Initialize UART2 */
uart2_tx_init();
while(1)
{
printf("hi there!\n\r");
psuedo_delay(9000);
}
}
static void psuedo_delay(int dly)
{
for(int i = 0; i < dly; i++)
{
// DO NOTHING
}
}
If I'm right then PA2 has been set up as a UART TX with a Baud rate of 115200 & this is connected to the USB on the board.
But when I open a TeraTerm window & connect to the board I get nothing just a blank terminal window. What am I missing here?
Solved! Go to Solution.
2025-10-01 3:02 AM
Shouldn't it be waiting for the empty flag to set ?
while(!(USART2->SR & SR_TXE)){}
2025-10-01 5:47 AM - edited 2025-10-01 5:59 AM
The problem you experience is a direct result of not using the register bit constants defined in ST-supplied headers.
Once you replace the constants defined by you with the standard ones, you will easily notice your mistake.
The correct way to enable USART2 is:
RCC->APB1ENR = RCC_APB1ENR_USART2EN;
(typo corrected in response to the post below)
2025-10-01 5:52 AM
That throws an "undeclared identifier" error for RCC_APBENR1_USART2EN
2025-10-01 5:59 AM
You're right, there was a typo - corrected.
2025-10-01 6:07 AM
Still nothing coming through the serial, still hanging waiting for SR_TXE to set.
2025-10-01 6:15 AM
As well as enabling the UART peripheral, have you also enabled the transmitter:
2025-10-01 6:20 AM
Yes,
#define CR1_TE (1U<<3)
....
USART2->CR1 = CR1_TE;
2025-10-01 6:36 AM - edited 2025-10-01 6:36 AM
The procedure in the Reference Manual (above) says to enable the UART first, then the transmitter.
You do that "backwards":
/* Configure baudrate */
uart2_set_baudrate(APB1_CLK, UART_BAUDRATE);
/* Configure transfer direction */
USART2->CR1 = CR1_TE;
/* Enable UART module */
USART2->CR1 |= CR1_UE;
}
2025-10-01 6:40 AM
Hasn't made any difference, still waiting on SR_TXE to set
2025-10-01 1:46 PM
And still not using official, proven and correct bit masks.
Get rid of your custom constants, rewrite the code using standard stuff and show it.
You only need two assignments to initialize the USART after it is enabled: write to BRR, then set CR1 with a single assignment.