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?

20 REPLIES 20


Shouldn't it be waiting for the empty flag to set ?



Yes, quite right, I got muddled writing the post, that what this line does right?
 
while(!(USART2->SR & SR_TXE)){}
 
I've  stripped everything down to just using the USART but still it just hangs waiting on the SR_TXE flag to set, which never happens. 
gbm
Principal

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)

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

That throws an "undeclared identifier" error for RCC_APBENR1_USART2EN

You're right, there was a typo - corrected.

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

Still nothing coming through the serial, still hanging waiting for SR_TXE to set.

As well as enabling the UART peripheral, have you also enabled the transmitter:

AndrewNeil_0-1759324364128.png

AndrewNeil_1-1759324518117.png

 

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,

#define CR1_TE   (1U<<3)

....

USART2->CR1 = CR1_TE;

 

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;
}

 

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.

Hasn't made any difference, still waiting on SR_TXE to set

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.

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