cmake_cpputest_template/inc/extralibs/hsusb_v30x.c

651 lines
24 KiB
C

#include "hsusb_v30x.h"
#include "ch32fun.h"
#include <string.h>
#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;
}