Skip to main content

STM32 USB Implementation

STM32 provides four kinds of USB peripherals as shown below. You can refer to the CDC code generated by the code generator to understand how USB endpoints are configured.
On STM32, it is recommended to derive the USB device serial number from the MCU Unique ID (UID) and pass it as {reinterpret_cast<void*>(UID_BASE), 12} in the USB device constructor.

Current mainline pathClassRoleNotes
USB_BASE / FSDEVLibXR::STM32USBDeviceDevFsDeviceFSDEV / DRD FS device-side path
USB_OTG_FSLibXR::STM32USBDeviceOtgFSDevice side of OTG FSOTG FS device path
USB_OTG_HSLibXR::STM32USBDeviceOtgHSDevice side of OTG HSOTG HS device path

STM32USBDeviceDevFs

STM32USBDeviceDevFs supports two endpoint declaration styles; endpoint numbers for the buffers auto-increment:

  1. {usb_fs_ep0_in_buf, usb_fs_ep0_out_buf, 8, 8}: declares a bidirectional endpoint; hardware double buffering is not available
    • usb_fs_ep0_in_buf: EP0 IN software buffer array
    • usb_fs_ep0_out_buf: EP0 OUT software buffer array
    • 8: EP0 IN hardware RAM size
    • 8: EP0 OUT hardware RAM size
  2. {usb_fs_ep2_in_buf, 16, true}: declares a unidirectional endpoint using hardware double buffering
    • usb_fs_ep2_in_buf: EP2 IN software buffer array
    • 16: EP2 IN hardware RAM size
    • bool: is in direction

To ensure throughput, for Bulk endpoints the hardware RAM size should be no less than 64. The software buffer can be much larger than 64, and its size is proportional to transfer speed.

STM32USBDeviceDevFs usb_fs(
/* USB Handler */
&hpcd_USB_FS,
/* Endpoints */
{
{usb_fs_ep0_in_buf, usb_fs_ep0_out_buf, 8, 8},
{usb_fs_ep1_in_buf, usb_fs_ep1_out_buf, 128, 128},
{usb_fs_ep2_in_buf, 16, true}
},
USB::DeviceDescriptor::PacketSize0::SIZE_8,
0x1D50, 0x6199, 0x0100,
/* Language pack */
{&USB_FS_LANG_PACK},
/* Classes */
{{&usb_fs_cdc}},
/* Serial Number UID (12 bytes read from STM32 UID) */
{reinterpret_cast<void*>(UID_BASE), 12}
);

USB_OTG_FS/USB_OTG_HS

STM32USBDeviceOtgHS and STM32USBDeviceOtgFS also support two endpoint declaration styles. IN and OUT endpoint numbers each auto-increment independently:

  1. {{usb_otg_fs_ep0_in_buf, 8},...}: IN endpoints must declare both a buffer and a FIFO size
  2. {usb_otg_fs_ep0_out_buf, ...}: OUT endpoints only need to declare a buffer

All OUT endpoints share a single RX FIFO, which should be given a relatively large size. For performance, the IN endpoint FIFO size should not be smaller than the packet size, and the software buffer size is proportional to transfer speed.

// STM32USBDeviceOtgHS usb_hs(
STM32USBDeviceOtgFS usb_fs(
/* USB Handler */
&hpcd_USB_OTG_FS,
/* RX Fifo Size */
256,
/* Out Endpoints */
{usb_otg_fs_ep0_out_buf, usb_otg_fs_ep1_out_buf},
/* In Endpoints */
{{usb_otg_fs_ep0_in_buf, 8}, {usb_otg_fs_ep1_in_buf, 128}, {usb_otg_fs_ep2_in_buf, 16}},
USB::DeviceDescriptor::PacketSize0::SIZE_8,
0x1D50, 0x6199, 0x0100,
/* Language pack */
{&USB_OTG_FS_LANG_PACK},
/* Classes */
{{&usb_otg_fs_cdc}},
/* Serial Number UID (12 bytes read from STM32 UID) */
{reinterpret_cast<void*>(UID_BASE), 12}
);
usb_fs.Init();
usb_fs.Start();

Running

Just add the following statements:

usb_fs.Init();
usb_fs.Start();