From 50a4eea41be18bfeb6ad49f6f28de21b66bf33ef Mon Sep 17 00:00:00 2001 From: cumin <13809292481@163.com> Date: Thu, 27 Aug 2026 15:55:27 +0800 Subject: [PATCH] feat(usb): add STM32C5 HAL v2 USB device support --- libraries/SrcWrapper/inc/stm32_def.h | 6 +- libraries/USBDevice/inc/usbd_cdc_if.h | 3 + libraries/USBDevice/inc/usbd_conf.h | 16 +- libraries/USBDevice/inc/usbd_ep_conf.h | 13 +- libraries/USBDevice/src/cdc/cdc_queue.c | 5 + libraries/USBDevice/src/cdc/usbd_cdc.c | 12 +- libraries/USBDevice/src/cdc/usbd_cdc_if.c | 8 +- libraries/USBDevice/src/usbd_conf.c | 5 +- libraries/USBDevice/src/usbd_confv2.c | 261 ++++++++++++++++++++++ libraries/USBDevice/src/usbd_ep_conf.c | 3 +- 10 files changed, 317 insertions(+), 15 deletions(-) create mode 100644 libraries/USBDevice/src/usbd_confv2.c diff --git a/libraries/SrcWrapper/inc/stm32_def.h b/libraries/SrcWrapper/inc/stm32_def.h index e057418c0c..f63b83de26 100644 --- a/libraries/SrcWrapper/inc/stm32_def.h +++ b/libraries/SrcWrapper/inc/stm32_def.h @@ -203,11 +203,13 @@ __STATIC_INLINE void LL_RTC_SetBinMixBCDU(RTC_TypeDef *RTCx, uint32_t BinMixBcdU } #endif // STM32U0xx -/* STM32G0xx, STM32U0xx and some STM32U5xx defined USB_DRD_FS */ +/* Some STM32 series define USB_DRD_FS instead of the legacy USB instance. */ #if !defined(USB) && defined(USB_DRD_FS) #define USB USB_DRD_FS #define PinMap_USB PinMap_USB_DRD_FS - #if defined(STM32H5xx) || defined(STM32U0xx) ||\ + #if defined(STM32C5xx) + #define USB_BASE USB_DRD_FS_BASE + #elif defined(STM32H5xx) || defined(STM32U0xx) ||\ defined(STM32U3xx) || defined(STM32U5xx) #define USB_BASE USB_DRD_BASE #if !defined(__HAL_RCC_USB_CLK_ENABLE) diff --git a/libraries/USBDevice/inc/usbd_cdc_if.h b/libraries/USBDevice/inc/usbd_cdc_if.h index 1d3f8b91ff..5f1459388a 100644 --- a/libraries/USBDevice/inc/usbd_cdc_if.h +++ b/libraries/USBDevice/inc/usbd_cdc_if.h @@ -59,6 +59,9 @@ uint8_t CDC_getStopBits(void); uint8_t CDC_getParity(void); uint8_t CDC_getDataBits(void); +/* Optional board hook invoked after the host changes the CDC line coding. */ +void CDC_LineCodingChanged(uint32_t bitrate); + #ifdef __cplusplus } #endif diff --git a/libraries/USBDevice/inc/usbd_conf.h b/libraries/USBDevice/inc/usbd_conf.h index a08fa61e7e..15d0d35341 100644 --- a/libraries/USBDevice/inc/usbd_conf.h +++ b/libraries/USBDevice/inc/usbd_conf.h @@ -30,8 +30,16 @@ extern "C" { #include "stm32_def.h" #if defined(USE_HALV2_DRIVER) -#error "USB library is not yet compatible with HALv2 driver." -#else +#if !defined(STM32C5xx) +#warning "USB device support is currently implemented only for STM32C5xx HAL v2." +#endif +#endif + +#if defined(STM32C5xx) +#define PCD_SNG_BUF HAL_PCD_SNG_BUF +#define PCD_DBL_BUF HAL_PCD_DBL_BUF +#endif + #if !defined(USB_BASE) && !defined(USB_OTG_DEVICE_BASE) #error "This board does not support USB! Select 'None' in the 'Tools->USB interface' menu" #endif @@ -40,8 +48,6 @@ extern "C" { #endif #if !defined(USB_BASE) && !defined(USB_OTG_FS) && defined(USB_OTG_HS) && !defined(USE_USB_HS) #error "This board support only USB High Speed! Select 'High Speed' or 'High Speed in Full Speed mode' in the 'Tools->USB interface' menu" -#endif - #endif #include #include @@ -77,7 +83,7 @@ extern "C" { #elif defined(STM32G0B1xx) || defined(STM32G0C1xx) #define USB_IRQn USB_UCPD1_2_IRQn #define USB_IRQHandler USB_UCPD1_2_IRQHandler -#elif defined(STM32C0xx) || defined(STM32H5xx) || defined(STM32U0xx) +#elif defined(STM32C0xx) || defined(STM32C5xx) || defined(STM32H5xx) || defined(STM32U0xx) #define USB_IRQn USB_DRD_FS_IRQn #define USB_IRQHandler USB_DRD_FS_IRQHandler #elif defined(STM32U5xx) && !defined(USB_DRD_FS) diff --git a/libraries/USBDevice/inc/usbd_ep_conf.h b/libraries/USBDevice/inc/usbd_ep_conf.h index 354b6f4d0c..b305b64e4f 100644 --- a/libraries/USBDevice/inc/usbd_ep_conf.h +++ b/libraries/USBDevice/inc/usbd_ep_conf.h @@ -69,10 +69,21 @@ typedef struct { #ifdef USBD_USE_CDC #define PMA_CDC_OUT_BASE (PMA_EP0_IN_ADDR + USB_MAX_EP0_SIZE) +#if defined(STM32C5xx) +/* + * The C5 USB DRD FS peripheral is used with bulk double buffering disabled. + * Keep each CDC endpoint in its own 64-byte PMA area; in particular, the + * interrupt IN endpoint must not overlap the bulk IN data buffer. + */ +#define PMA_CDC_OUT_ADDR PMA_CDC_OUT_BASE +#define PMA_CDC_IN_ADDR (PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE) +#define PMA_CDC_CMD_ADDR (PMA_CDC_IN_ADDR + USB_FS_MAX_PACKET_SIZE) +#else #define PMA_CDC_OUT_ADDR ((PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE) | \ (PMA_CDC_OUT_BASE << 16U)) #define PMA_CDC_IN_ADDR (PMA_CDC_OUT_BASE + USB_FS_MAX_PACKET_SIZE * 2) #define PMA_CDC_CMD_ADDR (PMA_CDC_IN_ADDR + CDC_CMD_PACKET_SIZE) +#endif #endif /* USBD_USE_CDC */ #ifdef USBD_USE_HID_COMPOSITE #define PMA_MOUSE_IN_ADDR (PMA_EP0_IN_ADDR + HID_MOUSE_EPIN_SIZE) @@ -86,4 +97,4 @@ extern const ep_desc_t ep_def[DEV_NUM_EP + 1]; #endif /* USBCON */ #endif /* __USBD_EP_CONF_H */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ \ No newline at end of file +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/USBDevice/src/cdc/cdc_queue.c b/libraries/USBDevice/src/cdc/cdc_queue.c index 2d2330c195..50d3031a5e 100644 --- a/libraries/USBDevice/src/cdc/cdc_queue.c +++ b/libraries/USBDevice/src/cdc/cdc_queue.c @@ -85,6 +85,11 @@ uint8_t *CDC_TransmitQueue_ReadBlock(CDC_TransmitQueue_TypeDef *queue, } else { *size = CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read; } + + /* Limit the queued transaction to one endpoint packet. */ + if (*size > CDC_QUEUE_MAX_PACKET_SIZE) { + *size = CDC_QUEUE_MAX_PACKET_SIZE; + } queue->reserved = *size; return &queue->buffer[queue->read]; } diff --git a/libraries/USBDevice/src/cdc/usbd_cdc.c b/libraries/USBDevice/src/cdc/usbd_cdc.c index d2e8cf7dfb..803476aca9 100644 --- a/libraries/USBDevice/src/cdc/usbd_cdc.c +++ b/libraries/USBDevice/src/cdc/usbd_cdc.c @@ -701,7 +701,11 @@ static uint8_t USBD_CDC_Setup(USBD_HandleTypeDef *pdev, static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_CDC_HandleTypeDef *hcdc; +#if defined(USE_HALV2_DRIVER) + hal_pcd_handle_t *hpcd = (hal_pcd_handle_t *)pdev->pData; +#else PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)pdev->pData; +#endif if (pdev->pClassDataCmsit[pdev->classId] == NULL) { return (uint8_t)USBD_FAIL; @@ -710,7 +714,13 @@ static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; if ((pdev->ep_in[epnum & 0xFU].total_length > 0U) && - ((pdev->ep_in[epnum & 0xFU].total_length % hpcd->IN_ep[epnum & 0xFU].maxpacket) == 0U)) { + ((pdev->ep_in[epnum & 0xFU].total_length % +#if defined(USE_HALV2_DRIVER) + hpcd->in_ep[epnum & 0xFU].max_packet +#else + hpcd->IN_ep[epnum & 0xFU].maxpacket +#endif + ) == 0U)) { /* Update the packet total length */ pdev->ep_in[epnum & 0xFU].total_length = 0U; diff --git a/libraries/USBDevice/src/cdc/usbd_cdc_if.c b/libraries/USBDevice/src/cdc/usbd_cdc_if.c index 922b7d57e3..4b67022be5 100644 --- a/libraries/USBDevice/src/cdc/usbd_cdc_if.c +++ b/libraries/USBDevice/src/cdc/usbd_cdc_if.c @@ -89,6 +89,12 @@ USBD_CDC_LineCodingTypeDef linecoding = { 0x08 /* nb. of bits 8*/ }; +/* Boards that need a CDC line-coding side effect can override this hook. */ +WEAK void CDC_LineCodingChanged(uint32_t bitrate) +{ + (void)bitrate; +} + /* Private functions ---------------------------------------------------------*/ /** @@ -175,6 +181,7 @@ static int8_t USBD_CDC_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length) linecoding.format = pbuf[4]; linecoding.paritytype = pbuf[5]; linecoding.datatype = pbuf[6]; + CDC_LineCodingChanged(linecoding.bitrate); break; case CDC_GET_LINE_CODING: @@ -406,4 +413,3 @@ uint8_t CDC_getDataBits(void) #endif /* USBD_USE_CDC */ #endif /* USBCON */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ - diff --git a/libraries/USBDevice/src/usbd_conf.c b/libraries/USBDevice/src/usbd_conf.c index 8b0d8184aa..85398b8bea 100644 --- a/libraries/USBDevice/src/usbd_conf.c +++ b/libraries/USBDevice/src/usbd_conf.c @@ -16,7 +16,7 @@ * ****************************************************************************** */ -#ifdef USBCON +#if defined(USBCON) && !defined(USE_HALV2_DRIVER) /* Includes ------------------------------------------------------------------*/ #include "usbd_core.h" #include "usbd_if.h" @@ -718,6 +718,5 @@ void USBD_LL_Delay(uint32_t Delay) HAL_Delay(Delay); } #endif /* HAL_PCD_MODULE_ENABLED */ -#endif /* USBCON */ +#endif /* USBCON && !USE_HALV2_DRIVER */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ - diff --git a/libraries/USBDevice/src/usbd_confv2.c b/libraries/USBDevice/src/usbd_confv2.c new file mode 100644 index 0000000000..3cb5dbeff5 --- /dev/null +++ b/libraries/USBDevice/src/usbd_confv2.c @@ -0,0 +1,261 @@ +/** + ****************************************************************************** + * @file usbd_confv2.c + * @brief HAL v2 USB device low-level adapter. + ****************************************************************************** + */ + +#if defined(USBCON) && defined(USE_HALV2_DRIVER) + +#if !defined(STM32C5xx) +#warning "USB device support is currently implemented only for STM32C5xx HAL v2." +#else + +#include "usbd_core.h" +#include "usbd_if.h" +#include "usbd_ep_conf.h" + +#ifndef USE_HAL_PCD_MODULE +#error "USE_HAL_PCD_MODULE is required" +#endif + +static hal_pcd_handle_t g_hpcd; +static USBD_HandleTypeDef *g_pdev; +static uint8_t g_stalled_in; +static uint8_t g_stalled_out; + +static void USBD_V2_ErrorHandler(void) +{ + Error_Handler(); +} + +static void USBD_V2_ConfigPinsAndIrq(void) +{ + /* The HAL v2 USB DRD FS PCD owns PA11/PA12 and configures these fixed USB + * pins during peripheral initialization. */ + + HAL_RCC_USB_EnableClock(); + HAL_CORTEX_NVIC_SetPriority(USB_IRQn, USBD_IRQ_PRIO, USBD_IRQ_SUBPRIO); + HAL_CORTEX_NVIC_EnableIRQ(USB_IRQn); +} + +void HAL_PCD_SetupStageCallback(hal_pcd_handle_t *hpcd) +{ + USBD_LL_SetupStage(g_pdev, (uint8_t *)hpcd->setup); +} + +void HAL_PCD_DataOutStageCallback(hal_pcd_handle_t *hpcd, uint8_t epnum) +{ + USBD_LL_DataOutStage(g_pdev, epnum, hpcd->out_ep[epnum].p_xfer_buffer); +} + +void HAL_PCD_DataInStageCallback(hal_pcd_handle_t *hpcd, uint8_t epnum) +{ + USBD_LL_DataInStage(g_pdev, epnum, hpcd->in_ep[epnum].p_xfer_buffer); +} + +void HAL_PCD_SofCallback(hal_pcd_handle_t *hpcd) +{ + (void)hpcd; + USBD_LL_SOF(g_pdev); +} + +void HAL_PCD_ResetCallback(hal_pcd_handle_t *hpcd) +{ + (void)hpcd; + USBD_LL_Reset(g_pdev); + USBD_LL_SetSpeed(g_pdev, USBD_SPEED_FULL); +} + +void HAL_PCD_SuspendCallback(hal_pcd_handle_t *hpcd) +{ + (void)hpcd; + USBD_LL_Suspend(g_pdev); +} + +void HAL_PCD_ResumeCallback(hal_pcd_handle_t *hpcd) +{ + (void)hpcd; + USBD_LL_Resume(g_pdev); +} + +void HAL_PCD_ISOOUTIncompleteCallback(hal_pcd_handle_t *hpcd, uint8_t epnum) +{ + (void)hpcd; + USBD_LL_IsoOUTIncomplete(g_pdev, epnum); +} + +void HAL_PCD_ISOINIncompleteCallback(hal_pcd_handle_t *hpcd, uint8_t epnum) +{ + (void)hpcd; + USBD_LL_IsoINIncomplete(g_pdev, epnum); +} + +void HAL_PCD_ConnectCallback(hal_pcd_handle_t *hpcd) +{ + (void)hpcd; + USBD_LL_DevConnected(g_pdev); +} + +void HAL_PCD_DisconnectCallback(hal_pcd_handle_t *hpcd) +{ + (void)hpcd; + USBD_LL_DevDisconnected(g_pdev); +} + +void USB_IRQHandler(void) +{ + HAL_PCD_IRQHandler(&g_hpcd); +} + +USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) +{ + hal_pcd_config_t config = { + .dma_enable = HAL_PCD_DMA_DISABLED, + .pcd_speed = HAL_PCD_SPEED_FS, + .phy_interface = HAL_PCD_PHY_EMBEDDED_FS, + .sof_enable = HAL_PCD_SOF_DISABLED, + .lpm_enable = HAL_PCD_LPM_DISABLED, + .battery_charging_enable = HAL_PCD_BCD_DISABLED, + .vbus_sensing_enable = HAL_PCD_VBUS_SENSE_DISABLED, + .bulk_doublebuffer_enable = HAL_PCD_BULK_DB_DISABLED, + }; + + USBD_V2_ConfigPinsAndIrq(); + + g_pdev = pdev; + g_stalled_in = 0U; + g_stalled_out = 0U; + pdev->pData = &g_hpcd; + + if (HAL_PCD_Init(&g_hpcd, HAL_PCD_DRD_FS) != HAL_OK) { + USBD_V2_ErrorHandler(); + } + if (HAL_PCD_SetConfig(&g_hpcd, &config) != HAL_OK) { + USBD_V2_ErrorHandler(); + } + + for (uint32_t i = 0U; i < (DEV_NUM_EP + 1U); i++) { + if (HAL_PCD_PMAConfig(&g_hpcd, ep_def[i].ep_adress, ep_def[i].ep_kind, + ep_def[i].ep_size) != HAL_OK) { + USBD_V2_ErrorHandler(); + } + } + + /* HAL v2 exposes the USB pull-up through the PCD device-connect API. Do + * the startup detach after the PCD has been initialized instead of reaching + * into a board-specific GPIO pin from the common re-enumeration helper. + * HAL_PCD_Start() performs the matching attach once USB is ready. */ + (void)HAL_PCD_DeviceDisconnect(&g_hpcd); + HAL_Delay(USBD_ENUM_DELAY); + + return USBD_OK; +} + +USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev) +{ + (void)pdev; + HAL_CORTEX_NVIC_DisableIRQ(USB_IRQn); + HAL_PCD_DeInit(&g_hpcd); + HAL_RCC_USB_DisableClock(); + g_pdev = NULL; + return USBD_OK; +} + +USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev) +{ + (void)pdev; + return (HAL_PCD_Start(&g_hpcd) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev) +{ + (void)pdev; + return (HAL_PCD_Stop(&g_hpcd) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, + uint8_t ep_type, uint16_t ep_mps) +{ + (void)pdev; + return (HAL_PCD_OpenEndpoint(&g_hpcd, ep_addr, ep_mps, + (hal_pcd_ep_type_t)ep_type) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + (void)pdev; + return (HAL_PCD_CloseEndpoint(&g_hpcd, ep_addr) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + (void)pdev; + return (HAL_PCD_FlushEndpoint(&g_hpcd, ep_addr) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + uint8_t mask = (uint8_t)(1U << (ep_addr & 0x0FU)); + (void)pdev; + if ((ep_addr & 0x80U) != 0U) { + g_stalled_in |= mask; + } else { + g_stalled_out |= mask; + } + return (HAL_PCD_SetEndpointStall(&g_hpcd, ep_addr) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + uint8_t mask = (uint8_t)(1U << (ep_addr & 0x0FU)); + (void)pdev; + if ((ep_addr & 0x80U) != 0U) { + g_stalled_in &= (uint8_t)~mask; + } else { + g_stalled_out &= (uint8_t)~mask; + } + return (HAL_PCD_ClearEndpointStall(&g_hpcd, ep_addr) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + uint8_t mask = (uint8_t)(1U << (ep_addr & 0x0FU)); + (void)pdev; + return ((ep_addr & 0x80U) != 0U) ? ((g_stalled_in & mask) != 0U) : + ((g_stalled_out & mask) != 0U); +} + +USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr) +{ + (void)pdev; + return (HAL_PCD_SetDeviceAddress(&g_hpcd, dev_addr) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, + uint8_t *pbuf, uint32_t size) +{ + (void)pdev; + return (HAL_PCD_SetEndpointTransmit(&g_hpcd, ep_addr, pbuf, size) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, + uint8_t *pbuf, uint32_t size) +{ + (void)pdev; + return (HAL_PCD_SetEndpointReceive(&g_hpcd, ep_addr, pbuf, size) == HAL_OK) ? USBD_OK : USBD_FAIL; +} + +uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr) +{ + (void)pdev; + return HAL_PCD_EP_GetRxCount(&g_hpcd, ep_addr); +} + +void USBD_LL_Delay(uint32_t delay) +{ + HAL_Delay(delay); +} + +#endif /* STM32C5xx */ +#endif /* USBCON && USE_HALV2_DRIVER */ diff --git a/libraries/USBDevice/src/usbd_ep_conf.c b/libraries/USBDevice/src/usbd_ep_conf.c index d872acca5f..8759e49fda 100644 --- a/libraries/USBDevice/src/usbd_ep_conf.c +++ b/libraries/USBDevice/src/usbd_ep_conf.c @@ -37,7 +37,7 @@ const ep_desc_t ep_def[] = { #else {0x00, PMA_EP0_OUT_ADDR, PCD_SNG_BUF}, {0x80, PMA_EP0_IN_ADDR, PCD_SNG_BUF}, -#ifndef USBD_CDC_USE_SINGLE_BUFFER +#if !defined(STM32C5xx) && !defined(USBD_CDC_USE_SINGLE_BUFFER) {CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_DBL_BUF}, #else {CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_SNG_BUF}, @@ -72,4 +72,3 @@ const ep_desc_t ep_def[] = { #endif /* HAL_PCD_MODULE_ENABLED && USBCON */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ -