Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBDEVICE by
USBDevice/TARGET_Silicon_Labs/src/em_usbhal.c
- Committer:
- qroche
- Date:
- 2017-09-03
- Branch:
- master
- Revision:
- 5:3329e56e51d7
- Parent:
- 1:2a3ae13b45ef
File content as of revision 5:3329e56e51d7:
/**************************************************************************//** * @file em_usbhal.c * @brief USB protocol stack library, low level USB peripheral access. * @version 3.20.14 ****************************************************************************** * @section License * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #include "em_device.h" #if defined( USB_PRESENT ) && ( USB_COUNT == 1 ) #include "em_usb.h" #if defined( USB_DEVICE ) || defined( USB_HOST ) #include "em_usbtypes.h" #include "em_usbhal.h" #if defined( USB_DEVICE ) #include "em_usbd.h" #endif #if defined( USB_HOST ) #include "em_usbh.h" #endif #include "em_cmu.h" #include "em_gpio.h" /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ #define EPABORT_BREAK_LOOP_COUNT 15000 /* Approx. 100 ms */ /* NOTE: The sequence of error message strings must agree with the */ /* definition of USB_Status_TypeDef enum. */ static const char * const errMsg[] = { [ USB_STATUS_OK ] = "No errors", [ -USB_STATUS_REQ_ERR ] = "Setup request error", [ -USB_STATUS_EP_BUSY ] = "Endpoint is busy", [ -USB_STATUS_REQ_UNHANDLED ] = "Setup request not handled", [ -USB_STATUS_ILLEGAL ] = "Illegal operation attempted", [ -USB_STATUS_EP_STALLED ] = "Endpoint is stalled", [ -USB_STATUS_EP_ABORTED ] = "Transfer aborted", [ -USB_STATUS_EP_ERROR ] = "Transfer error", [ -USB_STATUS_EP_NAK ] = "Endpoint NAK", [ -USB_STATUS_DEVICE_UNCONFIGURED ] = "Device is not configured", [ -USB_STATUS_DEVICE_SUSPENDED ] = "Device is suspended", [ -USB_STATUS_DEVICE_RESET ] = "Device has been reset", [ -USB_STATUS_TIMEOUT ] = "Transfer timeout", [ -USB_STATUS_DEVICE_REMOVED ] = "Device removed", [ -USB_STATUS_HC_BUSY ] = "Host channel is busy", [ -USB_STATUS_DEVICE_MALFUNCTION ] = "Device malfunction", [ -USB_STATUS_PORT_OVERCURRENT ] = "VBUS overcurrent", }; /** @endcond */ /***************************************************************************//** * @brief * Return an error message string for a given error code. * * @param[in] error * Error code, see \ref USB_Status_TypeDef. * * @return * Error message string pointer. ******************************************************************************/ char *USB_GetErrorMsgString( int error ) { if ( error >= 0 ) return (char*)errMsg[ 0 ]; return (char*)errMsg[ -error ]; } #if defined( USB_USE_PRINTF ) /***************************************************************************//** * @brief * Format and print a text string given an error code, prepends an optional user * supplied leader string. * * @param[in] pre * Optional leader string to prepend to error message string. * * @param[in] error * Error code, see \ref USB_Status_TypeDef. ******************************************************************************/ void USB_PrintErrorMsgString( char *pre, int error ) { if ( pre ) { USB_PRINTF( "%s", pre ); } if ( error > USB_STATUS_OK ) { USB_PRINTF( "%d", error ); } else { USB_PRINTF( "%s", USB_GetErrorMsgString( error ) ); } } #endif /* defined( USB_USE_PRINTF ) */ /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ #if defined( DEBUG_EFM_USER ) static void PrintI( int i ) { #if !defined ( USER_PUTCHAR ) (void)i; #else if ( i >= 10 ) { PrintI( i / 10 ); } DEBUG_USB_API_PUTCHAR( ( i % 10 ) + '0' ); #endif } void assertEFM( const char *file, int line ) { #if !defined ( USER_PUTCHAR ) (void)file; #endif DEBUG_USB_API_PUTS( "\nASSERT " ); DEBUG_USB_API_PUTS( file ); DEBUG_USB_API_PUTCHAR( ' ' ); PrintI( line ); for(;;){} } #endif /* defined( DEBUG_EFM_USER ) */ #if defined ( USER_PUTCHAR ) void USB_Puts( const char *p ) { while( *p ) USB_PUTCHAR( *p++ ); } #endif /* defined ( USER_PUTCHAR ) */ void USBHAL_CoreReset( void ) { USB->PCGCCTL &= ~USB_PCGCCTL_STOPPCLK; USB->PCGCCTL &= ~(USB_PCGCCTL_PWRCLMP | USB_PCGCCTL_RSTPDWNMODULE); /* Core Soft Reset */ USB->GRSTCTL |= USB_GRSTCTL_CSFTRST; while ( USB->GRSTCTL & USB_GRSTCTL_CSFTRST ) {} USBTIMER_DelayUs( 1 ); /* Wait for AHB master IDLE state. */ while ( !( USB->GRSTCTL & USB_GRSTCTL_AHBIDLE ) ) {} } #ifdef USB_DEVICE void USBDHAL_Connect( void ) { USB->DCTL &= ~( DCTL_WO_BITMASK | USB_DCTL_SFTDISCON ); } USB_Status_TypeDef USBDHAL_CoreInit( uint32_t totalRxFifoSize, uint32_t totalTxFifoSize ) { uint8_t i, j; uint16_t start, depth; USBD_Ep_TypeDef *ep; #if !defined( USB_VBUS_SWITCH_NOT_PRESENT ) CMU_ClockEnable( cmuClock_GPIO, true ); GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */ USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Enable PHY pins. */ #else USB->ROUTE = USB_ROUTE_PHYPEN; /* Enable PHY pins. */ #endif USBHAL_CoreReset(); /* Reset USB core */ #if defined( USB_GUSBCFG_FORCEHSTMODE ) /* Force Device Mode */ USB->GUSBCFG = ( USB->GUSBCFG & ~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEHSTMODE ) ) | USB_GUSBCFG_FORCEDEVMODE; #endif INT_Enable(); USBTIMER_DelayMs( 50 ); INT_Disable(); /* Set device speed */ USB->DCFG = ( USB->DCFG & ~_USB_DCFG_DEVSPD_MASK ) | 3; /* Full speed PHY */ /* Stall on non-zero len status OUT packets (ctrl transfers). */ USB->DCFG |= USB_DCFG_NZSTSOUTHSHK; /* Set periodic frame interval to 80% */ USB->DCFG &= ~_USB_DCFG_PERFRINT_MASK; USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) | USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR; /* Ignore frame numbers on ISO transfers. */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_IGNRFRMNUM; /* Set Rx FIFO size */ start = EFM32_MAX( totalRxFifoSize, MIN_EP_FIFO_SIZE_INWORDS ); USB->GRXFSIZ = ( start << _USB_GRXFSIZ_RXFDEP_SHIFT ) & _USB_GRXFSIZ_RXFDEP_MASK; /* Set Tx EP0 FIFO size */ depth = EFM32_MAX( dev->ep[ 0 ].fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); USB->GNPTXFSIZ = ( ( depth << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) & _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) | ( ( start << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) & _USB_GNPTXFSIZ_NPTXFSTADDR_MASK ); /* Set Tx EP FIFO sizes for all IN ep's */ for ( j = 1; j <= MAX_NUM_TX_FIFOS; j++ ) { for ( i = 1; i <= MAX_NUM_IN_EPS; i++ ) { ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | i ); if ( ep ) /* Is EP in use ? */ { if ( ep->txFifoNum == j ) /* Is it correct FIFO number ? */ { start += depth; depth = EFM32_MAX( ep->fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); USB_DIEPTXFS[ ep->txFifoNum - 1 ] = ( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) | ( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK ); } } } } if ( totalRxFifoSize + totalTxFifoSize > MAX_DEVICE_FIFO_SIZE_INWORDS ) return USB_STATUS_ILLEGAL; if ( start > MAX_DEVICE_FIFO_SIZE_INWORDS ) return USB_STATUS_ILLEGAL; /* Flush the FIFO's */ USBHAL_FlushTxFifo( 0x10 ); /* All Tx FIFO's */ USBHAL_FlushRxFifo(); /* The Rx FIFO */ /* Disable all device interrupts */ USB->DIEPMSK = 0; USB->DOEPMSK = 0; USB->DAINTMSK = 0; USB->DIEPEMPMSK = 0; /* Disable all EP's, clear all EP ints. */ for ( i = 0; i <= MAX_NUM_IN_EPS; i++ ) { USB_DINEPS[ i ].CTL = 0; USB_DINEPS[ i ].TSIZ = 0; USB_DINEPS[ i ].INT = 0xFFFFFFFF; } for ( i = 0; i <= MAX_NUM_OUT_EPS; i++ ) { USB_DOUTEPS[ i ].CTL = 0; USB_DOUTEPS[ i ].TSIZ = 0; USB_DOUTEPS[ i ].INT = 0xFFFFFFFF; } #if ( USB_DCTL_SFTDISCON_DEFAULT != 0 ) USBD_Connect(); #endif /* Enable VREGO sense. */ USB->CTRL |= USB_CTRL_VREGOSEN; USB->IFC = USB_IFC_VREGOSH | USB_IFC_VREGOSL; USB->IEN = USB_IFC_VREGOSH | USB_IFC_VREGOSL; /* Force a VREGO interrupt. */ if ( USB->STATUS & USB_STATUS_VREGOS) USB->IFS = USB_IFS_VREGOSH; else USB->IFS = USB_IFS_VREGOSL; return USB_STATUS_OK; } USB_Status_TypeDef USBDHAL_ReconfigureFifos( uint32_t totalRxFifoSize, uint32_t totalTxFifoSize ) { uint8_t i, j; uint16_t start, depth; USBD_Ep_TypeDef *ep; /* Set Rx FIFO size */ start = EFM32_MAX( totalRxFifoSize, MIN_EP_FIFO_SIZE_INWORDS ); USB->GRXFSIZ = ( start << _USB_GRXFSIZ_RXFDEP_SHIFT ) & _USB_GRXFSIZ_RXFDEP_MASK; /* Set Tx EP0 FIFO size */ depth = EFM32_MAX( dev->ep[ 0 ].fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); USB->GNPTXFSIZ = ( ( depth << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) & _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) | ( ( start << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) & _USB_GNPTXFSIZ_NPTXFSTADDR_MASK ); /* Set Tx EP FIFO sizes for all IN ep's */ for ( j = 1; j <= MAX_NUM_TX_FIFOS; j++ ) { for ( i = 1; i <= MAX_NUM_IN_EPS; i++ ) { ep = USBD_GetEpFromAddr( USB_SETUP_DIR_MASK | i ); if ( ep ) /* Is EP in use ? */ { if ( ep->txFifoNum == j ) /* Is it correct FIFO number ? */ { start += depth; depth = EFM32_MAX( ep->fifoSize, MIN_EP_FIFO_SIZE_INWORDS ); USB_DIEPTXFS[ ep->txFifoNum - 1 ] = ( depth << _USB_DIEPTXF1_INEPNTXFDEP_SHIFT ) | ( start & _USB_DIEPTXF1_INEPNTXFSTADDR_MASK ); } } } } if ( totalRxFifoSize + totalTxFifoSize > MAX_DEVICE_FIFO_SIZE_INWORDS ) return USB_STATUS_ILLEGAL; if ( start > MAX_DEVICE_FIFO_SIZE_INWORDS ) return USB_STATUS_ILLEGAL; /* Flush the FIFO's */ USBHAL_FlushTxFifo( 0x10 ); /* All Tx FIFO's */ USBHAL_FlushRxFifo(); /* The Rx FIFO */ return USB_STATUS_OK; } void USBDHAL_Disconnect( void ) { USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SFTDISCON; } void USBDHAL_AbortEpIn( USBD_Ep_TypeDef *ep ) { /* Clear epdis & inepnakeff INT's */ USB_DINEPS[ ep->num ].INT |= USB_DIEP_INT_EPDISBLD | USB_DIEP_INT_INEPNAKEFF; /* Enable epdis & inepnakeff INT's */ USB->DIEPMSK |= USB_DIEPMSK_EPDISBLDMSK | USB_DIEPMSK_INEPNAKEFFMSK; USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK ) | USB_DIEP_CTL_SNAK; /* Wait for inepnakeff INT */ while ( !( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_INEPNAKEFF ) ) {} USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_INEPNAKEFF; USB->DIEPMSK &= ~USB_DIEPMSK_INEPNAKEFFMSK; DEBUG_USB_INT_LO_PUTCHAR( '.' ); USBDHAL_SetEPDISNAK( ep ); /* Wait for epdis INT */ while ( !( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_EPDISBLD ) ) {} USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_EPDISBLD; USB->DIEPMSK &= ~USB_DIEPMSK_EPDISBLDMSK; USBHAL_FlushTxFifo( ep->txFifoNum ); /* Clear any interrupts generated by the abort sequence. */ NVIC_ClearPendingIRQ( USB_IRQn ); DEBUG_USB_INT_LO_PUTCHAR( '.' ); } void USBDHAL_AbortEpOut( USBD_Ep_TypeDef *ep ) { int cnt; /* Clear epdis INT's */ USB_DOUTEPS[ ep->num ].INT |= USB_DOEP_INT_EPDISBLD; /* Clear Global OUT NAK if already set */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; USB->GINTMSK |= USB_GINTMSK_GOUTNAKEFFMSK; /* Enable GOUTNAKEFF int */ /* Set Global OUT NAK */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SGOUTNAK; /* Wait for goutnakeff */ cnt = EPABORT_BREAK_LOOP_COUNT; while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) && cnt ) { cnt--; } USB->GINTMSK &= ~USB_GINTMSK_GOUTNAKEFFMSK; /* Disable GOUTNAKEFF int */ USB->DOEPMSK |= USB_DOEPMSK_EPDISBLDMSK; /* Enable EPDIS interrupt */ DEBUG_USB_INT_LO_PUTCHAR( ',' ); USBDHAL_SetEPDISNAK( ep ); /* Disable ep */ /* Wait for epdis INT */ cnt = EPABORT_BREAK_LOOP_COUNT; while ( !( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD ) && cnt ) { cnt--; } USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_EPDISBLD; USB->DOEPMSK &= ~USB_DOEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */ /* Clear Global OUT NAK */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; /* Clear any interrupts generated by the abort sequence. */ NVIC_ClearPendingIRQ( USB_IRQn ); DEBUG_USB_INT_LO_PUTCHAR( ',' ); } void USBDHAL_AbortAllEps( void ) { int i, cnt; USBD_Ep_TypeDef *ep; uint16_t im, om, inmask=0, outmask=0; /* Clear epdis & inepnakeff INT's */ for ( i = 1; i <= NUM_EP_USED; i++ ) { ep = &dev->ep[i]; if ( ep->state != D_EP_IDLE ) { if ( ep->in ) { inmask |= ep->mask; USB_DINEPS[ ep->num ].INT |= USB_DIEP_INT_EPDISBLD | USB_DIEP_INT_INEPNAKEFF; } else { outmask |= ep->mask; USB_DOUTEPS[ ep->num ].INT |= USB_DOEP_INT_EPDISBLD; } } } if ( inmask ) { /* Enable epdis & inepnakeff INT's */ USB->DIEPMSK |= USB_DIEPMSK_EPDISBLDMSK | USB_DIEPMSK_INEPNAKEFFMSK; /* Set NAK on all IN ep's */ im = inmask; for ( i = 1; i <= NUM_EP_USED; i++ ) { ep = &dev->ep[i]; if ( im & ep->mask ) { USB_DINEPS[ ep->num ].CTL = ( USB_DINEPS[ ep->num ].CTL & ~DEPCTL_WO_BITMASK ) | USB_DIEP_CTL_SNAK; } } } if ( outmask ) { /* Clear Global OUT NAK if already set */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; USB->GINTMSK |= USB_GINTMSK_GOUTNAKEFFMSK; /* Enable GOUTNAKEFF int */ /* Set Global OUT NAK */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_SGOUTNAK; /* Wait for goutnakeff */ cnt = EPABORT_BREAK_LOOP_COUNT; while ( !( USB->GINTSTS & USB_GINTSTS_GOUTNAKEFF ) && cnt ) { cnt--; } USB->GINTMSK &= ~USB_GINTMSK_GOUTNAKEFFMSK; /* Disable GOUTNAKEFF int */ USB->DOEPMSK |= USB_DOEPMSK_EPDISBLDMSK; /* Enable EPDIS interrupt */ } if ( inmask ) { /* Wait for inepnakeff INT on all IN ep's */ im = inmask; cnt = EPABORT_BREAK_LOOP_COUNT; do { for ( i = 1; i <= NUM_EP_USED; i++ ) { ep = &dev->ep[i]; if ( im & ep->mask ) { if ( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_INEPNAKEFF ) { USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_INEPNAKEFF; im &= ~ep->mask; } } } cnt--; } while ( im && cnt ); USB->DIEPMSK &= ~USB_DIEPMSK_INEPNAKEFFMSK; } DEBUG_USB_INT_LO_PUTCHAR( '\'' ); /* Disable ep's */ for ( i = 1; i <= NUM_EP_USED; i++ ) { ep = &dev->ep[i]; if ( ep->state != D_EP_IDLE ) { USBDHAL_SetEPDISNAK( ep ); } } /* Wait for epdis INT */ im = inmask; om = outmask; cnt = EPABORT_BREAK_LOOP_COUNT; do { for ( i = 1; i <= NUM_EP_USED; i++ ) { ep = &dev->ep[i]; if ( ep->in && ( im & ep->mask ) ) { if ( USBDHAL_GetInEpInts( ep ) & USB_DIEP_INT_EPDISBLD ) { USB_DINEPS[ ep->num ].INT = USB_DIEP_INT_EPDISBLD; im &= ~ep->mask; } } if ( !ep->in && ( om & ep->mask ) ) { if ( USBDHAL_GetOutEpInts( ep ) & USB_DOEP_INT_EPDISBLD ) { USB_DOUTEPS[ ep->num ].INT = USB_DOEP_INT_EPDISBLD; om &= ~ep->mask; } } } cnt--; } while ( ( im || om ) && cnt ); if ( inmask ) { USB->DIEPMSK &= ~USB_DIEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */ USBHAL_FlushTxFifo( 0x10 ); /* Flush all Tx FIFO's */ } if ( outmask ) { USB->DOEPMSK &= ~USB_DOEPMSK_EPDISBLDMSK; /* Disable EPDIS interrupt */ /* Clear Global OUT NAK */ USB->DCTL = ( USB->DCTL & ~DCTL_WO_BITMASK ) | USB_DCTL_CGOUTNAK; } DEBUG_USB_INT_LO_PUTCHAR( '\'' ); } void USBDHAL_AbortAllTransfers( USB_Status_TypeDef reason ) { int i; USBD_Ep_TypeDef *ep; USB_XferCompleteCb_TypeDef callback; if ( reason != USB_STATUS_DEVICE_RESET ) { USBDHAL_AbortAllEps(); } for ( i = 1; i <= NUM_EP_USED; i++ ) { ep = &(dev->ep[i]); if ( ep->state != D_EP_IDLE ) { ep->state = D_EP_IDLE; if ( ep->xferCompleteCb ) { callback = ep->xferCompleteCb; ep->xferCompleteCb = NULL; if ( ( dev->lastState == USBD_STATE_CONFIGURED ) && ( dev->state == USBD_STATE_ADDRESSED ) ) { USBDHAL_DeactivateEp( ep ); } DEBUG_TRACE_ABORT( reason ); callback( reason, ep->xferred, ep->remaining ); } } } /* Clear any interrupts generated by the abort sequence. */ NVIC_ClearPendingIRQ( USB_IRQn ); } #endif /* defined( USB_DEVICE ) */ #if defined( USB_HOST ) USB_Status_TypeDef USBHHAL_CoreInit( uint32_t rxFifoSize, uint32_t nptxFifoSize, uint32_t ptxFifoSize ) { uint8_t i; rxFifoSize /= 4; /* Convert from byte count to word count. */ nptxFifoSize /= 4; ptxFifoSize /= 4; CMU_ClockEnable( cmuClock_GPIO, true ); GPIO_PinModeSet( gpioPortF, 5, gpioModePushPull, 0 ); /* Enable VBUSEN pin */ #if ( USB_VBUSOVRCUR_PORT != USB_VBUSOVRCUR_PORT_NONE ) /* Enable VBUS overcurrent flag pin. */ GPIO_PinModeSet( USB_VBUSOVRCUR_PORT, USB_VBUSOVRCUR_PIN, gpioModeInput, 0 ); #endif USB->ROUTE = USB_ROUTE_PHYPEN | USB_ROUTE_VBUSENPEN; /* Enable PHY pins. */ USBHAL_CoreReset(); /* Reset USB core */ /* Force Host Mode */ USB->GUSBCFG = ( USB->GUSBCFG & ~(GUSBCFG_WO_BITMASK | USB_GUSBCFG_FORCEDEVMODE ) ) | USB_GUSBCFG_FORCEHSTMODE; INT_Enable(); USBTIMER_DelayMs( 100 ); INT_Disable(); /* Set 48 MHz PHY clock, FS/LS mode */ USB->HCFG = ( USB->HCFG & ~_USB_HCFG_FSLSPCLKSEL_MASK ) | ( 1 << _USB_HCFG_FSLSPCLKSEL_SHIFT ) | ( USB_HCFG_FSLSSUPP ); USB->GAHBCFG = ( USB->GAHBCFG & ~_USB_GAHBCFG_HBSTLEN_MASK ) | USB_GAHBCFG_DMAEN | USB_GAHBCFG_HBSTLEN_INCR; /* Set Rx FIFO size */ USB->GRXFSIZ = ( rxFifoSize << _USB_GRXFSIZ_RXFDEP_SHIFT ) & _USB_GRXFSIZ_RXFDEP_MASK; /* Set Tx FIFO sizes */ USB->GNPTXFSIZ = ( ( nptxFifoSize << _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_SHIFT ) & _USB_GNPTXFSIZ_NPTXFINEPTXF0DEP_MASK ) | ( ( rxFifoSize << _USB_GNPTXFSIZ_NPTXFSTADDR_SHIFT ) & _USB_GNPTXFSIZ_NPTXFSTADDR_MASK ); USB->HPTXFSIZ = ( ( ptxFifoSize << _USB_HPTXFSIZ_PTXFSIZE_SHIFT ) & _USB_HPTXFSIZ_PTXFSIZE_MASK ) | ( ( ( rxFifoSize + nptxFifoSize ) << _USB_HPTXFSIZ_PTXFSTADDR_SHIFT ) & _USB_HPTXFSIZ_PTXFSTADDR_MASK ); /* Flush Tx and Rx FIFO's */ USBHAL_FlushTxFifo( 0x10 ); USBHAL_FlushRxFifo(); for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ ) { USB->HC[ i ].CHAR = USB_HC_CHAR_CHDIS; /* Disable channel */ USB->HC[ i ].INT = 0xFFFFFFFF; /* Clear pending interrupts */ } /* Enable and halt all channels */ for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ ) { USB->HC[ i ].CHAR |= USB_HC_CHAR_CHDIS | USB_HC_CHAR_CHENA; do { __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); } while ( USB->HC[ i ].CHAR & USB_HC_CHAR_CHENA ); } /* Disable all interrupts */ for ( i = 0; i < MAX_NUM_HOSTCHANNELS; i++ ) { USB->HC[ i ].INTMSK = 0; } USB->HAINTMSK = 0; return USB_STATUS_OK; } void USBHHAL_HCHalt( int hcnum, uint32_t hcchar ) { hcchar |= USB_HC_CHAR_CHENA | USB_HC_CHAR_CHDIS; USB->HC[ hcnum ].CHAR = hcchar; } void USBHHAL_HCInit( int hcnum ) { USBH_Ep_TypeDef *ep; ep = hcs[ hcnum ].ep; USB->HC[ hcnum ].INT = 0xFFFFFFFF; /* Clear all interrupt flags */ switch ( ep->type ) /* Enable host channel int. types */ { case USB_EPTYPE_CTRL: case USB_EPTYPE_BULK: case USB_EPTYPE_INTR: USB->HC[ hcnum ].INTMSK = USB_HC_INT_CHHLTD; break; } hcs[ hcnum ].errorCnt = 0; USB->HAINTMSK |= 1 << hcnum; /* Enable host channel interrupt */ USB->HC[ hcnum ].CHAR = /* Program HCCHAR register */ ( ep->parentDevice->addr << _USB_HC_CHAR_DEVADDR_SHIFT ) | ( ( ep->addr & USB_EPNUM_MASK ) << _USB_HC_CHAR_EPNUM_SHIFT ) | ( ep->type << _USB_HC_CHAR_EPTYPE_SHIFT ) | ( ep->packetSize << _USB_HC_CHAR_MPS_SHIFT ) | ( ep->in ? USB_HC_CHAR_EPDIR : 0 ) | ( ep->parentDevice->speed == HPRT_L_SPEED >> _USB_HPRT_PRTSPD_SHIFT ? USB_HC_CHAR_LSPDDEV : 0 ); } void USBHHAL_HCStart( int hcnum ) { USBH_Hc_TypeDef *hc; uint16_t packets, len; hc = &hcs[ hcnum ]; hc->status = 0; hc->idle = false; if ( hc->remaining > 0 ) { packets = ( hc->remaining + hc->ep->packetSize - 1 ) / hc->ep->packetSize; } else { packets = 1; } if ( hc->ep->in ) { len = packets * hc->ep->packetSize; } else { len = hc->remaining; } /* Initialize the HCTSIZn register */ hc->hwXferSize = len; USB->HC[ hcnum ].TSIZ = ( ( len << _USB_HC_TSIZ_XFERSIZE_SHIFT ) & _USB_HC_TSIZ_XFERSIZE_MASK ) | ( ( packets << _USB_HC_TSIZ_PKTCNT_SHIFT ) & _USB_HC_TSIZ_PKTCNT_MASK ) | ( ( hc->ep->toggle << _USB_HC_TSIZ_PID_SHIFT ) & _USB_HC_TSIZ_PID_MASK ); USB->HC[ hcnum ].DMAADDR = (uint32_t)hc->buf; USBHHAL_HCActivate( hcnum, USB->HC[ hcnum ].CHAR, hc->ep->type == USB_EPTYPE_INTR ); } #endif /* defined( USB_HOST ) */ /** @endcond */ #endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */ #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */