back

@Levi--G's USBLibrarySTM32

Unlike older Maple library, STM32duino USBDevice does not support composite USB for e.g. CDC + MIDI.
USBLibrarySTM32 emulates AVR Arduino PluggableUSB API,
effectively replacing STM32duino core USBDevice library
reportedly works with Arduino sketches ported to PlatformIO, but had issues in Arduino 2.
- wanted to pretend that it is ARDUINO_ARCH_AVR;
  instead, hacked HID-project/src/HID-Settings.h and MIDIUSB/src/MIDIUSB.h:
	- #if defined(ARDUINO_ARCH_AVR)
	+ #if defined(ARDUINO_ARCH_AVR) || defined(HAL_PCD_MODULE_ENABLED)

- requires USBCON and HAL_PCD_MODULE_ENABLED build flags
  probably set in menu based on usb_flags and platform.txt
- Arduino 2 does not see files in USBLibrarySTM32/include/;
  moving those files to USBLibrarySTM32/src/ fixed that.
- reported my experience
- coordination with STM32duino core USB is discussed here;
  likely integration would be as a menu option

This compiles with hacked MIDIUSB Library for Arduino example sketch,
but then failed to link because duplicated STM32duino USB library definitions.

working   5 Sep 2025
sample SerialUSB sketch compiles, loads and runs on a Black Pill from VSCode-Arduino. then Arduino 2:
  • moved USBDevice folder out of Arduino15/packages/STMicroelectronics/hardware/stm32/2.11.0/libraries
      Arduino 2 scripting wanted to use USBDevice source, whether referenced or not..
  • added USBLibrarySTM32 to Documents/Arduino/libraries
  • in USBLibrarySTM32, moved files from include to src
  • moved SerialUSB example src/main.cpp to SerialUSB.ino, added build_opt.h
      added syncopated LED blink code to SerialUSB.ino, for deducing execution state
  • Arduino Serial Monitor or PuTTY can connect and pass data
      initially failed, because COM8 conflict with com0com null modem

failed workarounds, leaving USBDevice folder in Arduino15/packages/STMicroelectronics/hardware/stm32/2.11.0/libraries
STM32duino USB multiple definition
install and use a custom core version
more detailsPlatform specification
https://github.com/stm32duino/Arduino_Core_STM32 seemingly matches (658MB) content at
AppData/Local/Arduino15/packages/STMicroelectronics/hardware/stm32/2.11.0/

results from grep -R USBD_Init

potential hack, based on feedback from @Levi--G
add ../Arduino2/platform.local.txt file in packages/STMicroelectronics/hardware/stm32/2.11.0/:
USBDevice_include_dir=/libraries/USBLibrarySTM32
With only this change, builds fail:
C:\Users\bleke\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.11.0\cores\arduino/WSerial.h:7:12:
	 fatal error: USBSerial.h: No such file or directory
    7 |   #include "USBSerial.h"
      |            ^~~~~~~~~~~~~
compilation terminated.
Success requires setting USB support (if available): "None", then:
$ cat MIDIUSB_loop/build_opt.h
-DUSBCON -DHAL_PCD_MODULE_ENABLED
Attempts to build a USBSerial library in user space failed
Compiling STM32 core seemingly uses incompatible rules...


USB enumeration, endpoints and descriptors

problematic USBSerial.availableForWrite()

hardware serial trace log; USBSerial COM session terminated after goodbye
USBLibrarySTM32 seemingly lacks means to detect COM port session disconnects;
USBSerial.availableForWrite() presumably reports space available when not.
  • Want to configure Black Pill composite USB device with CDC and MIDI,
    occasionally using CDC for logging and debugging...

13 Sep 2025 availableForWrite() fixed in develop branch

Updated SerialUSB sketch

How it was

This library interfaces, via USBD_HandleTypeDef to
Arduino15/packages/STMicroelectronics/hardware/stm32/2.11.0/system/Middlewares/ST/STM32_USB_Device_Library/Core,
specifically USBD_HandleTypeDef in STM32_USB_Device_Library/Core/Inc/usbd_def.h, as described in ST's wiki

For USBSerial, UDBCDC write(const uint8_t *buffer, size_t size) calls USB_Send(CDC_ENDPOINT_IN, buffer, size);
USB_Send() calls USB_SendQuick(),
which grabs the CDC endpoint buffer class instance and invokes its Write method,
then, if endpoint state is HID_IDLE, invokes USB_SendTXBufferUnsafe(),
which invokes USBD_LL_Transmit(), which calls HAL_PCD_EP_Transmit()
for the implicated chip type in STMicroelectronics/hardware/stm32/2.11.0/system/Drivers/.
Curiously, this release:
"Remove Lock mechanism from HAL_PCD_EP_Transmit() and HAL_PCD_EP_Receive() API’s"...

HAL_PCD_EP_Transmit() returns HAL_StatusTypeDef, which gets ignored.

After USB_SendQuick(), USB_Send() calls USB_Flush_Internal(), but ignores its return code.
USB_Flush_Internal() does nothing if USB_SendAvailable_Internal() returns true.

USBLibrarySTM32 seemingly handles only fixed size buffers;
if only 1 byte is written, a full 64-byte buffer is used.
Thus, availableForWrite() returns either USB_EP_SIZE or 0.

Because default PACKETBUFFER_ALLOW_OVERWRITE was true, for e.g. Black Pill,
availableForWrite() always returned USB_EP_SIZE

int USBCDC::availableForWrite(void)
{
  return USB_SendAvailable(CDC_ENDPOINT_OUT) ? USB_EP_SIZE : 0;
}

static bool USB_SendAvailable_Internal(USBD_HID_HandleTypeDef *&hhid, uint8_t endp)
{
  uint8_t ep = SMALL_EP(endp);
#if PACKETBUFFER_USE_TX_BUFFERS
  if (EP_Buffers[ep] != NULL && (!EP_Buffers[ep]->isFull() || PACKETBUFFER_ALLOW_OVERWRITE))
  {
    return true;
  }
#endif

USBCDC write() error recovery

  • USBLibrarySTM32/src/USBCDC.cpp setWriteError() seems vestigial;
    USBSerial.clearWriteError() did not help...
  • neither did USBSerial.end() .... USBSerial.begin(115200) by itself help
  • What did work:  USBSerial.end(); USB_End();, followed by restarting both
maintained by blekenbleu