Skip to content

Conversation

mathieuchopstm
Copy link
Contributor

@mathieuchopstm mathieuchopstm commented Oct 2, 2025

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

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
tmon-nordic
tmon-nordic previously approved these changes Oct 3, 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
Create a new Kconfig option allowing to tweak the RxFIFO size on OTG_FS
and OTG_HS instances, and replace the old hardcoded method with this new
mecanism.

The default value of 600 bytes yields a similar size to the the previous
hardcoded default of 160 words (= 640 bytes) when combined with the fixed
overhead computed by the driver (~56 bytes on OTG_FS with 6 endpoints).

Also fix a tiny error in a logging message (DRAM size in bytes, not bits).

Signed-off-by: Mathieu Choplain <[email protected]>
@mathieuchopstm mathieuchopstm removed the DNM This PR should not be merged (Do Not Merge) label Oct 3, 2025
@mathieuchopstm
Copy link
Contributor Author

Went for a different solution which allows tweaking RxFIFO size via Kconfig. This is acceptable for now since the driver is single-instance anyways, and more flexible than hardcoding a value in the driver.

Testing will be done at a later time to confirm no regression is observed...

Copy link

sonarqubecloud bot commented Oct 3, 2025

@everedero
Copy link
Contributor

I tested it on the apex_pro_mini / stm32l412 target and it works! 🥳. The exact test being: checking that lsusb gives me a "NordicSemiconductor Zephyr testusb sample", and also verifying that the testusb enumeration disappears when I disconnect the device.

@mathieuchopstm mathieuchopstm linked an issue Oct 6, 2025 that may be closed by this pull request
1 task
@mathieuchopstm
Copy link
Contributor Author

mathieuchopstm commented Oct 6, 2025

With the usual cherry-pick from 94001, I see one regression compared to #96028 (comment): test 13 no longer passes on nucleo_l552ze_q (error 22, verify_not_halted failed status -110 as usual)

This is surprising given that the board uses the ST USB IP which (should!) see 0 functional change (it isn't affected by the RxFIFO stuff). I'll try to see if error is present in main, but either way this is a non-issue to me since test 13 also fails on all boards in HS mode regardless.

Note: I did not re-test N6 since it should be almost identical to U5A5 (same IP, only PHY differs).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: USB Universal Serial Bus platform: STM32 ST Micro STM32
Projects
None yet
Development

Successfully merging this pull request may close these issues.

USB sample not working on STM32L412
6 participants