Skip to main content
JLask.1
Associate
April 3, 2023
Question

Problem with UART and STM32F413ZH

  • April 3, 2023
  • 8 replies
  • 2058 views

Hello,

i have a problem and hope that someone can help me. I've been trying to find a solution for days now and I'm just not able to get any further.

I would like to set up a UART interface using register. Unfortunately nothing gets to the PC.

What I have tried so far:

UART2 Tx via PA2 and PD5 . Both unsuccessful.

Additionally I tried it over a FTDI USB. This also does not work

The registers look good, as far as I can see

I tried several terminals but no success

Here is my code:

#include "stdint.h"
#include "uart.h"
#include "stm32f413xx.h"
 
#define GPIOAEN				(1U<<0)
#define UART2EN				(1U<<17)
 
#define DBG_UART_BAUDRATE	9600
#define SYS_FREQ			16000000
#define APB1_CLK			SYS_FREQ
#define CR1_TE				(1U<<3)
#define CR1_UE				(1U<<13)
#define SR_TXE				(1U<<7)
 
static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate);
static void uart_write(int ch);
 
int __io_putchar(int ch) {
	uart_write(ch);
	return ch;
}
 
void debug_uart_init(void){
 
	/* Enable clock acces to GPIOA */
	RCC->AHB1ENR |= GPIOAEN;
 
	/* Set the mode of PA2 to alternate function mode */
	GPIOA->MODER &= ~(1U << 4);
	GPIOA->MODER |= (1U << 5);
 
	/* Set alternate function type to AF7 (UART2_TX) */
	GPIOA->AFR[0] |= (1U << 8);
	GPIOA->AFR[0] |= (1U << 9);
	GPIOA->AFR[0] |= (1U << 10);
	GPIOA->AFR[0] &= ~(1U << 11);
 
	/* Enable clock access to UART2 */
	RCC->APB1ENR |= UART2EN;
 
	/* Configure UART baudrate */
	uart_set_baudrate(APB1_CLK, DBG_UART_BAUDRATE);
 
	/* Configure transfer direction */
	USART2->CR1 = CR1_TE;
 
	/* Enable UART Module */
	USART2->CR1 = CR1_UE;
}
 
static void uart_write(int ch){
 
	/* Make sure transmit data register is empty */
	while(!(USART2->SR & SR_TXE)){}
 
	/* Write to transmit data register */
	USART2->DR = (ch & 0xFF);
}
 
 
static uint16_t compute_uart_bd(uint32_t periph_clk, uint32_t baudrate){
	return ((periph_clk + (baudrate / 2U)) / baudrate);
}
 
static void uart_set_baudrate(uint32_t periph_clk, uint32_t baudrate){
	USART2->BRR = compute_uart_bd(periph_clk, baudrate);
}

The main.c has the following code

#include "stdio.h"
#include "stm32f413xx.h"
#include "fpu.h"
#include "uart.h"
  
int main()
{
 
	/* Enable FPU */
	fpu_enable();
 
	/* Initialize debug UART */
	debug_uart_init();
 
	while(1)
	{
		printf("Hello");
		for (int i = 0; i < 9000; ++i){}
	}
}

I would be really grateful if someone could help me find the problem

This topic has been closed for replies.

8 replies

Tesla DeLorean
Guru
April 3, 2023

Isn't HSI 16 MHz ??

Perhaps get a scope look at signals on pins.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
JLask.1
JLask.1Author
Associate
April 3, 2023

Yes you are right HSI is 16MHz. i had also tried 16MHz and also just tried again now. unfortunately the same problem. I have also tried several terminals. MobaXterm, CoolTerm, RealTerm and Putty. 

Tesla DeLorean
Guru
April 4, 2023

Probably not an issue with the terminal applications, look at the signal itself, with a scope, perhaps output a continuous 'U' 0x55 pattern?

Review the register settings, per manual.

Try with a HAL example to sanity check the hardware is working as expected.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Chris21
Associate II
April 4, 2023

It's odd that you have RCC->APB1ENR |= UART2EN; should be USART2EN.

USART2->CR1 = CR1_TE; // enable transmitter

/* Enable UART Module */

USART2->CR1 = CR1_UE; // disables transmitter

Probably want to be using |= ...

.
Piranha
Principal III
April 4, 2023
#include "stm32f413xx.h"
 
#define GPIOAEN				(1U<<0)
#define UART2EN				(1U<<17)
 
#define CR1_TE				(1U<<3)
#define CR1_UE				(1U<<13)
#define SR_TXE				(1U<<7)

32-bit platform needs an "ul/UL" suffix. But why are you redefining bit field definitions instead of using ST defined ones?

Tesla DeLorean
Guru
April 4, 2023

Because it's more efficient, and less error prone, like repeatedly accessing the same register..

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
April 5, 2023

As long as short defined names aren't unfortunately reused by other peripherals using the same implementation... or these defines are "local" to a C source file....

Tesla DeLorean
Guru
April 4, 2023

One of the tricks with register level code is to let the COMPILER do a lot of heavy lifting ONCE at compile time, on a machine running at 3 GHz.

The compiler can fold up the math, it can't fold RMW action on VOLATILE memory, where it instead has to assure in-order-execution.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..