cancel
Showing results for 
Search instead for 
Did you mean: 

UART driver issue NUCLEO F411RE

NicRoberts
Senior II

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?

7 REPLIES 7
Andrew Neil
Super User

@NicRoberts wrote:

If I'm right then PA2 has been set up as a UART TX


You can confirm that in the board's User Manual:

AndrewNeil_0-1754315802661.png

AndrewNeil_1-1754315825898.png

https://www.st.com/resource/en/user_manual/um1724-stm32-nucleo64-boards-mb1136-stmicroelectronics.pdf

via: https://www.st.com/en/evaluation-tools/nucleo-f411re.html#documentation

You could also check the schematics:

AndrewNeil_2-1754315934411.png

via https://www.st.com/en/evaluation-tools/nucleo-f411re.html#cad-resources

 


@NicRoberts wrote:

with a Baud rate of 115200 


The baud rate can be whatever you like - it just has to match what you terminal is set to.

 


@NicRoberts wrote:

But when I open a TeraTerm window & connect to the board I get nothing 


Are you sure you're connecting to the correct COM port?

Do you have an Arduino shield (or any other hardware) connected which could interfere?

The manual describes various configuration options - has your board been modified?

Before adding the complications of printf, get it working with just direct UART output.

Have you tried one of the ready-made examples?

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

OK so the board is set up correctly for use of USART2 over the ST-Link/USB connection, I have used this before with no issue with the board but just double checked & it all looks good.

No other hardware connected.

Baud rate on the board & the terminal match (115200),

COM5: STMicroelectronics STLink Virtual COM Port selected from Tera Term pull down

 

.....and nothing.....

Flow control set to 'None' ?

 

Have you tried one of the ready-made examples?

Do you have a scope to see if anything is actually coming out of the TX pin?

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

Yes, flow control set to 'None'

Settings,

Baud : 115200

Data: 8 bit

Parity: none

Stop bits: 1

Flow control: none

Same config on TeraTerm

 

I'm trying to run some of the examples but the example selector keeps crashing CubeIDE

Got a simple HAL_UART_Transmit() code to work using printf() though, so I know the board is working now.

Still cant figure out why my bare metal implementation isn't working though.


@NicRoberts wrote:

Still cant figure out why my bare metal implementation isn't working though.


Step through the two examples; compare & contrast ...

 

Alternatively, start with the working HAL code, and pare that back to the minimum register operations ...

 

PS:

Or, of course, just use the HAL version as-is...

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

Are we sure APB1 is DIV2 and not DIV1 ?

Perhaps send 'U' patterns and scope the PA2 pin to confirm activity and bit-timing

If you're using bare-metal registers for efficiency, this is NOT efficient, and the compiler can't optimize / fold this because the registers are deemed volatile. So 4x load-store operations, when one load and one store would be the goal.

GPIOA->AFR[0] |= (1U<<8);
GPIOA->AFR[0] |= (1U<<9);
GPIOA->AFR[0] |= (1U<<10);
GPIOA->AFR[0] &=~ (1U<<11);

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

Hi, 

I'm relatively new to STM32 so I'm doing everything long hand to get a better understanding but I get the sense in what you're are saying.

As for APB1, when I check against the auto-generated code the RCC initialiser uses DIV1. I thought I'd configured for DIV1?