2025-05-17 6:46 AM
Hi All,
I have written a baremetal code to initialize the USART2 of STM32F401RE and print HELLO WORLD. The code does not use HAL and rather accesses and writes to USART2 peripheral registers using the C pointers. I have cross verified the code multiple times and have tried multiple methods to get the print, but I am not seeing any output on the teraterm/puTTY.
I even used USB-TTL cable for this purpose by connecting the PA2 and PA3 (on the ST-Morpho connector) to TTL's cable Rx and Tx pin respectively. But there is no output. What can be the reason? Below is my code:
#include "stdint.h"
#include "stm32f4xx.h"
#include "string.h"
typedef struct{
volatile uint32_t REG_MODER;
volatile uint32_t REG_OTYPER;
volatile uint32_t REG_PUPDR;
volatile uint32_t REG_IDR;
volatile uint32_t REG_ODR;
volatile uint32_t REG_AFR[2];
}GPIO_REG_DEF;
typedef struct{
volatile uint32_t REG_SR;
volatile uint32_t REG_DR;
volatile uint32_t REG_BRR;
volatile uint32_t REG_CR1;
volatile uint32_t REG_CR2;
volatile uint32_t REG_CR3;
}USART_REG_DEF;
/*Create a pointer of type GPIO_REG_DEF pointing to base address of GPIOA*/
#define GPIO_BASE_ADDR 0x40020000
#define GPIO_A ((GPIO_REG_DEF *)GPIO_BASE_ADDR)
/*Create pointers of type volatile uint32_t to point to respective registers in the RCC*/
#define AHB1_ADDR (*(volatile uint32_t *)(0x40023800+0x30))
#define APB1_ADDR (*(volatile uint32_t *)(0x40023800+0x40))
/*Create pointers of type USART_REG_DEF pointing to base address of USART2*/
#define USART_BASE_ADDR 0x40004400
#define USART_2 ((USART_REG_DEF *)USART_BASE_ADDR)
/*Create an alias for USART pins*/
#define USART_TX_PIN 2
#define USART_RX_PIN 3
/*Create an alias for USART registers' bits*/
#define USART_EN (1<<13)
#define USART_OVER8 (1<<15)
#define USART_STOP_BITS (0x3<<12)
#define USART_WORD_LEN (1<<12)
#define USART_PARITY_CTRL (1<<10)
#define USART_PARITY_TYPE (1<<9)
#define USART_TX_EN (1<<3)
#define USART_RX_EN (1<<2)
#define USART_BR ((0x16<<4) | (0xD & 0xFF))
#define TXE (1<<7)
#define TC (1<<6)
#define RXNE (1<<5)
#define SEND_MSG "HELLO WORLD"
/*Function to set up the clock for GPIOA and USART2*/
void clockSet(){
AHB1_ADDR |= 1;
APB1_ADDR |= (1<<17);
}
/*Function to initialize the UART Tx and Rx pins*/
void gpioConfig(){
/*Configure GPIOA pin2 and pin3 in alternate function mode to use it as an UART*/
GPIO_A->REG_MODER &= ~(0x3<<(2*USART_TX_PIN) | 0x3<<(2*USART_RX_PIN));
GPIO_A->REG_MODER |= (0x2<<(2*USART_TX_PIN) | 0x2<<(2*USART_RX_PIN));
GPIO_A->REG_AFR[0] |= (7<<(4*USART_TX_PIN)| 7<<(4*USART_RX_PIN));
GPIO_A->REG_OTYPER &= ~(0x1<<USART_TX_PIN | 0x1<<USART_RX_PIN);
GPIO_A->REG_PUPDR &= ~(0x3<<(2*USART_TX_PIN) | 0x3<<(2*USART_RX_PIN));
}
/*Function to initialize the USART*/
void usart_init(){
USART_2->REG_CR1 &= ~USART_EN;
USART_2->REG_CR1 &= ~USART_OVER8; //RESET the OVER8 bit in CR1 for oversampling=16
USART_2->REG_CR2 &= ~USART_STOP_BITS; //Configure number of stop bits=1
USART_2->REG_CR1 &= ~USART_WORD_LEN; //Configure the word length (1 start bit+8 data bits+1 stop bits)
USART_2->REG_CR1 &= ~USART_PARITY_CTRL; //Disable parity control
USART_2->REG_CR1 |= USART_TX_EN; //enable the transmit driver path
USART_2->REG_CR1 |= USART_RX_EN; //ENABLE the receive driver path
USART_2->REG_BRR = USART_BR; //SET the baud rate to 115200
USART_2->REG_CR1 |= USART_EN; //Enable the USART2
}
void send_data(){
unsigned char ch;
int i=0;
while(i != strlen(SEND_MSG)){
ch = SEND_MSG[i];
while(!(USART_2->REG_SR & TXE));
USART_2->REG_DR = ch;
i++;
}
while(!(USART_2->REG_SR & TC));
}
int main(){
clockSet();
gpioConfig();
usart_init();
send_data();
while(1);
}
Can anyone please help me to get this working?
Thanks,
Lalit.
2025-05-17 8:13 AM
Sanity test with HAL, even if you choose to do it this way. There's a LOT of non-optimal code in your example
Have you checked signal with scope?
Baud rate looks wrong. What was the goal?
Default HSI clock is 8 MHz for F401
#define USART_BR (8000000 / 9600)
#define USART_BR (HSI_VALUE / 9600)