DEV Community

vietdt89
vietdt89

Posted on • Edited on

Setup Uart with STM32F411RE

1. Open block diagram in Datasheet

Image description
We will use USART2 interface because it is connected to the same bus (APB1) with the power interface. That means we can communicate directly with the computer via USB without having a chip to convert from UART to USB.
Image description

2. Write UART send function to computer USB

Open Alternate function mapping in datasheet. We can see that creating UART TX involving PA2 and AF07 (will mention later)
Image description

  1. First we need to setup PA2 port to alternate function type as table above
  • Enable clock to GPIOA
RCC->AHB1ENR |= GPIOAEN;
Enter fullscreen mode Exit fullscreen mode
  • Set PA2 to alternate mode As the table, we need to set bit 5 and 4 of pin 2 to value 10 If we want to receive UART, as the alternate table, we need to set PA3 to alternate mode Image description
GPIOA->MODER &=~(1U<<4);
GPIOA->MODER |= (1U<<5);
Enter fullscreen mode Exit fullscreen mode
GPIOA->MODER &=~(1U<<6);
GPIOA->MODER |= (1U<<7);
Enter fullscreen mode Exit fullscreen mode
  • Set PA2 alternate type to UART_TX As mentioned above, besides PA2, we need to modify AF07. AFRL is a low register for alternate function Image description There are 2 alternate function registers, and we are dealing with PA2, so we use AFR[0] for low to locate to AFRL2, and we will modify bit 8, 9, 10, 11. To set to AF7, use value 0111
GPIOA->AFR[0] |= (1U<<8);
GPIOA->AFR[0] |= (1U<<9);
GPIOA->AFR[0] |= (1U<<10);
GPIOA->AFR[0] &= ~(1U<<11);
Enter fullscreen mode Exit fullscreen mode

Set PA3

GPIOA->AFR[0] |= (1U<<12);
GPIOA->AFR[0] |= (1U<<13);
GPIOA->AFR[0] |= (1U<<14);
GPIOA->AFR[0] &= ~(1U<<15);
Enter fullscreen mode Exit fullscreen mode
  • Set clock to USART2 port Image description
#define UART2EN (1U<<17)
RCC->APB1ENR |= UART2EN;
Enter fullscreen mode Exit fullscreen mode
  • Set direction of UART to sending We need to set TE mode Image description Image description
#define CR1_TE (1U<<3)
USART2->CR1 = CR1_TE;
Enter fullscreen mode Exit fullscreen mode

Then we need to enable USART in bit 13
Remember that we only enable after we set up all the configuration.
Image description

#define CR1_UE (1U<<13)
USART2->CR1 |= CR1_UE;
USART2->CR1 = CR1_TE | CR1_RE; //if we want to receive UART
Enter fullscreen mode Exit fullscreen mode
  • Set baudrate
    We will set frequency as 16Mhz and baudrate as 115200.
    And calculate as formula below
    Image description
    Then we need to set value to BRR register
    Image description

  • Write data to pin
    Before sending, we need to check if send status is ok or not
    Image description
    Image description

#define SR_TXE (1U<<7)
USART2->SR & SR_TXE
Enter fullscreen mode Exit fullscreen mode

And we can only write one character per write
Image description

USART2->DR = (character & 0xFF);
Enter fullscreen mode Exit fullscreen mode

Source code

#include "stm32f4xx.h"
#include <stdint.h>
#include <stdio.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 uart_set_baudrate(USART_TypeDef *USARTx, uint32_t PeriphClk, uint32_t BaudRate);
static uint16_t compute_uart_bd(uint32_t PeriphClk,uint32_t BaudRate);
void uart2_tx_init(void);
void uart2_write(int ch);

int __io_putchar(int ch){
    uart2_write(ch);
    return ch;
}
int main(void){
    uart2_tx_init();
    while(1){
        uart2_write('O');
        //printf("hello\n\r");
    }
    return 0;
}

void uart2_tx_init(void){
    //Enable GPIOA
    RCC->AHB1ENR |= GPIOAEN;

    //Set PA2 to alternate function mode
    GPIOA->MODER &=~(1U<<4);
    GPIOA->MODER |= (1U<<5);

    //Set PA2 alternate function type to UART_TX (AF07)
    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 baudrate
    uart_set_baudrate(USART2, APB1_CLK, UART_BAUDRATE);
    //Configure transfer direct
    USART2->CR1 = CR1_TE;

    //Enable uart module
    USART2->CR1 |= CR1_UE;

}

void uart2_write(int ch){
    while( !(USART2->SR & SR_TXE)){}
    USART2->DR = (ch & 0xFF);
}

static void uart_set_baudrate(USART_TypeDef *USARTx, uint32_t PeriphClk, uint32_t BaudRate){
    USARTx->BRR |= compute_uart_bd(PeriphClk, BaudRate);
}

static uint16_t compute_uart_bd(uint32_t PeriphClk,uint32_t BaudRate){
    return ((PeriphClk + (BaudRate/2U))/BaudRate);
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)