cancel
Showing results for 
Search instead for 
Did you mean: 

NUCLEO-F103RB: Bare-metal USART driver

Jajang01
Associate II

I'm writing a UART driver for NUCLEO-F103RB and I followed all steps in the book "Bare-metal embedded C programming" and advices from Gemini but still can't see the receiving output from my PC.

How can I fix this?

Other parts than UART work without problem in this setting.

main.c

#include <stdint.h>
#include <stdio.h>

#include "gpio.h"
#include "uart.h"

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif



unsigned readBit(unsigned line, unsigned position){
	unsigned mask = 1U<<position;
	return ((mask & line) >> position);
}

int main(void)
{
	RCC_APB2EN_R |= 1U<<2;
	RCC_APB2EN_R |= 1U<<4;

	//led init
	GPIOA_MODE_R &= ~(1U<<20);
	GPIOA_MODE_R |= 1U<<21;
	GPIOA_MODE_R &= ~(1U<<22);
	GPIOA_MODE_R &= ~(1U<<23);
	//button init
	GPIOC_MODE_R &= ~(1U<<20);
	GPIOC_MODE_R &= ~(1U<<21);
	GPIOC_MODE_R |= 1U<<22;
	GPIOC_MODE_R &= ~(1U<23);

	uart_init();
	unsigned short button_pressed = 0;
	unsigned short led_on = 0;
    /* Loop forever */
	for(;;){
		for(int i = 0; i < 500000; i++);
		printf("Hello from STM32...\r\n");


	}
}

 

gpio.h

#define PERIPH_BASE 0x40000000UL
#define GPIOA_OFFSET 0x00010800UL
#define GPIOC_OFFSET 0x00011000UL
#define GPIOA_BASE PERIPH_BASE + GPIOA_OFFSET
#define GPIOC_BASE PERIPH_BASE + GPIOC_OFFSET
#define RCC_OFFSET 0x00021000UL
#define RCC_BASE PERIPH_BASE + RCC_OFFSET
#define APB2EN_R_OFFSET 0x18UL
#define RCC_APB2EN_R *(volatile unsigned int *)(RCC_BASE + APB2EN_R_OFFSET)
#define A_MODE_R_OFFSET 0x00UL
#define C_MODE_R_OFFSET 0x04UL
#define GPIOA_MODE_R *(volatile unsigned int *)(GPIOA_BASE + A_MODE_R_OFFSET)
#define GPIOC_MODE_R *(volatile unsigned int *)(GPIOC_BASE + C_MODE_R_OFFSET)
#define OD_R_OFFSET 0x0CUL
#define GPIOA_OD_R *(volatile unsigned int *)(GPIOA_BASE + OD_R_OFFSET)
#define ID_R_OFFSET 0x08UL
#define GPIOC_ID_R *(volatile unsigned int *)(GPIOC_BASE + ID_R_OFFSET)
#define BSRR_OFFSET 0x10UL
#define GPIOA_BSRR *(volatile unsigned int*)(GPIOA_BASE + BSRR_OFFSET)

 

uart.h

#define PERIPH_BASE 0x40000000UL
#define GPIOA_OFFSET 0x00010800UL
#define GPIOC_OFFSET 0x00011000UL
#define GPIOA_BASE PERIPH_BASE + GPIOA_OFFSET
#define GPIOC_BASE PERIPH_BASE + GPIOC_OFFSET
#define USART2_BASE PERIPH_BASE + 0x00013800UL
#define RCC_OFFSET 0x00021000UL
#define RCC_BASE PERIPH_BASE + RCC_OFFSET
#define RCC_APB1EN_R *(volatile unsigned int *)(RCC_BASE + 0x1CUL)
#define RCC_APB2EN_R *(volatile unsigned int *)(RCC_BASE + 0x18UL)
#define C_MODE_R_OFFSET 0x04UL
#define GPIOA_MODEL_R *(volatile unsigned int *)(GPIOA_BASE)
#define GPIOC_MODE_R *(volatile unsigned int *)(GPIOC_BASE + C_MODE_R_OFFSET)
#define USART2_BRR_R *(volatile unsigned int *)(USART2_BASE + 0x08UL)
#define USART2_CR1_R *(volatile unsigned int *)(USART2_BASE + 0x0CUL)
#define USART2_SR_R *(volatile unsigned int *)(USART2_BASE + 0x00UL)
#define USART2_DR_R *(volatile unsigned int *)(USART2_BASE + 0x04UL)
#define APB1_CLK 36000000
#define USART_BAUDRATE 115200

void uart_init(void);

 

uart.c

#include <stdint.h>
#include "uart.h"
void uart_init(void){
	RCC_APB2EN_R |= 1U<<2;
	RCC_APB1EN_R |= 1U<<17;//UART2 enable

    /*GPIOA_MODEH_R &= ~(1U<<4);
    GPIOA_MODEH_R |= (1U<<5);
    GPIOA_MODEH_R &= ~(1U<<6);
    GPIOA_MODEH_R |= (1U<<7);
    */
	GPIOA_MODEL_R &= ~(0xFUL << 8);

	    // Set MODE9[1:0] = 10 (Output mode, max speed 2 MHz)
	GPIOA_MODEL_R |= (1U << 9);

	    // Set CNF9[1:0] = 10 (Alternate function output Push-pull)
	GPIOA_MODEL_R |= (1U << 11);

    //int uartdiv = APB2_CLK/USART_BAUDRATE;
    unsigned uartdiv = APB1_CLK/USART_BAUDRATE;
    unsigned mantissa = uartdiv / 16;
    unsigned fraction = uartdiv % 16;
    USART2_BRR_R = (mantissa << 4) | fraction;
    //USART2_BRR_R = (APB1_CLK + (USART_BAUDRATE/2U))/(16U * USART_BAUDRATE);
    USART2_CR1_R |= 1U<<3;
    USART2_CR1_R |= 1U<<13;
}

int __io_putchar(int ch)
 {
    while(!(USART2_SR_R & (1U<<7))){}
    USART2_DR_R = (ch & 0xFF);
    return ch;
 }

 1.png

10 REPLIES 10
gbm
Principal

BRR formula above is simply wrong. Use the right one:

#define UART_CLK 36000000u
#define BAUD_RATE 115200u

UARTx->BRR = (UART_CLK + BAUD_RATE / 2u) / BAUD_RATE;

For the default, 16x oversampling, there is no "MANT" or FRAQ part. Even for 8x it's simpler than what you wrote above or what could be found in F10x RefMan.

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