#include "hsusb_v30x.h" #include "ch32fun.h" #include #define UEP_CTRL_H(n) (((uint16_t *)&USBHSD->UEP0_TX_CTRL)[n * 2]) struct _USBState HSUSBCTX; // based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM // Mask for the combined USBHSD->INT_FG + USBHSD->INT_ST #define CRB_U_IS_NAK (1 << 7) #define CTOG_MATCH_SYNC (1 << 6) #define CRB_UIF_SETUP_ACT (1 << 5) // CRB_U_SIE_FREE on USBFS #define CRB_UIF_FIFO_OV (1 << 4) #define CRB_UIF_HST_SOF (1 << 3) #define CRB_UIF_SUSPEND (1 << 2) #define CRB_UIF_TRANSFER (1 << 1) #define CRB_UIF_BUS_RST (1 << 0) #define CSETUP_ACT (1 << 15) #define CRB_UIS_TOG_OK (1 << 14) #define CMASK_UIS_TOKEN (3 << 12) #define CMASK_UIS_ENDP (0xf << 8) #define CUIS_TOKEN_OUT 0x0 #define CUIS_TOKEN_SOF 0x1 #define CUIS_TOKEN_IN 0x2 #define CUIS_TOKEN_SETUP 0x3 #if 0 static inline void DMA7FastCopy( uint8_t * dest, const uint8_t * src, int len ) { while( DMA1_Channel7->CNTR ); DMA1_Channel7->CFGR = 0; DMA1_Channel7->MADDR = (uintptr_t)src; DMA1_Channel7->PADDR = (uintptr_t)dest; DMA1_Channel7->CNTR = (len+3)/4; DMA1_Channel7->CFGR = DMA_M2M_Enable | DMA_DIR_PeripheralDST | DMA_Priority_Low | DMA_MemoryDataSize_Word | DMA_PeripheralDataSize_Word | DMA_MemoryInc_Enable | DMA_PeripheralInc_Enable | DMA_Mode_Normal | DMA_CFGR1_EN; #if !(FUSB_CURSED_TURBO_DMA == 1) // Somehow, it seems to work (unsafely) without this. // Really, though, it's probably fine. while( DMA1_Channel7->CNTR ); #endif } static inline void DMA7FastCopyComplete() { while( DMA1_Channel7->CNTR ); } #endif void USBHS_InternalFinishSetup(); // void USBHSWakeUp_IRQHandler(void) __attribute((interrupt)); // void USBHSWakeUp_IRQHandler(void) //{ // printf( "USBHSWakeUp MSTATUS:%08x MTVAL:%08x MCAUSE:%08x MEPC:%08x\n", (int)__get_MSTATUS(), (int)__get_MTVAL(), (int)__get_MCAUSE(), (int)__get_MEPC() ); // } extern uint8_t scratchpad[]; void USBHS_IRQHandler(void) __attribute((interrupt)); void USBHS_IRQHandler(void) { // Based on https://github.com/openwch/ch32v307/blob/main/EVT/EXAM/USB/USBHS/DEVICE/CompositeKM/User/ch32v30x_usbhs_device.c // Combined FG + ST flag uint16_t intfgst = *(uint16_t *)(&USBHSD->INT_FG); int len = 0; struct _USBState *ctx = &HSUSBCTX; uint8_t *ctrl0buff = CTRL0BUFF; if (intfgst & (CRB_UIF_SETUP_ACT)) { // On the Chapter 22 USB, SETUP Requests are handled here instead of in UIF_TRANSFER, with TOKEN_SETUP. USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK; /* Store All Setup Values */ int USBHS_SetupReqType = HSUSBCTX.USBHS_SetupReqType = pUSBHS_SetupReqPak->bmRequestType; int USBHS_SetupReqCode = HSUSBCTX.USBHS_SetupReqCode = pUSBHS_SetupReqPak->bRequest; int USBHS_SetupReqLen = HSUSBCTX.USBHS_SetupReqLen = pUSBHS_SetupReqPak->wLength; int USBHS_SetupReqIndex = pUSBHS_SetupReqPak->wIndex; int USBHS_IndexValue = HSUSBCTX.USBHS_IndexValue = (pUSBHS_SetupReqPak->wIndex << 16) | pUSBHS_SetupReqPak->wValue; len = 0; // printf( "Setup: %d %d %d %d %d\n", USBHS_SetupReqType, USBHS_SetupReqCode, USBHS_SetupReqLen, // USBHS_SetupReqIndex, USBHS_IndexValue ); if ((USBHS_SetupReqType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD) { #if HUSB_HID_INTERFACES > 0 if ((USBHS_SetupReqType & USB_REQ_TYP_MASK) == USB_REQ_TYP_CLASS) { /* Class Request */ // printf( "REQ: %d [%02x %02x %04x %04x]\n", USBHS_SetupReqCode, pUSBHS_SetupReqPak->bmRequestType, pUSBHS_SetupReqPak->bRequest, pUSBHS_SetupReqPak->wValue, pUSBHS_SetupReqPak->wLength ); switch (USBHS_SetupReqCode) { case HID_SET_REPORT: #if HUSB_HID_USER_REPORTS len = HandleHidUserSetReportSetup(ctx, pUSBHS_SetupReqPak); if (len < 0) goto sendstall; ctx->USBHS_SetupReqLen = len; USBHSD->UEP0_TX_LEN = 0; USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1; goto replycomplete; case HID_GET_REPORT: len = HandleHidUserGetReportSetup(ctx, pUSBHS_SetupReqPak); if (len < 0) goto sendstall; ctx->USBHS_SetupReqLen = len; len = len >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : len; if (!ctx->pCtrlPayloadPtr) { len = HandleHidUserReportDataIn(ctx, ctrl0buff, len); } else { // DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); memcpy(ctrl0buff, ctx->pCtrlPayloadPtr, len); ctx->pCtrlPayloadPtr += len; } USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; ctx->USBHS_SetupReqLen -= len; goto replycomplete; #endif break; case HID_SET_IDLE: if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) HSUSBCTX.USBHS_HidIdle[USBHS_SetupReqIndex] = (uint8_t)(USBHS_IndexValue >> 8); break; case HID_SET_PROTOCOL: if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) HSUSBCTX.USBHS_HidProtocol[USBHS_SetupReqIndex] = (uint8_t)USBHS_IndexValue; break; case HID_GET_IDLE: if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) { ctrl0buff[0] = HSUSBCTX.USBHS_HidIdle[USBHS_SetupReqIndex]; len = 1; } break; case HID_GET_PROTOCOL: if (USBHS_SetupReqIndex < HUSB_HID_INTERFACES) { ctrl0buff[0] = HSUSBCTX.USBHS_HidProtocol[USBHS_SetupReqIndex]; len = 1; } break; default: goto sendstall; break; } } #else ; #endif } else { /* usb standard request processing */ switch (USBHS_SetupReqCode) { /* get device/configuration/string/report/... descriptors */ case USB_GET_DESCRIPTOR: { const struct descriptor_list_struct *e = descriptor_list; const struct descriptor_list_struct *e_end = e + DESCRIPTOR_LIST_ENTRIES; for (; e != e_end; e++) { if (e->lIndexValue == USBHS_IndexValue) { ctx->pCtrlPayloadPtr = (uint8_t *)e->addr; len = e->length; break; } } if (e == e_end) { goto sendstall; } /* Copy Descriptors to Endp0 DMA buffer */ int totalLen = USBHS_SetupReqLen; if (totalLen > len) { totalLen = len; } len = (totalLen >= DEF_USBD_UEP0_SIZE) ? DEF_USBD_UEP0_SIZE : totalLen; // DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); //memcpy( CTRL0BUFF, ctx->pCtrlPayloadPtr, len ); memcpy(ctrl0buff, ctx->pCtrlPayloadPtr, len); ctx->USBHS_SetupReqLen = totalLen - len; ctx->pCtrlPayloadPtr += len; USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; goto replycomplete; } /* Set usb address */ case USB_SET_ADDRESS: ctx->USBHS_DevAddr = (uint16_t)(ctx->USBHS_IndexValue & 0xFF); break; /* Get usb configuration now set */ case USB_GET_CONFIGURATION: ctrl0buff[0] = ctx->USBHS_DevConfig; if (ctx->USBHS_SetupReqLen > 1) ctx->USBHS_SetupReqLen = 1; break; /* Set usb configuration to use */ case USB_SET_CONFIGURATION: ctx->USBHS_DevConfig = (uint8_t)(ctx->USBHS_IndexValue & 0xFF); ctx->USBHS_DevEnumStatus = 0x01; break; /* Clear or disable one usb feature */ case USB_CLEAR_FEATURE: #if HUSB_SUPPORTS_SLEEP if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { /* clear one device feature */ if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_REMOTE_WAKEUP) { /* clear usb sleep status, device not prepare to sleep */ ctx->USBHS_DevSleepStatus &= ~0x01; } else { goto sendstall; } } else #endif if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_ENDP_HALT) { /* Clear End-point Feature */ int ep = USBHS_SetupReqIndex & 0xf; if ((USBHS_SetupReqIndex & DEF_UEP_IN) && ep < HUSB_CONFIG_EPS) { UEP_CTRL_H(ep) = USBHS_UEP_T_TOG_DATA0 | USBHS_UEP_T_RES_NAK; } else { goto sendstall; } } else { goto sendstall; } } else { goto sendstall; } break; /* set or enable one usb feature */ case USB_SET_FEATURE: if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { #if HUSB_SUPPORTS_SLEEP /* Set Device Feature */ if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_REMOTE_WAKEUP) { /* Set Wake-up flag, device prepare to sleep */ USBHS_DevSleepStatus |= 0x01; } else #endif { goto sendstall; } } else if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { /* Set Endpoint Feature */ if ((uint8_t)(USBHS_IndexValue & 0xFF) == USB_REQ_FEAT_ENDP_HALT) { int ep = USBHS_SetupReqIndex & 0xf; if ((USBHS_SetupReqIndex & DEF_UEP_IN) && ep < HUSB_CONFIG_EPS) UEP_CTRL_H(ep) = (UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_STALL; } else goto sendstall; } else goto sendstall; break; /* This request allows the host to select another setting for the specified interface */ case USB_GET_INTERFACE: ctrl0buff[0] = 0x00; if (USBHS_SetupReqLen > 1) USBHS_SetupReqLen = 1; break; case USB_SET_INTERFACE: break; /* host get status of specified device/interface/end-points */ case USB_GET_STATUS: ctrl0buff[0] = 0x00; ctrl0buff[1] = 0x00; if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { #if FUSB_SUPPORTS_SLEEP ctrl0buff[0] = (ctx->USBHS_DevSleepStatus & 0x01) << 1; #else ctrl0buff[0] = 0x00; #endif } else if ((USBHS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { int ep = USBHS_SetupReqIndex & 0xf; if ((USBHS_SetupReqIndex & DEF_UEP_IN) && ep < HUSB_CONFIG_EPS) ctrl0buff[0] = (UEP_CTRL_H(ep) & USBHS_UEP_T_RES_MASK) == USBHS_UEP_T_RES_STALL; else goto sendstall; } else goto sendstall; if (USBHS_SetupReqLen > 2) USBHS_SetupReqLen = 2; break; default: goto sendstall; break; } } { /* end-point 0 data Tx/Rx */ if (USBHS_SetupReqType & DEF_UEP_IN) { len = (USBHS_SetupReqLen > DEF_USBD_UEP0_SIZE) ? DEF_USBD_UEP0_SIZE : USBHS_SetupReqLen; USBHS_SetupReqLen -= len; USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; } else { if (USBHS_SetupReqLen == 0) { USBHSD->UEP0_TX_LEN = 0; USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_ACK; } else { USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK; } } } goto replycomplete; // This might look a little weird, for error handling but it saves a nontrivial amount of storage, and simplifies // control flow to hard-abort here. sendstall: // if one request not support, return stall. Stall means permanent error. USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_TOG_DATA1 | USBHS_UEP_T_RES_STALL; USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_STALL; replycomplete:; } if (intfgst & (CRB_UIF_TRANSFER)) { int token = (intfgst & CMASK_UIS_TOKEN) >> 12; int ep = (intfgst & CMASK_UIS_ENDP) >> 8; switch (token) { case CUIS_TOKEN_IN: if (ep) { if (ep < HUSB_CONFIG_EPS) { UEP_CTRL_H(ep) = (UEP_CTRL_H(ep) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK; UEP_CTRL_H(ep) ^= USBHS_UEP_T_TOG_DATA1; ctx->USBHS_Endp_Busy[ep] = 0; // Don't set EP in here. Wait for out. // Optimization: Could we set EP here? } } else { /* end-point 0 data in interrupt */ if (ctx->USBHS_SetupReqLen == 0) { USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_TOG_DATA1 | USBHS_UEP_R_RES_ACK; } if (ctx->pCtrlPayloadPtr) { // Shortcut mechanism, for descriptors or if the user wants it. len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen; // DMA7FastCopy( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA memcpy(ctrl0buff, ctx->pCtrlPayloadPtr, len); ctx->USBHS_SetupReqLen -= len; if (ctx->USBHS_SetupReqLen > 0) ctx->pCtrlPayloadPtr += len; else ctx->pCtrlPayloadPtr = 0; USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1; } else if ((ctx->USBHS_SetupReqType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD) { #if HUSB_HID_USER_REPORTS len = ctx->USBHS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBHS_SetupReqLen; if (len && HSUSBCTX.USBHS_SetupReqCode == HID_GET_REPORT) { len = HandleHidUserReportDataIn(ctx, ctrl0buff, len); USBHSD->UEP0_TX_LEN = len; USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1; ctx->USBHS_SetupReqLen -= len; ctx->pCtrlPayloadPtr += len; } #endif } else { switch (HSUSBCTX.USBHS_SetupReqCode) { case USB_GET_DESCRIPTOR: break; case USB_SET_ADDRESS: USBHSD->DEV_AD = ctx->USBHS_DevAddr; break; default: break; } } } /* data-out stage processing */ case CUIS_TOKEN_OUT: switch (ep) { /* end-point 0 data out interrupt */ case DEF_UEP0: { // XXX WARNINGS: // 1. intfgst & CRB_UIS_TOG_OK is not set for non-odd transactions, i.e. first, third, etc, are all fine. // 2. HandleHidUserReportOutComplete doesn't seem to work. // if( intfgst & CRB_UIS_TOG_OK ) #if HUSB_HID_USER_REPORTS int len = USBHSD->RX_LEN; uint8_t *cptr = ctx->pCtrlPayloadPtr; if (!cptr) { HandleHidUserReportDataOut(ctx, ctrl0buff, len); } else { int remain = ctx->USBHS_SetupReqLen - len; if (remain < 0) { len += remain; remain = 0; } // DMA7FastCopy( cptr, ctrl0buff, len ); memcpy(cptr, ctrl0buff, len); ctx->USBHS_SetupReqLen = remain; if (remain > 0) ctx->pCtrlPayloadPtr = cptr + len; else ctx->pCtrlPayloadPtr = 0; } #endif if (ctx->USBHS_SetupReqLen == 0) { #if HUSB_HID_USER_REPORTS // DMA7FastCopyComplete(); HandleHidUserReportOutComplete(ctx); #endif } // See above comment // //USBHSD->UEP0_RX_CTRL ^= USBFS_UEP_R_TOG; break; } default: // Any other out. (also happens with In) HSUSBCTX.USBHS_Endp_Busy[ep] = 0x02; USBHSD_UEP_RXCTRL(ep) = ((USBHSD_UEP_RXCTRL(ep)) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK; #if HUSB_BULK_USER_REPORTS HandleGotEPComplete(ctx, ep); #endif break; } break; case CUIS_TOKEN_SETUP: // Not actually used on this chip (It's done as a separate flag) case CUIS_TOKEN_SOF: // Sof pack processing break; default: break; } } if (intfgst & USBHS_UIF_BUS_RST) { /* usb reset interrupt processing */ ctx->USBHS_DevConfig = 0; ctx->USBHS_DevAddr = 0; ctx->USBHS_DevSleepStatus = 0; ctx->USBHS_DevEnumStatus = 0; USBHSD->DEV_AD = 0; USBHS_InternalFinishSetup(); } if (intfgst & USBHS_UIF_SUSPEND) { USBHSD->INT_FG = USBHS_UIF_SUSPEND; Delay_Us(10); // USB suspend interrupt processing if (USBHSD->MIS_ST & USBHS_UMS_SUSPEND) { HSUSBCTX.USBHS_DevSleepStatus |= 0x02; if (HSUSBCTX.USBHS_DevSleepStatus == 0x03) { // TODO: Handle usb sleep here } } else { HSUSBCTX.USBHS_DevSleepStatus &= ~0x02; } } USBHSD->INT_FG = intfgst; } void USBHS_InternalFinishSetup() { // To reconfigure your endpoints for TX/RX do it here. #if HUSB_CONFIG_EPS > 5 USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN | USBHS_UEP5_R_EN; #elif HUSB_CONFIG_EPS > 4 USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN | USBHS_UEP3_T_EN | USBHS_UEP4_T_EN; #elif HUSB_CONFIG_EPS > 3 USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN | USBHS_UEP3_T_EN; #elif HUSB_CONFIG_EPS > 2 USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN | USBHS_UEP2_T_EN; #elif HUSB_CONFIG_EPS > 1 USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN | USBHS_UEP1_T_EN; #else USBHSD->ENDP_CONFIG = USBHS_UEP0_T_EN | USBHS_UEP0_R_EN; #endif // This is really cursed. Somehow it doesn't explode. // But, normally the USB wants a separate buffer here. #if HUSB_CONFIG_EPS > 5 // Feel free to override any of these. USBHSD->UEP5_MAX_LEN = 64; USBHSD->UEP5_RX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[5]; USBHSD->UEP5_RX_CTRL = USBHS_UEP_R_RES_ACK | USBHS_UEP_R_TOG_AUTO; // For bulk-out, I think you need to do this. #endif #if HUSB_CONFIG_EPS > 4 USBHSD->UEP4_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64? USBHSD->UEP4_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[4]; #endif #if HUSB_CONFIG_EPS > 3 USBHSD->UEP3_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64? USBHSD->UEP3_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[3]; #endif #if HUSB_CONFIG_EPS > 2 USBHSD->UEP2_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64? USBHSD->UEP2_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[2]; #endif #if HUSB_CONFIG_EPS > 1 USBHSD->UEP1_MAX_LEN = 64; // TODO: change to dynamic size, as USB HS supports more than 64? USBHSD->UEP1_TX_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[1]; #endif #if HUSB_CONFIG_EPS > 0 USBHSD->UEP0_MAX_LEN = 64; USBHSD->UEP0_DMA = (uintptr_t)HSUSBCTX.ENDPOINTS[0]; #else #error You must have at least EP0! #endif UEP_CTRL_H(0) = USBHS_UEP_R_RES_ACK | USBHS_UEP_T_RES_NAK; int i; for (i = 1; i < HUSB_CONFIG_EPS; i++) UEP_CTRL_H(i) = USBFS_UEP_T_RES_NAK; for (uint8_t i = 0; i < sizeof(HSUSBCTX.USBHS_Endp_Busy) / sizeof(HSUSBCTX.USBHS_Endp_Busy[0]); i++) { HSUSBCTX.USBHS_Endp_Busy[i] = 0; } } int HSUSBSetup() { // Set USB clock source to USBPHY RCC->CFGR2 &= ~(1 << 31); RCC->CFGR2 |= RCC_USBCLK48MCLKSource_USBPHY << 31; // Set PLL clock source to HSE RCC->CFGR2 &= ~(1 << 27); RCC->CFGR2 |= RCC_HSBHSPLLCLKSource_HSE << 27; // Configure PLL for USB RCC->CFGR2 &= ~(7 << 24); RCC->CFGR2 |= RCC_USBPLL_Div2 << 24; // Configure reference clock RCC->CFGR2 &= ~(3 << 28); RCC->CFGR2 |= RCC_USBHSPLLCKREFCLK_4M << 28; // Enable USB high-speed peripheral RCC->CFGR2 |= (1 << 30); RCC->AHBPCENR |= RCC_AHBPeriph_USBHS | RCC_AHBPeriph_DMA1; // Initialize USB module USBHSD->CONTROL = USBHS_UC_CLR_ALL | USBHS_UC_RESET_SIE; Delay_Us(10); USBHSD->CONTROL = 0; // Initialize USB device config USBHSD->HOST_CTRL = USBHS_UH_PHY_SUSPENDM; USBHSD->CONTROL = USBHS_UC_DMA_EN | USBHS_UC_INT_BUSY | USBHS_UC_SPEED_HIGH; USBHSD->INT_EN = USBHS_UIE_SETUP_ACT | USBHS_UIE_TRANSFER | USBHS_UIE_DETECT | USBHS_UIE_SUSPEND; USBHS_InternalFinishSetup(); USBHSD->CONTROL |= USBHS_UC_DEV_PU_EN; NVIC_EnableIRQ(USBHS_IRQn); // Go on-bus. return 0; }