I am trying to connect STM32F373 to my computer (Windows 10) via USB, aiming to have a log on terminal. Nevertheless, the COM port does not even appear in Device Manager. I read on the internet that others had problems with Windows returning "Unknown Device". But I am not getting anything. No response at all.
I took everything that was in this video, with parts of the code copied directly from this page. The notable difference is that the F3 series supports only Full-Speed. Considering the code from the video, it is the only change that the function for transmitting is CDC_Transmit_FS(...) instead of CDC_Transmit_HS(...). The main loop remains the same. Compilation and upload to the MCU seem to be successful.
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usbd_cdc_if.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define USB_BUFLEN 128
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t usbTxBuf[USB_BUFLEN];
uint16_t usbTxBufLen;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
usbTxBufLen = snprintf((char *) usbTxBuf, USB_BUFLEN, "%lu\r\n", HAL_GetTick());
CDC_Transmit_FS(usbTxBuf, usbTxBufLen);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL3;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInit.USBClockSelection = RCC_USBCLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
usbd_cdc_if.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : usbd_cdc_if.c
* @version : v2.0_Cube
* @brief : Usb device for Virtual Com Port.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usbd_cdc_if.h"
/* USER CODE BEGIN INCLUDE */
/* USER CODE END INCLUDE */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @brief Usb device library.
* @{
*/
/** @addtogroup USBD_CDC_IF
* @{
*/
/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
* @brief Private types.
* @{
*/
/* USER CODE BEGIN PRIVATE_TYPES */
/* USER CODE END PRIVATE_TYPES */
/**
* @}
*/
/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
* @brief Private defines.
* @{
*/
/* USER CODE BEGIN PRIVATE_DEFINES */
/* USER CODE END PRIVATE_DEFINES */
/**
* @}
*/
/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
* @brief Private macros.
* @{
*/
/* USER CODE BEGIN PRIVATE_MACRO */
/* USER CODE END PRIVATE_MACRO */
/**
* @}
*/
/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
* @brief Private variables.
* @{
*/
/* Create buffer for reception and transmission */
/* It's up to user to redefine and/or remove those define */
/** Received data over USB are stored in this buffer */
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
/** Data to send over USB CDC are stored in this buffer */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
/* USER CODE BEGIN PRIVATE_VARIABLES */
USBD_CDC_LineCodingTypeDef LineCoding = {
115200,
0x00,
0x00,
0x08
};
/* USER CODE END PRIVATE_VARIABLES */
/**
* @}
*/
/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
* @brief Public variables.
* @{
*/
extern USBD_HandleTypeDef hUsbDeviceFS;
/* USER CODE BEGIN EXPORTED_VARIABLES */
/* USER CODE END EXPORTED_VARIABLES */
/**
* @}
*/
/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
* @brief Private functions declaration.
* @{
*/
static int8_t CDC_Init_FS(void);
static int8_t CDC_DeInit_FS(void);
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */
/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */
/**
* @}
*/
USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
{
CDC_Init_FS,
CDC_DeInit_FS,
CDC_Control_FS,
CDC_Receive_FS
};
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initializes the CDC media low layer over the FS USB IP
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Init_FS(void)
{
/* USER CODE BEGIN 3 */
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
return (USBD_OK);
/* USER CODE END 3 */
}
/**
* @brief DeInitializes the CDC media low layer
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_DeInit_FS(void)
{
/* USER CODE BEGIN 4 */
return (USBD_OK);
/* USER CODE END 4 */
}
/**
* @brief Manage the CDC class requests
* @param cmd: Command code
* @param pbuf: Buffer containing command data (request parameters)
* @param length: Number of data to be sent (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
/* USER CODE BEGIN 5 */
switch(cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
LineCoding.bitrate = (uint32_t) (pbuf[0] | (pbuf[1] << 8) |
(pbuf[2] << 16) | (pbuf[3] << 24));
LineCoding.format = pbuf[4];
LineCoding.paritytype = pbuf[5];
LineCoding.datatype = pbuf[6];
break;
case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t) (LineCoding.bitrate);
pbuf[1] = (uint8_t) (LineCoding.bitrate >> 8);
pbuf[2] = (uint8_t) (LineCoding.bitrate >> 16);
pbuf[3] = (uint8_t) (LineCoding.bitrate >> 24);
pbuf[4] = LineCoding.format;
pbuf[5] = LineCoding.paritytype;
pbuf[6] = LineCoding.datatype;
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break;
default:
break;
}
return (USBD_OK);
/* USER CODE END 5 */
}
/**
* @brief Data received over USB OUT endpoint are sent over CDC interface
* through this function.
*
* @note
* This function will issue a NAK packet on any OUT packet received on
* USB endpoint until exiting this function. If you exit this function
* before transfer is complete on CDC interface (ie. using DMA controller)
* it will result in receiving more data while previous ones are still
* not sent.
*
* @param Buf: Buffer of data to be received
* @param Len: Number of data received (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* @brief CDC_Transmit_FS
* Data to send over USB IN endpoint are sent over CDC interface
* through this function.
* @note
*
*
* @param Buf: Buffer of data to be sent
* @param Len: Number of data to be sent (in bytes)
* @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if (hcdc->TxState != 0){
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
/* USER CODE END 7 */
return result;
}
/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
/**
* @}
*/
/**
* @}
*/
The device is a custom board, and the schematic with the key parts related to USB is shown below. MCU schematic.
Here are the USB settings from CubeMX
Clock settings. Clock configuration.
I have tried to use the debugger, but I was only able to find out that the execution of transmission ends on line 300. Code snippet with tracked problem.
DISCLAIMER: I was not sure how to share the whole project in a simple way, so I put there only the parts I considered relevant. I can supply anything else if needed.
-
2\$\begingroup\$ Please use code blocks rather than quote blocks when you're posting code. Check out the "show formatting tips" button at the top right when you're writing a question - there's a bunch of helpful formatting info in there :) \$\endgroup\$Polynomial– Polynomial2025年08月08日 20:36:38 +00:00Commented Aug 8 at 20:36
-
1\$\begingroup\$ Should I also edit the second code in this way instead of the picture snippet? I was not sure if it would not be worse without row numbering. \$\endgroup\$Humphrey Appleby– Humphrey Appleby2025年08月08日 20:41:29 +00:00Commented Aug 8 at 20:41
-
1\$\begingroup\$ @HumphreyAppleby Yeah, code as text instead of screenshots would be preferable. You can post the full code; once it goes beyond a certain length the site will add a scrollbar to the code block. \$\endgroup\$Polynomial– Polynomial2025年08月08日 20:50:45 +00:00Commented Aug 8 at 20:50
-
1\$\begingroup\$ I tried to add the most important parts as recommended, omitting only schematics with sensors and the LED array. The above codes are files that were modified. Every other file was untouched. \$\endgroup\$Humphrey Appleby– Humphrey Appleby2025年08月08日 20:58:14 +00:00Commented Aug 8 at 20:58
-
1\$\begingroup\$ Thanks for adding the extra details, your question is much more answerable now! :) \$\endgroup\$Polynomial– Polynomial2025年08月08日 21:29:37 +00:00Commented Aug 8 at 21:29
1 Answer 1
There's no pull-up on USB D+ pin.
The PC will not see that anything is plugged in so it will not try to communicate with anything.
That's why the USB does not work.
But it seems there might be room for improving other things that are not in line with manufacturer recommendations, like why is there a pull-up on NRST pin.
Also it is difficult to figure out the part value from the part numbers and I am not going to zoom into them, figure out what they read and type them into google to see if the crystal and other resiators and capacitors have sensble values.
But the USB should work after fixing it.
-
\$\begingroup\$ HSE is this one eu.mouser.com/ProductDetail/NDK/…. It has 8 pF load capacitance. Parallel capacitors are GJM1555C1H6R0WB01D with 6 pF. The reason behind the NRST pull-up is this video youtu.be/PMEpQZ90f34?feature=shared&t=1307. As I am still learning this, I did not try to question it. The resistor seems to be the biggest problem, as it is missing entirely from the board. I have some THT resistors at home, and I can try to solder them to a suitable place. \$\endgroup\$Humphrey Appleby– Humphrey Appleby2025年08月08日 21:20:24 +00:00Commented Aug 8 at 21:20
-
\$\begingroup\$ @HumphreyAppleby In the video they also claim the whole reset circuit including the capacitor is not necessary. That is not true for STM32 MCUs. Now, in general, a generic MCU could need an external pull-up and maybe an optional capacitor for a bit filtering. That certainly isn't the case for STM32 MCUs. Also there are also differences between STM32 MCUs so what has been learnt on one model may be different on a different model, which means everything must be verified from the documentation of that exact MCU. \$\endgroup\$Justme– Justme2025年08月08日 21:35:05 +00:00Commented Aug 8 at 21:35
-
\$\begingroup\$ Just out of curiosity. A year ago, I was designing something similar with the F4 series MCU (particularly F401RET). I am checking the schematic now, and there are no additional pull-up resistors. And it seems to me that I was using FS as well. It worked. That was the reason why I did not even think about doing it differently. I would really love to avoid this mistake next time. But this thing is quite confusing. Do you please have some explanation? \$\endgroup\$Humphrey Appleby– Humphrey Appleby2025年08月08日 21:49:28 +00:00Commented Aug 8 at 21:49
-
2\$\begingroup\$ @HumphreyAppleby Documentation for this F373 MCU says it needs external resistor. Documentation for that F401 MCU says it has one built-in. They are just different MCUs with different USB peripherals inside them. \$\endgroup\$Justme– Justme2025年08月08日 22:48:13 +00:00Commented Aug 8 at 22:48
-
\$\begingroup\$ Thank you. I am gonna try to solder a THT resistor, and if it solves the issue, I will accept the answer. Nevertheless, I am having only a 2k2 resistor, so it might be a little bit later. \$\endgroup\$Humphrey Appleby– Humphrey Appleby2025年08月09日 06:17:12 +00:00Commented Aug 9 at 6:17