cancel
Showing results for 
Search instead for 
Did you mean: 

Bare metal USART2 clock speed question

STMnoob
Associate II

Hello,

I am learning bare metal programming for STM32F446RE and am trying to write a simple transmit driver for USART2. I managed to do it but my only problem is when I use HSI 16Mhz clock speed (or anything lower) I get a weird first character. When I use a higher clock speed it works fine (using another clock source). 

Does anyone know the reason for that?

Thank you

 

void USART_init(){
	RCC->APB1ENR|=(1<<17);

	USART2->CR1&=~(1<<12);
	USART2->CR1&=~(1<<10);
	USART2->CR1&=~(1<<15);

	USART2->CR1|=(1<<13);

	// Baud Rate of 115200 and Clock of 16Mhz
	USART2->BRR=(8<<4 | 11);

	USART2->CR1|=(1<<3);
	USART2->CR1|=(1<<2);

	char g[15];
	sprintf(g,"Hello\r\n");

	for(int i=0;i<strlen(g);i++){
		while(!(USART2->SR & (1<<7)));
		USART2->DR=g[i];
	}

	while(!(USART2->SR & (1<<6)));

STMnoob_0-1758935979151.png

 

3 REPLIES 3
Danish1
Lead III

One possible explanation is that the state of the TXD pin is wrong during your code that sets up the UART and directs output to TXD.  You only notice this when running at 16 MHz or slower because then the processor takes sufficient time for this wrong state to be received as a weird character.

A way to avoid this is to initially have the TXD pin as GPIO output in the UART line-idle state, then set up the UART, and only then tell the pin to use the alternate function of UART.

As a point of coding style, I imagine you #include the ST header for your processor to get things like RCC->APB1ENR defined. That also has all the bits defined; your code would be more readable and less error-prone if you were to use the bit definitions. For example the line that enables the clock would become:

RCC->APB1ENR|=RCC_APB1ENR_USART2;

 Similarly for the USART e.g. USART_CR1_TXE

gbm
Principal

I suspect a little problem with the setup code. Setup the UART first, then set the GPIO->AFR and GPIO->MODER registers for UART pins. For UART, write the BRR first, then set CR1 with a single asignment. Your BRR setting is funny and not exactly correct. It should simply be:

USART2->BRR = (UART_CLK_FREQ + BAUD_RATE / 2) / BAUD_RATE;
USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Thank you for your answers.

Sorry for the late reply.