Skip to content

Conversation

mathieuchopstm
Copy link
Contributor

Cleans up various parts of the STM32 UDC shim driver while also fixing issues related to endpoint sizes.

Testing on hardware TBD.

The EP0 max packet size was de facto a constant because its value was the
same regardless of which USB IP was in use. However, it was stored as part
of the instance configuration anyways which is wasteful and slower.

Create new "UDC_STM32_EP0_MAX_PACKET_SIZE" driver-level constant with which
all usage of the per-instance configuration field is replaced.

Signed-off-by: Mathieu Choplain <[email protected]>
The ST USB controller (compatible 'st,stm32-usb') is fitted with private
SRAM called the Private Memory Area or PMA. This is primarily used to hold
data transfered over USB, but it also contains the so-called 'buffer table'
(a.k.a. BTABLE) which holds the base address and size of buffers in the PMA
allocated to each endpoint. The BTABLE is placed by the driver at the start
of the PMA and occupies a fixed size ('USB_BTABLE_SIZE'), which was stored
in the driver configuration field 'pma_offset'. This mechanism is unused on
non-ST USB controllers from STM32 microcontrollers, but USB_BTABLE_SIZE is
still defined (to a dummy value) and stored in the 'pma_offset' field which
becomes unused.

Remove the 'USB_BTABLE_SIZE' definition and the 'pma_offset' field from the
driver configuration, and update the ST USB controller-specific verison of
'udc_stm32_mem_init' to derive the BTABLE size from the number of endpoints
that the controller has instead.

Signed-off-by: Mathieu Choplain <[email protected]>
STM32 OTG USB controllers use word-addressable RAM with a 32-bit word size
so all allocations from the USB SRAM must be 32-bit aligned. The driver did
not accept unaligned values of wMaxPacketSize, and FIFO allocation code was
implicitly expecting FIFO sizes to be aligned as well (since it allocated
"bytes / 4" without rounding up).

Update driver to accept values of wMaxPacketSize that aren't word-aligned
and to allocate properly sized FIFOs sizes when an unaligned size has been
requested.

Signed-off-by: Mathieu Choplain <[email protected]>
The maximal packet size (for non-control endpoints) was obtained by the
driver from HAL definitions which appear to not properly reflect hardware
capabilities.

Update driver to allow endpoints with wMaxPacketSize up to the maximal
value allowed by the USB Specification depending on operation mode, since
all STM32 USB controllers always support these values. Also move the EP
max packet size field in the 'struct udc_stm32_config' to avoid implicit
padding and add a documentation comment.

Signed-off-by: Mathieu Choplain <[email protected]>
@mathieuchopstm mathieuchopstm changed the title drivers: udc: udc: stm32: driver cleanup and EP MPS fixes drivers: usb: udc: stm32: driver cleanup and EP MPS fixes Oct 2, 2025
@zephyrbot zephyrbot added platform: STM32 ST Micro STM32 area: USB Universal Serial Bus labels Oct 2, 2025
Copy link

sonarqubecloud bot commented Oct 2, 2025

Copy link
Contributor

@etienne-lms etienne-lms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Some minor comments.

* beginning of Private Memory Area and consumes
* 8 bytes for each endpoint.
*/
priv->occupied_mem = (8 * cfg->num_endpoints);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking: could drop parentheses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, copy-paste artifact from expanding USB_BTABLE_SIZE = (8 * USB_NUM_BIDIR_ENDPOINTS).

#define UDC_STM32_NODE_EP_MPS(node_id) \
((UDC_STM32_NODE_SPEED(node_id) == PCD_SPEED_HIGH) ? 1024U : 1023U)


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking: could you remove this extra empty line?

*
* WARNING: Don't mix USB defined in STM32Cube HAL and CONFIG_USB_* from Zephyr
* Kconfig system.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these inline comment still useful? (non-blocking, liekly a bit outside the scope of this P-R)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the comment still applies because there is some usage remaining of the Cube macros (see L1115 in new file). But eventually it should be removed yes.

@mathieuchopstm
Copy link
Contributor Author

I am seeing a regression on b_u585i_iot02a (st,stm32-otgfs) because of the following:

/* The documentation is not clear at all about RX FiFo size requirement,
* 160 has been selected through trial and error.
*/
words = MAX(160, DIV_ROUND_UP(cfg->ep_mps, 4U));

This SoC has only 1280 bytes of DRAM. Beforehand, cfg->ep_mps was a small value (USB_OTG_FS_MAX_PACKET_SIZE = 64) so the result of MAX(160, cfg->ep_mps / 4) was 160 words = 640 bytes allocated for the RX FIFO. Now that cfg->ep_mps = 1023, the result of MAX(160, DIV_ROUND_UP(cfg->ep_mps, 4U)) is ((1023 + 3) / 4) = 256 words and 1024 bytes are allocated for the RX FIFO.

In addition, 64 bytes are reserved for EP0-OUT TX FIFO, so the RAM usage after initialization is now 1088 bytes (192 bytes free) instead of 708 (576 bytes free).

The testusb sample seems to create three endpoints that require FIFO allocation: two with mps=64, one with mps=0. Combine this with the mysterious line[1]:

words = (words <= 64) ? words * 2 : words;

This means that (64 + 64) * 2 = 256 bytes will be request for endpoint TX FIFOs... which is over the new budget of 192 bytes free! And thus, -ENOMEM is returned and bubbles up, leading to the sample failing miserably:

*** Booting Zephyr OS build v4.2.0-4890-g19f9377b9c1f ***
[00:00:02.480,000] <err> udc_stm32: Unable to allocate FIFO for 0x82
[00:00:02.487,000] <err> usbd_iface: Failed to handle op 1, ep 0x82, bm 0x00020002, -12
[00:00:02.495,000] <err> usbd_ch9: Failed to set configuration 1, -12
[00:00:02.502,000] <err> usbd_core: unrecoverable error -12, ep 0x00, buf 0x2000cef8

[1] I suspect the "mysterious line" is here to increase TX FIFO sizes as recommended in RefMan: "More space allocated in the transmit IN endpoint FIFO results in better performance on the
USB"


I will modify the driver to implement similar logic to the DWC2 driver:

  • take an hardcoded baseline value (I'll keep the historic 160 words)
  • add a small quantity based on endpoint count (as per RefMan)
  • limit to a certain percentage of the USB SRAM (previously, we appeared to use ~55% so limiting to half sounds acceptable)

@mathieuchopstm mathieuchopstm added the DNM This PR should not be merged (Do Not Merge) label Oct 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: USB Universal Serial Bus DNM This PR should not be merged (Do Not Merge) platform: STM32 ST Micro STM32
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants