Skip to main content
KPres.1
Associate
February 25, 2023
Solved

STM32F303VC Bare Metal - How to Enable VCP / USART Over USB?

  • February 25, 2023
  • 7 replies
  • 2029 views

I'm trying to follow the reference manual to use USART over USB via VCP (bare metal), but Realterm isn't able to read *any* data. According to the user manual, USART/VCP over USB should be supported, mentioning it's on the PC4,PC5 pins. Here's the code I'm using:

#include <stdio.h>
#include "stm32f303xc.h"
 
/* USART1 is an alternative function of GPIOC */
#define GPIOCEN (1U << 19)
#define USART1EN (1U << 14)
 
/* USART1 -> CR1 Control Register */
#define CR1_TE (1U << 3)
#define CR1_UE (1U << 0)
 
#define SYS_FREQ 8000000
#define APB2_CLK SYS_FREQ
 
#define USART_BAUDRATE 9600
 
static void usart_set_baudrate(USART_TypeDef *USARTx, uint32_t PeriphClk, uint32_t BaudRate);
static uint16_t compute_usart_bd(uint32_t PeriphClk, uint32_t BaudRate);
 
void usart1_tx_init(void);
void usart1_write(int ch);
 
int main(void)
{
 usart1_tx_init();
 
 while(1)
 {
 usart1_write('H');
 usart1_write('i');
 }
}
 
void usart1_tx_init(void)
{
 /****** Configure UART GPIO pin ******/
 /* Enable clock access to GPIOC */
 RCC -> AHBENR |= GPIOCEN;
 
 /* Set PC4 mode to alternate function mode */
 GPIOC -> MODER &= ~(1U << 8);
 GPIOC -> MODER |= (1U << 9);
 
 /* Set PC4 alternate function type to USART_TX */
 GPIOC -> AFR[0] |= (1U << 28);
 GPIOC -> AFR[0] |= (1U << 29);
 GPIOC -> AFR[0] |= (1U << 30);
 GPIOC -> AFR[0] &= ~(1U << 31);
 
 /****** Configure UART module ******/
 /* Enable clock access to USART1 */
 RCC -> APB2ENR |= USART1EN;
 
 /* Configure baud rate */
 usart_set_baudrate(USART1, APB2_CLK, USART_BAUDRATE);
 
 /* Enable UART module */
 USART1 -> CR1 = CR1_UE;
 
 /* Configure the transfer direction */
 USART1 -> CR1 = CR1_TE;
}
 
void usart1_write(int ch)
{
 
 /* Make sure transmit data register is empty */
 while (!(USART1 -> ISR & ISR_TXE)){}
 
 /* Write to transmit data register */
 USART1 -> TDR = (ch & 0xFF);
}
 
static void usart_set_baudrate(USART_TypeDef *USARTx, uint32_t PeriphClk, uint32_t BaudRate)
{
 USARTx -> BRR = compute_usart_bd(PeriphClk, BaudRate);
}
 
static uint16_t compute_usart_bd(uint32_t PeriphClk, uint32_t BaudRate)
{
 return ((PeriphClk + (BaudRate/2U))/BaudRate);
}

I'd very much appreciate any help or resources I could look at!

This topic has been closed for replies.
Best answer by Tesla DeLorean

Code is not very efficient, you want the compiler to do the work, not the MCU

Setting AF7 for PC7, not PC4

OR bits onto UART->CR1

7 replies

waclawek.jan
Super User
February 25, 2023

Where's the USB here? What hardware is this?

Style: Why don't you use symbols defined in the CMSIS-mandated device header (stm32f303xc.h)?

JW

Tesla DeLorean
Guru
February 25, 2023

Assuming a NUCLEO or DISCO board

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
gbm
Super User
February 25, 2023

Line 61 disables the UART. Lines 45..48 don't do what you expect them to - they set PC7.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Tesla DeLorean
Tesla DeLoreanBest answer
Guru
February 25, 2023

Code is not very efficient, you want the compiler to do the work, not the MCU

Setting AF7 for PC7, not PC4

OR bits onto UART->CR1

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
KPres.1
KPres.1Author
Associate
February 25, 2023

Thank you so much! I had rewritten the code at least 3 times, each time missing the fact I was setting the AF for the wrong pin. Everything seems to be working fine now!

I'm following a beginner's guide for a similar board, as this is my first time working with something other than an ESP32 and MicroPython, so code efficiency probably leaves much to be desired. But I'll get there eventually

waclawek.jan
Super User
February 25, 2023

> Assuming a NUCLEO or DISCO board

AFAIK there's no 100-pin-target Nucleo. The 'F303 Disco indeed uses 'F303VC, but older variants had the STLink without VCP (ST-LINK/V2 PCB version A or B, ST-LINK/V2-B (+ VCP + MSD) for PCB version C and newer),

If it's the C revision or newer, VCP related jumpers/SBs are to be checked.

And, reading out and checking content of UART and related GPIO registers is always the way to go. Plus observing the pins using oscilloscope/LA, plus the basic blinky to verify basic functionality and/or clocks settings.

JW