Skip to main content
Visitor II
June 10, 2026
Question

STM32F411 USB CDC Host

  • June 10, 2026
  • 4 replies
  • 35 views

I have a laser engraver that runs on an ESP32 S2 Mini microcontroller. It has the following signature: “Espressif CDC Device” and emulates a COM-type serial port. I had two identical cables; if I connect my engraver to my PC via a serial program (NinjaTerm), I can control GRBL. I cut one of these cables, and they have four wires: VBUS, D+, D-, and GND. After crimping some connectors onto the ends of the wires and testing the cable connected to the port to distinguish between my D+ and D-, 

Now I’d like to put an STM32F411 (WeAct BlackPill v3.0) between my engraver and my PC to control my homemade Z-axis. The PC side is on a UART port of the STM32 connected to a CH340, and on the engraver side, a USB (D+/D-) CDC Host (Note: I’m not using the USB-C connector already soldered onto the BlackPill). The UART programming side worked perfectly. Where it’s getting stuck is on the CDC side… no response… 
 

 

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "usbh_cdc.h"

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;

void HAL_UART_Printf(UART_HandleTypeDef Uart, const char *Format, ...)
{
unsigned char TmpStr[128];

va_list args;
va_start(args, Format);
vsprintf((char*)TmpStr, Format, args);
va_end(args);

HAL_UART_Transmit(&Uart, TmpStr, strlen((char*)TmpStr), 10);
}

extern USBH_HandleTypeDef hUsbHostFS;
extern ApplicationTypeDef Appli_state;

void ParseCommand(char *line)
{
if (strncmp(line, "M900", 4) == 0)
{
return;
}

if (strncmp(line, "M901", 4) == 0)
{
return;
}

char txbuf[150];
sprintf(txbuf,"%s\r\n",line);

USBH_CDC_Transmit(&hUsbHostFS, (uint8_t*)txbuf, strlen(txbuf));
}

char UartCmd[256];
uint8_t UartCmdCount = 0;
uint8_t UartRx;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2)
{
HAL_UART_Printf(*huart, "Uart2Receive\r\n");

if (UartRx == '\n' || UartRx == '\r')
{
UartCmd[UartCmdCount] = '\0';
ParseCommand(UartCmd);
UartCmdCount = 0;
}
else
{
UartCmd[UartCmdCount++] = UartRx;
if (UartCmdCount > 256) UartCmdCount = 0;
}

HAL_UART_Receive_IT(huart, &UartRx, 1);
}
}

#define RX_BUFF_SIZE 64 /* Max Received data 1KB */
uint8_t CDC_RX_Buffer[RX_BUFF_SIZE];

void USBH_CDC_RxCpltCallback(USBH_HandleTypeDef *phost)
{
HAL_UART_Printf(huart2, "CDC Receive\r\n");
/* Get the length of data received */
//uint16_t length = USBH_CDC_GetLastRxSize(phost);

/* Copy data to your FIFO/Ring Buffer for non-blocking processing */
//Process_Rx_Data(rx_buffer, length);

//if (length > 0)
//HAL_UART_Transmit(&huart2, CDC_RX_Buffer, length, 10);

/* Re-arm the CDC receive interrupt for the next packet */
USBH_CDC_Receive(phost, CDC_RX_Buffer, sizeof(CDC_RX_Buffer));
}



/****** MAIN PART *********************/
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_USB_HOST_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Printf(huart2, "\x1b[94mWelcome\r\n");
HAL_UART_Receive_IT(&huart2, &UartRx, 1);
USBH_CDC_Receive(&hUsbHostFS, CDC_RX_Buffer, 1);
static uint8_t once = 0;

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();

/* USER CODE BEGIN 3 */
HAL_UART_Printf(huart2, "My name is %s and I`ve %d year old.\r\n", "Nobody", 30);
HAL_Delay(1000);

if (Appli_state == APPLICATION_READY)
{
if (!once)
{
HAL_UART_Printf(huart2,"CDC READY\r\n");

char cmd[] = "$$\r\n";
USBH_CDC_Transmit(&hUsbHostFS, (uint8_t*)cmd, strlen(cmd));
once = 1;
}
}
}
/* USER CODE END 3 */

 

4 replies

ST Technical Moderator
June 10, 2026

Hello ​@Fleuve 

The WeAct BlackPill is not an official ST product.

ST resources support genuine ST products. ST does not guarantee that clones or counterfeit products operate correctly with the firmware that ST provides.

Thank you for your understanding.

If work with this board must continue, use one of the ST USB CDC host examples as a comparison with the project and check for any differences.
BR
Gyessine

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question.
Andrew Neil
Super User
June 10, 2026

As ​@Gyessine said, the Black Pill is not an ST Product, and might not have a genuine STM32.

 

Therefore it would be best to first get this working on a genuine ST board:

https://www.st.com/en/microcontrollers-microprocessors/stm32f411ce.html#tools-software

Once you’ve got it working on a genuine ST board, you could then move on to the Black Pill

 

Note that connecting to USB via flying leads is not going to give great results;  you’d be better using a board with a dedicated USB host socket - looks like the 32F411EDISCOVERY is the best bet for that ...

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.
Ozone
Principal
June 10, 2026

> Where it’s getting stuck is on the CDC side… no response… 

Not quite sure what you mean, supposedly not the CH340 converter, but the “Falcon” engraver side.

BTW, I have two BluePill boards, and no indication the F411 MCUs on those are not genuine. Just saying.


But the Bluepill boards have a debug connector that works fine, I had tried a ST-Link and a JLink.
So, you could debug your code, and check the USB-related part.

Pavel A.
June 10, 2026

So, the CH340 and UART part is working fine, and the problem is the USB CDC host function, correct?

Does your board provide power to the connected USB device or is it self-powered?  Does the device detect and start enumerating - or no response at all, to any host request?