cancel
Showing results for 
Search instead for 
Did you mean: 

Bare-metal USART driver

Jajang01
Visitor

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

1 REPLY 1
Andrew Neil
Super User

Welcome to the forum.

Please see How to write your question to maximize your chances to find a solution for best results

 

 


@Jajang01 wrote:

NUCLEO-F103RB


 So, presumably, you are using the ST-Link's VCP (Virtual COM Port) to connect to the PC ?

Are you sure that you are using the correct UART pins for that ?

 

Have you tried one of the ST examples for reference?

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.