1. Understanding endpoint configuration
1.1 Endpoint size and buffering
Each endpoint type has specific size and buffering requirements:
- Control, interrupt, bulk: The max packet size is 64 bytes (Full-Speed) and 64, 1024, 512 respectively in High-Speed.
- Isochronous: The max packet size is 1023 bytes (Full-Speed) and 1024 bytes (High-Speed).
Ensure that data payloads do not exceed these sizes to prevent aborted transfers.
1.2 Endpoint addressing
Endpoints have unique addresses comprising direction and endpoint number:
- Bits 0-3: Endpoint number (0-15).
- Bit 7: Direction (0 for OUT, 1 for IN).
- Bits 4-6: Reserved.
Example:
#define EP1_OUT 0x01 // Endpoint 1, OUT direction
#define EP1_IN 0x81 // Endpoint 1, IN direction
1.3 Using the HAL_PCDEx_PMAConfig() function
The HAL_PCDEx_PMAConfig() function is used to configure the PMA for each endpoint in the application. This function is typically called in the USBD_LL_Init function in the usbd_conf.c file, which is generated by STM32CubeMX.
1.3.1 Function prototype
HAL_StatusTypeDef HAL_PCDEx_PMAConfig(PCD_HandleTypeDef *hpcd, uint16_t ep_addr, uint16_t ep_kind, uint32_t pmaadress);
1.3.2 Parameters
hpcd : Pointer to the USB device instance.
ep_addr : Endpoint address (direction + number.)
ep_kind : Endpoint type (USB_SNG_BUF for single buffer, USB_DBL_BUF for double buffer.)
- USB_SNG_BUF: single buffer used.
- USB_DBL_BUF: double buffer used.
pmaaddress : PMA address for the endpoint buffer(s.)
- Single buffer: 16-bit PMA address.
- Double buffer: 32-bit value combining two 16-bit PMA addresses (buffer0 in LSB, buffer1 in MSB.)
1.4 Best practice for PMA allocation
STM32 developers must not rely on STM32CubeMX code generation for PMA configuration. Instead, follow these guidelines:
- Use
HAL_PCDEx_PMAConfig() for each endpoint in your USB device configuration.
- Allocate PMA memory based on a predefined PMA address table to avoid overlaps.
- Use the BTABLE starting at address
0x00 to store endpoint buffer descriptors.
- Ensure that buffer boundaries are correct to prevent conflicts with other endpoint descriptors.
- Optimize memory usage by reducing buffer offsets and minimizing unused space.
- To avoid any potential issue linked to overlapping or too tightly packed buffer regions, increase the initial PMA buffer START address to 0x40 (the corner-case scenario.)
2. CDC application configuration
CDC applications typically use three endpoints: Bulk IN, Bulk OUT, and Command Interrupt IN.
HAL_PCDEx_PMAConfig(&hpcd_USB_FS, EP1_IN, PCD_SNG_BUF, 0x40); //EP1 BULK IN
HAL_PCDEx_PMAConfig(&hpcd_USB_FS, EP1_OUT, PCD_SNG_BUF, 0x80); // EP1 Bulk OUT
HAL_PCDEx_PMAConfig(&hpcd_USB_FS, EP2_IN, PCD_SNG_BUF, 0xC0); //EP2 Interrupt IN and Size of each region is 64B
3. HID application configuration
HID applications typically use an Interrupt IN endpoint to send data to the host.
HAL_PCDEx_PMAConfig(&hpcd_USB_FS, EP3_IN, PCD_SNG_BUF, 0x100); //EP3 Interrupt IN 64B
4. MSC application configuration
MSC applications use Bulk IN and Bulk OUT endpoints for data transfer.
HAL_PCDEx_PMAConfig(&hpcd_USB_FS, EP4_IN, PCD_SNG_BUF, 0x140); //EP4 Bulk IN 64B
HAL_PCDEx_PMAConfig(&hpcd_USB_FS, EP4_OUT, PCD_SNG_BUF, 0x180); // EP4 Bulk Out 64B
5. Audio application configuration
Audio speaker or headset application use isochronous OUT endpoints for data transfer.
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, AUDIO_OUT1_EP, PCD_DBL_BUF, 0x01500090);
// EP4 ISO Out : 32-bit PMA addresses split into two 16-bit
- Double-buffering requires two separate buffer addresses for the same endpoint (pmaaddr0 and pmaaddr1).
- For buffer 0 PMA start address 0x90 and for buffer 2 PMA start address 0x150
6. Debugging and testing
- Use debugging tools to trace USB communication and identify potential mismatches in endpoint size configurations.
- Test with different endpoint sizes (for example, 16, 32, 64 bytes) to determine the optimal configuration for your buffer. Try adding 0x10, 0x20, or 0x40.
- Set USB interrupt priority higher to prevent USB ISR starvation.
- You need to be careful not to overlap one buffer with another. Otherwise, you get unexpected behavior.
- For USBX middleware, verify if your application is configured to handle the desired endpoint sizes. This includes ensuring that the UX_SLAVE_REQUEST_DATA_MAX_LENGTH is set appropriately.
- In case of selecting EP3 directly, you should consider allocating buffers to different descriptors of precedent in, for example, of EP1 and EP2.
Conclusion
Configuring USB applications on STM32 involves careful management of endpoints and buffer memory. By following these guidelines and examples, developers can optimize their USB applications for efficient data transfer and reliable communication.
For further detailed technical information, consult the USB section in the reference manual applicable to your specific STM32 product series. If you have further questions, feel free to ask on ST Community forums.
Related links