MoistureSoftware/.pack/Keil/STM32F1xx_DFP.2.3.0/RTE_Driver/USBH_STM32F10x_cl.c

1170 lines
43 KiB
C
Raw Permalink Normal View History

2025-09-28 09:17:22 +00:00
/* -----------------------------------------------------------------------------
* Copyright (c) 2013-2017 ARM Ltd.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software. Permission is granted to anyone to use this
* software for any purpose, including commercial applications, and to alter
* it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
*
* $Date: 19. September 2017
* $Revision: V2.4
*
* Driver: Driver_USBH0
* Configured: via RTE_Device.h configuration file
* Project: USB Full/Low-Speed Host Driver for ST STM32F10x
* Connectivity Line
* --------------------------------------------------------------------------
* Use the following configuration settings in the middleware component
* to connect to this driver.
*
* Configuration Setting Value
* --------------------- -----
* Connect to hardware via Driver_USBH# = 0
* USB Host controller interface = Custom
* --------------------------------------------------------------------------
* Defines used for driver configuration (at compile time):
*
* USBH_MAX_PIPE_NUM: defines maximum number of Pipes that driver will
* support, this value impacts driver memory
* requirements
* - default value: 8
* - maximum value: 8
* -------------------------------------------------------------------------- */
/* History:
* Version 2.4
* Added support for CMSIS-RTOS2
* Version 2.3
* Removed interrupt priority handling
* Version 2.2
* Corrected multiple packet sending.
* Corrected PowerControl function for:
* - Unconditional Power Off
* - Conditional Power full (driver must be initialized)
* Version 2.1
* Update for USB Host CMSIS Driver API v2.01
* Version 2.0
* Initial release for USB Host CMSIS Driver API v2.0
*/
#include <stdint.h>
#include <string.h>
#include "RTE_Components.h"
#if defined(RTE_CMSIS_RTOS2)
#include "cmsis_os2.h"
#elif defined(RTE_CMSIS_RTOS)
#include "cmsis_os.h"
#endif
#include "stm32f10x.h"
#include "Driver_USBH.h"
#include "OTG_STM32F10x_cl.h"
#ifndef USBH_MAX_PIPE_NUM
#define USBH_MAX_PIPE_NUM 8U
#endif
#if (USBH_MAX_PIPE_NUM > 8)
#error Too many Pipes, maximum Pipes that this driver supports is 8 !!!
#endif
extern uint8_t otg_fs_role;
extern void OTG_FS_PinsConfigure (uint8_t pins_mask);
extern void OTG_FS_PinsUnconfigure (uint8_t pins_mask);
extern void OTG_FS_PinVbusOnOff (bool state);
extern bool OTG_FS_PinGetOC (void);
// USBH Driver *****************************************************************
#define ARM_USBH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2,4)
// Driver Version
static const ARM_DRIVER_VERSION usbh_driver_version = { ARM_USBH_API_VERSION, ARM_USBH_DRV_VERSION };
// Driver Capabilities
static const ARM_USBH_CAPABILITIES usbh_driver_capabilities = {
0x0001U, // Root HUB available Ports Mask
0U, // Automatic SPLIT packet handling
1U, // Signal Connect event
1U, // Signal Disconnect event
0U // Signal Overcurrent event
};
#define OTG OTG_FS
// FIFO sizes in bytes (total available memory for FIFOs is 1.25 kB)
#define RX_FIFO_SIZE 640U // RxFIFO depth is half of max 1.25 kB
#define TX_FIFO_SIZE_NON_PERI 512U // Non-periodic Tx FIFO size
#define TX_FIFO_SIZE_PERI 128U // Periodic Tx FIFO size
static volatile uint32_t *OTG_DFIFO[] = { OTG_FS_DFIFO0,
OTG_FS_DFIFO1,
OTG_FS_DFIFO2,
OTG_FS_DFIFO3,
OTG_FS_DFIFO4,
OTG_FS_DFIFO5,
OTG_FS_DFIFO6,
OTG_FS_DFIFO7
};
typedef struct { // Pipe structure definition
uint32_t packet;
uint8_t *data;
uint32_t num;
uint32_t num_transferred_total;
uint32_t num_transferring;
uint16_t ep_max_packet_size;
uint16_t interval_reload;
uint16_t interval;
uint8_t ep_type;
uint8_t active;
uint8_t in_progress;
uint8_t event;
} PIPE_t;
static ARM_USBH_SignalPortEvent_t SignalPortEvent;
static ARM_USBH_SignalPipeEvent_t SignalPipeEvent;
static bool hw_initialized = false;
static bool hw_powered = false;
static bool port_reset;
// Pipes runtime information
static volatile PIPE_t pipe[USBH_MAX_PIPE_NUM];
// Auxiliary functions
/**
\fn uint32_t USBH_CH_GetIndexFromAddress (OTG_FS_HC *ptr_ch)
\brief Get the Index of Channel from it's Address.
\param[in] ptr_ch Pointer to the Channel
\return Index of the Channel
*/
__INLINE static uint32_t USBH_CH_GetIndexFromAddress (OTG_FS_HC *ptr_ch) {
return (ptr_ch - ((OTG_FS_HC *)(&OTG->HCCHAR0)));
}
/**
\fn OTG_FS_HC *USBH_CH_GetAddressFromIndex (uint32_t index)
\brief Get the Channel Address from it's Index.
\param[in] index Index of the Channel
\return Address of the Channel
*/
__INLINE static OTG_FS_HC *USBH_CH_GetAddressFromIndex (uint32_t index) {
return (((OTG_FS_HC *)(&OTG->HCCHAR0)) + index);
}
/**
\fn OTG_FS_HC *USBH_CH_FindFree (void)
\brief Find a free Channel.
\return Pointer to the first free Channel (NULL = no free Channel is available)
*/
__INLINE static OTG_FS_HC *USBH_CH_FindFree (void) {
OTG_FS_HC *ptr_ch;
uint32_t i;
ptr_ch = (OTG_FS_HC *)(&(OTG->HCCHAR0));
for (i = 0U; i < USBH_MAX_PIPE_NUM; i++) {
if ((ptr_ch->HCCHAR & 0x3FFFFFFFU) == 0U) { return ptr_ch; }
ptr_ch++;
}
return NULL;
}
/**
\fn bool USBH_CH_Disable (OTG_FS_HC *ptr_ch)
\brief Disable the Channel.
\param[in] ptr_ch Pointer to the Channel
\return true = success, false = fail
*/
__INLINE static bool USBH_CH_Disable (OTG_FS_HC *ptr_ch) {
uint32_t i;
if (ptr_ch == 0U) { return false; }
if ((ptr_ch->HCINT & OTG_FS_HCINTx_CHH) != 0U) { return true; }
if ((ptr_ch->HCCHAR & OTG_FS_HCCHARx_CHENA) != 0U) {
ptr_ch->HCINTMSK = 0U;
osDelay(1U);
if ((ptr_ch->HCINT & OTG_FS_HCINTx_NAK) != 0U) {
ptr_ch->HCINT = 0x7BBU;
return true;
}
ptr_ch->HCINT = 0x7BBU;
ptr_ch->HCCHAR = ptr_ch->HCCHAR | OTG_FS_HCCHARx_CHENA | OTG_FS_HCCHARx_CHDIS;
for (i = 0U; i < 1000U; i++) {
if ((ptr_ch->HCINT & OTG_FS_HCINTx_CHH) != 0U) {
ptr_ch->HCINT = 0x7BBU;
return true;
}
}
return false;
}
return true;
}
/**
\fn bool USBH_HW_StartTransfer (PIPE_t *ptr_pipe, OTG_FS_HC *ptr_ch)
\brief Start transfer on Pipe.
\param[in] ptr_pipe Pointer to Pipe
\param[in] ptr_ch Pointer to Channel
\return true = success, false = fail
*/
static bool USBH_HW_StartTransfer (PIPE_t *ptr_pipe, OTG_FS_HC *ptr_ch) {
uint32_t hcchar;
uint32_t hctsiz;
uint32_t hcintmsk;
uint32_t txsts;
uint32_t pckt_num;
uint32_t data_num;
uint32_t max_pckt_size;
uint32_t max_data;
uint32_t max_num_pckt;
uint32_t num_to_transfer;
uint8_t *ptr_src;
volatile uint32_t *ptr_dest;
uint16_t cnt;
uint8_t out;
if (ptr_pipe == 0U) { return false; }
if (ptr_ch == 0U) { return false; }
if ((OTG->HPRT & OTG_FS_HPRT_PCSTS) == 0U) { return false; }
hcchar = ptr_ch->HCCHAR; // Read channel characteristics
hctsiz = ptr_ch->HCTSIZ; // Read channel size info
hcintmsk = 0U;
cnt = 0U;
out = 0U;
// Prepare transfer
// Prepare HCCHAR register
hcchar &= (OTG_FS_HCCHARx_ODDFRM | // Keep ODDFRM
OTG_FS_HCCHARx_DAD_MSK | // Keep DAD
OTG_FS_HCCHARx_MCNT_MSK | // Keep MCNT
OTG_FS_HCCHARx_EPTYP_MSK | // Keep EPTYP
OTG_FS_HCCHARx_LSDEV | // Keep LSDEV
OTG_FS_HCCHARx_EPNUM_MSK | // Keep EPNUM
OTG_FS_HCCHARx_MPSIZ_MSK); // Keep MPSIZ
hctsiz &= OTG_FS_HCTSIZx_DPID_MSK; // Keep DPID
switch (ptr_pipe->packet & ARM_USBH_PACKET_TOKEN_Msk) {
case ARM_USBH_PACKET_IN:
hcchar |= OTG_FS_HCCHARx_EPDIR;
hcintmsk = (OTG_FS_HCINTMSKx_DTERRM |
OTG_FS_HCINTMSKx_BBERRM |
OTG_FS_HCINTMSKx_TXERRM |
OTG_FS_HCINTMSKx_ACKM |
OTG_FS_HCINTMSKx_NAKM |
OTG_FS_HCINTMSKx_STALLM |
OTG_FS_HCINTMSKx_XFRCM) ;
break;
case ARM_USBH_PACKET_OUT:
hcchar &= ~OTG_FS_HCCHARx_EPDIR;
hcintmsk = (OTG_FS_HCINTMSKx_TXERRM |
// OTG_FS_HCINTMSKx_ACKM | // After ACK there must be other relevant interrupt so ACK is ignorred
OTG_FS_HCINTMSKx_NAKM |
OTG_FS_HCINTMSKx_STALLM |
OTG_FS_HCINTMSKx_XFRCM) ;
out = 1U;
break;
case ARM_USBH_PACKET_SETUP:
hcchar &= ~OTG_FS_HCCHARx_EPDIR;
hcintmsk = (OTG_FS_HCINTMSKx_TXERRM |
OTG_FS_HCINTMSKx_XFRCM) ;
hctsiz &= ~OTG_FS_HCTSIZx_DPID_MSK;
hctsiz |= OTG_FS_HCTSIZx_DPID_MDATA;
out = 1U;
break;
default:
return false;
}
num_to_transfer = ptr_pipe->num - ptr_pipe->num_transferred_total;
switch (ptr_pipe->ep_type) {
case ARM_USB_ENDPOINT_CONTROL:
case ARM_USB_ENDPOINT_BULK:
if (out != 0U) {
txsts = OTG->HNPTXSTS; // Read non-periodic FIFO status
}
break;
case ARM_USB_ENDPOINT_ISOCHRONOUS:
case ARM_USB_ENDPOINT_INTERRUPT:
if (out != 0U) {
txsts = OTG->HPTXSTS; // Read non-periodic FIFO status
}
if ((OTG->HFNUM & 1U) != 0U) {
hcchar &= ~OTG_FS_HCCHARx_ODDFRM;
} else {
hcchar |= OTG_FS_HCCHARx_ODDFRM;
}
break;
}
if (out != 0U) {
// For packet OUT/SETUP limit number of bytes to send to maximum FIFO size
// and maximum number of packets
max_pckt_size = ptr_pipe->ep_max_packet_size;
max_data = (txsts & 0x0000FFFFU) << 2;
max_num_pckt = (txsts & 0x00FF0000U) >> 16;
if (num_to_transfer > max_data) {
num_to_transfer = max_data;
}
data_num = num_to_transfer;
for (pckt_num = 1; data_num > max_pckt_size; pckt_num++) {
data_num -= max_pckt_size;
}
if (pckt_num > max_num_pckt) {
pckt_num = max_num_pckt;
}
if (num_to_transfer > (pckt_num * max_pckt_size)) {
num_to_transfer = pckt_num * max_pckt_size;
}
cnt = (num_to_transfer + 3U) / 4U;
}
hcchar &= ~OTG_FS_HCCHARx_CHDIS;
hcchar |= OTG_FS_HCCHARx_CHENA;
// Prepare HCTSIZ register
switch (ptr_pipe->packet & ARM_USBH_PACKET_DATA_Msk) {
case ARM_USBH_PACKET_DATA0:
hctsiz &= ~OTG_FS_HCTSIZx_DPID_MSK;
hctsiz |= OTG_FS_HCTSIZx_DPID_DATA0;
break;
case ARM_USBH_PACKET_DATA1:
hctsiz &= ~OTG_FS_HCTSIZx_DPID_MSK;
hctsiz |= OTG_FS_HCTSIZx_DPID_DATA1;
break;
default:
break;
}
// Prepare HCTSIZ register
if (num_to_transfer != 0U) { // Normal packet
// Prepare PKTCNT field
hctsiz |= ((num_to_transfer + ptr_pipe->ep_max_packet_size - 1U) / ptr_pipe->ep_max_packet_size) << 19;
hctsiz |= num_to_transfer; // Prepare XFRSIZ field
} else { // Zero length packet
hctsiz |= 1U << 19; // Prepare PKTCNT field
hctsiz |= 0U; // Prepare XFRSIZ field
}
if (cnt != 0U) {
ptr_src = ptr_pipe->data + ptr_pipe->num_transferred_total;
ptr_dest = OTG_DFIFO[USBH_CH_GetIndexFromAddress (ptr_ch)];
}
if (out != 0U) {
// For OUT/SETUP transfer num_transferring represents num of bytes to be sent
ptr_pipe->num_transferring = num_to_transfer;
} else {
// For IN transfer num_transferring represents num of bytes received (handled in IRQ)
ptr_pipe->num_transferring = 0U;
}
NVIC_DisableIRQ (OTG_FS_IRQn); // Disable OTG interrupt
ptr_ch->HCINTMSK = hcintmsk; // Enable channel interrupts
ptr_ch->HCTSIZ = hctsiz; // Write ch transfer size
ptr_ch->HCCHAR = hcchar; // Write ch characteristics
while (cnt != 0U) { // Load data
*ptr_dest = *((__packed uint32_t *)ptr_src);
ptr_src += 4U;
cnt--;
}
NVIC_EnableIRQ (OTG_FS_IRQn); // Enable OTG interrupt
return true;
}
// USBH Driver functions
/**
\fn ARM_DRIVER_VERSION USBH_GetVersion (void)
\brief Get driver version.
\return \ref ARM_DRIVER_VERSION
*/
static ARM_DRIVER_VERSION USBH_GetVersion (void) { return usbh_driver_version; }
/**
\fn ARM_USBH_CAPABILITIES USBH_GetCapabilities (void)
\brief Get driver capabilities.
\return \ref ARM_USBH_CAPABILITIES
*/
static ARM_USBH_CAPABILITIES USBH_GetCapabilities (void) { return usbh_driver_capabilities; }
/**
\fn int32_t USBH_Initialize (ARM_USBH_SignalPortEvent_t cb_port_event,
ARM_USBH_SignalPipeEvent_t cb_pipe_event)
\brief Initialize USB Host Interface.
\param[in] cb_port_event Pointer to \ref ARM_USBH_SignalPortEvent
\param[in] cb_pipe_event Pointer to \ref ARM_USBH_SignalPipeEvent
\return \ref execution_status
*/
static int32_t USBH_Initialize (ARM_USBH_SignalPortEvent_t cb_port_event,
ARM_USBH_SignalPipeEvent_t cb_pipe_event) {
if (hw_initialized == true) { return ARM_DRIVER_OK; }
SignalPortEvent = cb_port_event;
SignalPipeEvent = cb_pipe_event;
otg_fs_role = ARM_USB_ROLE_HOST;
OTG_FS_PinsConfigure (ARM_USB_PIN_DP | ARM_USB_PIN_DM | ARM_USB_PIN_OC | ARM_USB_PIN_VBUS);
hw_initialized = true;
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_Uninitialize (void)
\brief De-initialize USB Host Interface.
\return \ref execution_status
*/
static int32_t USBH_Uninitialize (void) {
OTG_FS_PinsUnconfigure (ARM_USB_PIN_DP | ARM_USB_PIN_DM | ARM_USB_PIN_OC | ARM_USB_PIN_VBUS);
otg_fs_role = ARM_USB_ROLE_NONE;
hw_initialized = false;
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PowerControl (ARM_POWER_STATE state)
\brief Control USB Host Interface Power.
\param[in] state Power state
\return \ref execution_status
*/
static int32_t USBH_PowerControl (ARM_POWER_STATE state) {
switch (state) {
case ARM_POWER_OFF:
RCC->AHBENR |= RCC_AHBENR_OTGFSEN; // OTG FS clock enable
NVIC_DisableIRQ (OTG_FS_IRQn); // Disable interrupt
NVIC_ClearPendingIRQ (OTG_FS_IRQn); // Clear pending interrupt
hw_powered = false; // Clear powered flag
OTG->GAHBCFG &= ~OTG_FS_GAHBCFG_GINTMSK; // Disable USB interrupts
RCC->AHBRSTR |= RCC_AHBRSTR_OTGFSRST; // Reset OTG FS module
port_reset = false; // Reset variables
memset((void *)(pipe), 0, sizeof(pipe));
OTG->GCCFG &= ~OTG_FS_GCCFG_PWRDWN; // Enable PHY power down
OTG->PCGCCTL |= OTG_FS_PCGCCTL_STPPCLK; // Stop PHY clock
OTG->GCCFG = 0U; // Reset core configuration
RCC->AHBENR &= ~RCC_AHBENR_OTGFSEN; // Disable OTG FS clock
break;
case ARM_POWER_FULL:
if (hw_initialized == false) { return ARM_DRIVER_ERROR; }
if (hw_powered == true) { return ARM_DRIVER_OK; }
RCC->AHBENR |= RCC_AHBENR_OTGFSEN; // OTG FS clock enable
RCC->AHBRSTR |= RCC_AHBRSTR_OTGFSRST; // Reset OTG FS module
osDelay(1U);
RCC->AHBRSTR &= ~RCC_AHBRSTR_OTGFSRST; // Clear reset of OTG FS module
osDelay(1U);
// On-chip Full-speed PHY
OTG->PCGCCTL &= ~OTG_FS_PCGCCTL_STPPCLK; // Start PHY clock
OTG->GCCFG |= OTG_FS_GCCFG_PWRDWN; // Disable power down
OTG->GUSBCFG |= OTG_FS_GUSBCFG_PHYSEL; // Full-speed transceiver
OTG->HCFG |= OTG_FS_HCFG_FSLSS; // Support for FS/LS only
// Wait until AHB Master state machine is in the idle condition
while ((OTG->GRSTCTL & OTG_FS_GRSTCTL_AHBIDL) == 0U);
OTG->GRSTCTL |= OTG_FS_GRSTCTL_CSRST; // Core soft reset
while ((OTG->GRSTCTL & OTG_FS_GRSTCTL_CSRST) != 0U);
osDelay(1U);
// Wait until AHB Master state machine is in the idle condition
while ((OTG->GRSTCTL & OTG_FS_GRSTCTL_AHBIDL) == 0U);
port_reset = false; // Reset variables
memset((void *)(pipe), 0, sizeof(pipe));
OTG->GCCFG &= ~OTG_FS_GCCFG_VBUSBSEN; // Disable VBUS sensing device "B"
OTG->GCCFG &= ~OTG_FS_GCCFG_VBUSASEN; // Disable VBUS sensing device "A"
OTG->GCCFG |= OTG_FS_GCCFG_NOVBUSSENS; // Disable VBUS sensing
if (((OTG->GUSBCFG & OTG_FS_GUSBCFG_FHMOD) == 0U) || ((OTG->GUSBCFG & OTG_FS_GUSBCFG_FDMOD) != 0U)) {
OTG->GUSBCFG &= ~OTG_FS_GUSBCFG_FDMOD; // Clear force device mode
OTG->GUSBCFG |= OTG_FS_GUSBCFG_FHMOD; // Force host mode
osDelay(100U);
}
// Rx FIFO setting
OTG->GRXFSIZ = (RX_FIFO_SIZE/4U);
// Non-periodic Tx FIFO setting
OTG->HNPTXFSIZ = ((TX_FIFO_SIZE_NON_PERI/4U) << 16) | (RX_FIFO_SIZE / 4U);
// Periodic Tx FIFO setting
OTG->HPTXFSIZ = ((TX_FIFO_SIZE_PERI /4U) << 16) | ((RX_FIFO_SIZE + TX_FIFO_SIZE_NON_PERI) / 4U);
OTG->HAINTMSK = (1U << USBH_MAX_PIPE_NUM) - 1U; // Enable channel interrupts
OTG->GINTMSK = (OTG_FS_GINTMSK_DISCINT | // Unmask interrupts
OTG_FS_GINTMSK_HCIM |
OTG_FS_GINTMSK_PRTIM |
OTG_FS_GINTMSK_RXFLVLM |
OTG_FS_GINTMSK_SOFM) ;
OTG->GAHBCFG |= OTG_FS_GAHBCFG_GINTMSK; // Enable interrupts
hw_powered = true; // Set powered flag
NVIC_EnableIRQ (OTG_FS_IRQn); // Enable interrupt
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PortVbusOnOff (uint8_t port, bool vbus)
\brief Root HUB Port VBUS on/off.
\param[in] port Root HUB Port Number
\param[in] vbus
- \b false VBUS off
- \b true VBUS on
\return \ref execution_status
*/
static int32_t USBH_PortVbusOnOff (uint8_t port, bool vbus) {
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (port != 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
if (vbus != 0U) { // VBUS power on
OTG->HPRT |= OTG_FS_HPRT_PPWR; // Port power on
OTG_FS_PinVbusOnOff (true); // VBUS pin on
} else { // VBUS power off
OTG_FS_PinVbusOnOff (false); // VBUS pin off
OTG->HPRT &= ~OTG_FS_HPRT_PPWR; // Port power off
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PortReset (uint8_t port)
\brief Do Root HUB Port Reset.
\param[in] port Root HUB Port Number
\return \ref execution_status
*/
static int32_t USBH_PortReset (uint8_t port) {
uint32_t hprt;
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (port != 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
port_reset = true;
hprt = OTG->HPRT;
hprt &= ~OTG_FS_HPRT_PENA; // Disable port
hprt |= OTG_FS_HPRT_PRST; // Port reset
OTG->HPRT = hprt;
osDelay(18U);
hprt &= ~OTG_FS_HPRT_PRST; // Clear port reset
OTG->HPRT = hprt;
osDelay(50U);
if (port_reset == true) {
port_reset = false;
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PortSuspend (uint8_t port)
\brief Suspend Root HUB Port (stop generating SOFs).
\param[in] port Root HUB Port Number
\return \ref execution_status
*/
static int32_t USBH_PortSuspend (uint8_t port) {
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (port != 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
OTG->HPRT |= OTG_FS_HPRT_PSUSP; // Port suspend
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PortResume (uint8_t port)
\brief Resume Root HUB Port (start generating SOFs).
\param[in] port Root HUB Port Number
\return \ref execution_status
*/
static int32_t USBH_PortResume (uint8_t port) {
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (port != 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
OTG->HPRT |= OTG_FS_HPRT_PRES; // Port resume
return ARM_DRIVER_OK;
}
/**
\fn ARM_USBH_PORT_STATE USBH_PortGetState (uint8_t port)
\brief Get current Root HUB Port State.
\param[in] port Root HUB Port Number
\return Port State \ref ARM_USBH_PORT_STATE
*/
static ARM_USBH_PORT_STATE USBH_PortGetState (uint8_t port) {
ARM_USBH_PORT_STATE port_state = { 0U, 0U, 0U };
uint32_t hprt;
if (hw_powered == false) { return port_state; }
if (port != 0U) { return port_state; }
hprt = OTG->HPRT;
port_state.connected = (hprt & OTG_FS_HPRT_PCSTS) != 0U;
#ifdef MX_USB_OTG_FS_Overcurrent_Pin
port_state.overcurrent = OTG_FS_PinGetOC ();
#else
port_state.overcurrent = 0U;
#endif
switch ((hprt & OTG_FS_HPRT_PSPD_MSK) >> OTG_FS_HPRT_PSPD_POS) {
case 0: // High speed
break;
case 1: // Full speed
port_state.speed = ARM_USB_SPEED_FULL;
break;
case 2: // Low speed
port_state.speed = ARM_USB_SPEED_LOW;
break;
default:
break;
}
return port_state;
}
/**
\fn ARM_USBH_PIPE_HANDLE USBH_PipeCreate (uint8_t dev_addr,
uint8_t dev_speed,
uint8_t hub_addr,
uint8_t hub_port,
uint8_t ep_addr,
uint8_t ep_type,
uint16_t ep_max_packet_size,
uint8_t ep_interval)
\brief Create Pipe in System.
\param[in] dev_addr Device Address
\param[in] dev_speed Device Speed
\param[in] hub_addr Hub Address
\param[in] hub_port Hub Port
\param[in] ep_addr Endpoint Address
- ep_addr.0..3: Address
- ep_addr.7: Direction
\param[in] ep_type Endpoint Type (ARM_USB_ENDPOINT_xxx)
\param[in] ep_max_packet_size Endpoint Maximum Packet Size
\param[in] ep_interval Endpoint Polling Interval
\return Pipe Handle \ref ARM_USBH_PIPE_HANDLE
*/
static ARM_USBH_PIPE_HANDLE USBH_PipeCreate (uint8_t dev_addr, uint8_t dev_speed, uint8_t hub_addr, uint8_t hub_port, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_max_packet_size, uint8_t ep_interval) {
PIPE_t *ptr_pipe;
OTG_FS_HC *ptr_ch;
if (hw_powered == false) { return 0U; }
ptr_ch = USBH_CH_FindFree (); // Find free Channel
if (ptr_ch == 0U) { return 0U; } // If no free
ptr_pipe = (PIPE_t *)(&pipe[USBH_CH_GetIndexFromAddress (ptr_ch)]);
memset((void *)ptr_pipe, 0, sizeof(PIPE_t)); // Clear Pipes runtime information
// Fill in all fields of Endpoint Descriptor
ptr_ch->HCCHAR = (OTG_FS_HCCHARx_MPSIZ (ep_max_packet_size) ) |
(OTG_FS_HCCHARx_EPNUM (ep_addr) ) |
(OTG_FS_HCCHARx_EPDIR * (((ep_addr >> 7) & 0x0001U) == 0U)) |
(OTG_FS_HCCHARx_LSDEV * (dev_speed == ARM_USB_SPEED_LOW) ) |
(OTG_FS_HCCHARx_EPTYP (ep_type) ) |
(OTG_FS_HCCHARx_DAD (dev_addr) ) ;
// Store Pipe settings
ptr_pipe->ep_max_packet_size = ep_max_packet_size;
ptr_pipe->ep_type = ep_type;
switch (ep_type) {
case ARM_USB_ENDPOINT_CONTROL:
case ARM_USB_ENDPOINT_BULK:
break;
case ARM_USB_ENDPOINT_ISOCHRONOUS:
case ARM_USB_ENDPOINT_INTERRUPT:
if (dev_speed == ARM_USB_SPEED_HIGH) {
if ((ep_interval > 0U) && (ep_interval <= 16U)) {
ptr_pipe->interval_reload = (uint16_t)1U << (ep_interval - 1U);
}
} else if ((dev_speed == ARM_USB_SPEED_FULL) || (dev_speed == ARM_USB_SPEED_LOW)) {
if (ep_interval > 0U) {
ptr_pipe->interval_reload = ep_interval;
}
}
ptr_pipe->interval = 0U;
ptr_ch->HCCHAR |= OTG_FS_HCCHARx_MCNT((((ep_max_packet_size >> 11) + 1U) & 3U));
break;
}
return ((ARM_USBH_EP_HANDLE)ptr_ch);
}
/**
\fn int32_t USBH_PipeModify (ARM_USBH_PIPE_HANDLE pipe_hndl,
uint8_t dev_addr,
uint8_t dev_speed,
uint8_t hub_addr,
uint8_t hub_port,
uint16_t ep_max_packet_size)
\brief Modify Pipe in System.
\param[in] pipe_hndl Pipe Handle
\param[in] dev_addr Device Address
\param[in] dev_speed Device Speed
\param[in] hub_addr Hub Address
\param[in] hub_port Hub Port
\param[in] ep_max_packet_size Endpoint Maximum Packet Size
\return \ref execution_status
*/
static int32_t USBH_PipeModify (ARM_USBH_PIPE_HANDLE pipe_hndl, uint8_t dev_addr, uint8_t dev_speed, uint8_t hub_addr, uint8_t hub_port, uint16_t ep_max_packet_size) {
PIPE_t *ptr_pipe;
OTG_FS_HC *ptr_ch;
uint32_t hcchar;
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (pipe_hndl == 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
ptr_ch = (OTG_FS_HC *)(pipe_hndl);
ptr_pipe = (PIPE_t *)(&pipe[USBH_CH_GetIndexFromAddress (ptr_ch)]);
if (ptr_pipe->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
// Fill in all fields of Endpoint Descriptor
hcchar = ptr_ch->HCCHAR;
hcchar &= ~(OTG_FS_HCCHARx_MPSIZ_MSK | // Clear maximum packet size field
OTG_FS_HCCHARx_LSDEV | // Clear device speed bit
OTG_FS_HCCHARx_DAD_MSK) ; // Clear device address field
hcchar |= OTG_FS_HCCHARx_MPSIZ (ep_max_packet_size) |
(OTG_FS_HCCHARx_LSDEV * (dev_speed == ARM_USB_SPEED_LOW)) |
(OTG_FS_HCCHARx_DAD (dev_addr)) ;
ptr_ch->HCCHAR = hcchar; // Update modified fields
ptr_pipe->ep_max_packet_size = ep_max_packet_size;
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PipeDelete (ARM_USBH_PIPE_HANDLE pipe_hndl)
\brief Delete Pipe from System.
\param[in] pipe_hndl Pipe Handle
\return \ref execution_status
*/
static int32_t USBH_PipeDelete (ARM_USBH_PIPE_HANDLE pipe_hndl) {
PIPE_t *ptr_pipe;
OTG_FS_HC *ptr_ch;
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (pipe_hndl == 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
ptr_ch = (OTG_FS_HC *)(pipe_hndl);
ptr_pipe = (PIPE_t *)(&pipe[USBH_CH_GetIndexFromAddress (ptr_ch)]);
if (ptr_pipe->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
ptr_ch->HCCHAR = 0U;
ptr_ch->HCINT = 0U;
ptr_ch->HCINTMSK = 0U;
ptr_ch->HCTSIZ = 0U;
// Clear all fields of Pipe structure
memset((void *)ptr_pipe, 0, sizeof(PIPE_t));
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PipeReset (ARM_USBH_PIPE_HANDLE pipe_hndl)
\brief Reset Pipe.
\param[in] pipe_hndl Pipe Handle
\return \ref execution_status
*/
static int32_t USBH_PipeReset (ARM_USBH_PIPE_HANDLE pipe_hndl) {
PIPE_t *ptr_pipe;
OTG_FS_HC *ptr_ch;
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (pipe_hndl == 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
ptr_ch = (OTG_FS_HC *)(pipe_hndl);
ptr_pipe = (PIPE_t *)(&pipe[USBH_CH_GetIndexFromAddress (ptr_ch)]);
if (ptr_pipe->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
ptr_ch->HCINT = 0U;
ptr_ch->HCINTMSK = 0U;
ptr_ch->HCTSIZ = 0U;
return ARM_DRIVER_OK;
}
/**
\fn int32_t USBH_PipeTransfer (ARM_USBH_PIPE_HANDLE pipe_hndl,
uint32_t packet,
uint8_t *data,
uint32_t num)
\brief Transfer packets through USB Pipe.
\param[in] pipe_hndl Pipe Handle
\param[in] packet Packet information
\param[in] data Pointer to buffer with data to send or for data to receive
\param[in] num Number of data bytes to transfer
\return \ref execution_status
*/
static int32_t USBH_PipeTransfer (ARM_USBH_PIPE_HANDLE pipe_hndl, uint32_t packet, uint8_t *data, uint32_t num) {
PIPE_t *ptr_pipe;
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (pipe_hndl == 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
if ((OTG->HPRT & OTG_FS_HPRT_PCSTS) == 0U) { return ARM_DRIVER_ERROR; }
ptr_pipe = (PIPE_t *)(&pipe[USBH_CH_GetIndexFromAddress ((OTG_FS_HC *)(pipe_hndl))]);
if (ptr_pipe->active != 0U) { return ARM_DRIVER_ERROR_BUSY; }
// Update current transfer information
ptr_pipe->packet = packet;
ptr_pipe->data = data;
ptr_pipe->num = num;
ptr_pipe->num_transferred_total = 0U;
ptr_pipe->num_transferring = 0U;
ptr_pipe->active = 0U;
ptr_pipe->in_progress = 0U;
ptr_pipe->event = 0U;
if ((ptr_pipe->ep_type == ARM_USB_ENDPOINT_INTERRUPT) && (ptr_pipe->interval != 0U)) {
// Already active interrupt endpoint (it will restart in IRQ based on interval)
ptr_pipe->active = 1U;
} else {
ptr_pipe->in_progress = 1U;
ptr_pipe->active = 1U;
if (USBH_HW_StartTransfer (ptr_pipe, (OTG_FS_HC *)pipe_hndl) == 0U) {
ptr_pipe->in_progress = 0U;
ptr_pipe->active = 0U;
return ARM_DRIVER_ERROR;
}
}
return ARM_DRIVER_OK;
}
/**
\fn uint32_t USBH_PipeTransferGetResult (ARM_USBH_PIPE_HANDLE pipe_hndl)
\brief Get result of USB Pipe transfer.
\param[in] pipe_hndl Pipe Handle
\return number of successfully transferred data bytes
*/
static uint32_t USBH_PipeTransferGetResult (ARM_USBH_PIPE_HANDLE pipe_hndl) {
if (pipe_hndl == 0U) { return 0U; }
return (pipe[USBH_CH_GetIndexFromAddress((OTG_FS_HC *)pipe_hndl)].num_transferred_total);
}
/**
\fn int32_t USBH_PipeTransferAbort (ARM_USBH_PIPE_HANDLE pipe_hndl)
\brief Abort current USB Pipe transfer.
\param[in] pipe_hndl Pipe Handle
\return \ref execution_status
*/
static int32_t USBH_PipeTransferAbort (ARM_USBH_PIPE_HANDLE pipe_hndl) {
PIPE_t *ptr_pipe;
if (hw_powered == false) { return ARM_DRIVER_ERROR; }
if (pipe_hndl == 0U) { return ARM_DRIVER_ERROR_PARAMETER; }
ptr_pipe = (PIPE_t *)(&pipe[USBH_CH_GetIndexFromAddress ((OTG_FS_HC *)(pipe_hndl))]);
if (ptr_pipe->active != 0U) {
ptr_pipe->active = 0U;
if (USBH_CH_Disable((OTG_FS_HC *)(pipe_hndl)) == 0U) { return ARM_DRIVER_ERROR; }
}
return ARM_DRIVER_OK;
}
/**
\fn uint16_t USBH_GetFrameNumber (void)
\brief Get current USB Frame Number.
\return Frame Number
*/
static uint16_t USBH_GetFrameNumber (void) {
if (hw_powered == false) { return 0U; }
return ((OTG->HFNUM >> 3) & 0x7FFU);
}
/**
\fn void USBH_FS_IRQ (uint32_t gintsts)
\brief USB Host Interrupt Routine (IRQ).
*/
void USBH_FS_IRQ (uint32_t gintsts) {
PIPE_t *ptr_pipe;
OTG_FS_HC *ptr_ch;
uint8_t *ptr_data;
volatile uint32_t *dfifo;
uint32_t hprt, haint, hcint, pktcnt, mpsiz;
uint32_t grxsts, bcnt, ch, dat, len, len_rest;
uint8_t hchalt;
if ((gintsts & OTG_FS_GINTSTS_HPRTINT) != 0U) { // If host port interrupt
hprt = OTG->HPRT;
OTG->HPRT = hprt & (~OTG_FS_HPRT_PENA); // Leave PENA bit
if ((hprt & OTG_FS_HPRT_PCDET) != 0U) { // Port connect detected
switch ((hprt >> 17) & 3U) {
case 0: // High-speed detected
break;
case 1: // Full-speed detected
OTG->HCFG = OTG_FS_HCFG_FSLSPCS(1U);
break;
case 2: // Low-speed detected
OTG->HCFG = OTG_FS_HCFG_FSLSPCS(2U);
break;
default:
break;
}
if (port_reset == false) { // If port not under reset
SignalPortEvent(0, ARM_USBH_EVENT_CONNECT);
}
}
if ((hprt & OTG_FS_HPRT_PENCHNG) != 0U) { // If port enable changed
if ((hprt & OTG_FS_HPRT_PENA) != 0U) { // If device connected
if (port_reset == true) {
port_reset = false;
SignalPortEvent(0, ARM_USBH_EVENT_RESET);
}
}
}
}
if ((gintsts & OTG_FS_GINTSTS_DISCINT) != 0U) { // If device disconnected
OTG->GINTSTS = OTG_FS_GINTSTS_DISCINT; // Clear disconnect interrupt
if (port_reset == false) { // Ignore disconnect under reset
ptr_ch = (OTG_FS_HC *)(&OTG->HCCHAR0);
ptr_pipe = (PIPE_t *)(pipe);
for (ch = 0U; ch < USBH_MAX_PIPE_NUM; ch++) {
if (ptr_pipe->active != 0U) {
ptr_pipe->active = 0U;
SignalPipeEvent((ARM_USBH_EP_HANDLE)ptr_ch, ARM_USBH_EVENT_BUS_ERROR);
}
ptr_ch++;
ptr_pipe++;
}
SignalPortEvent(0, ARM_USBH_EVENT_DISCONNECT);
}
}
// Handle reception interrupt
if ((gintsts & OTG_FS_GINTSTS_RXFLVL) != 0U) { // If RXFIFO non-empty interrupt
OTG->GINTMSK &= ~OTG_FS_GINTMSK_RXFLVLM;
grxsts = OTG->GRXSTSR;
if (((grxsts >> 17) & 0x0FU) == 0x02U) { // If PKTSTS = 0x02
grxsts = (OTG->GRXSTSP);
ch = (grxsts ) & 0x00FU;
bcnt = (grxsts >> 4) & 0x7FFU;
dfifo = OTG_DFIFO[ch];
ptr_data = pipe[ch].data + pipe[ch].num_transferred_total;
len = bcnt / 4U; // Received number of 32-bit data
len_rest = bcnt & 3U; // Number of bytes left
while (len != 0U) {
*((__packed uint32_t *)ptr_data) = *dfifo;
ptr_data += 4U;
len--;
}
if (len_rest != 0U) {
dat = *((__packed uint32_t *)dfifo);
while (len_rest != 0U) {
*ptr_data++ = dat;
dat >>= 8;
len_rest--;
}
}
pipe[ch].num_transferring += bcnt;
pipe[ch].num_transferred_total += bcnt;
} else { // If PKTSTS != 0x02
grxsts = OTG->GRXSTSP;
}
OTG->GINTMSK |= OTG_FS_GINTMSK_RXFLVLM;
}
// Handle host ctrl interrupt
if ((gintsts & OTG_FS_GINTSTS_HCINT) != 0U) { // If host channel interrupt
haint = OTG->HAINT;
for (ch = 0U; ch < USBH_MAX_PIPE_NUM; ch++) {
if (haint == 0U) { break; }
if ((haint & (1U << ch)) != 0U) { // If channels interrupt active
haint &= ~(1U << ch);
ptr_ch = (OTG_FS_HC *)(&OTG->HCCHAR0) + ch;
ptr_pipe = (PIPE_t *)(&pipe[ch]);
hcint = ptr_ch->HCINT & ptr_ch->HCINTMSK;
hchalt = 0U;
if ((hcint & OTG_FS_HCINTx_CHH) != 0U) { // If channel halted
ptr_ch->HCINT = OTG_FS_HCINTx_CHH; // Clear halt interrupt
ptr_ch->HCINTMSK = 0U; // Disable all channel interrupts
ptr_ch->HCINT = 0x7BBU; // Clear all interrupts
ptr_pipe->in_progress = 0U; // Transfer not in progress
} else if ((hcint & OTG_FS_HCINTx_XFRC) != 0U) {// If data transfer finished
ptr_ch->HCINT = 0x7BBU; // Clear all interrupts
if ((ptr_ch->HCCHAR & (1U << 15)) != 0U) { // If endpoint IN
ptr_pipe->event = ARM_USBH_EVENT_TRANSFER_COMPLETE;
} else { // If endpoint OUT
ptr_pipe->num_transferred_total += ptr_pipe->num_transferring;
ptr_pipe->num_transferring = 0U;
if (ptr_pipe->num_transferred_total == ptr_pipe->num) {
ptr_pipe->event = ARM_USBH_EVENT_TRANSFER_COMPLETE;
}
}
hchalt = 1U;
} else {
if ((hcint & OTG_FS_HCINTx_ACK) != 0U) { // If ACK received
ptr_ch->HCINT = OTG_FS_HCINTx_ACK; // Clear ACK interrupt
// On ACK, ACK is not an event that can be returned so if transfer
// is completed another interrupt will happen otherwise for IN
// endpoint transfer will be restarted for remaining data
if ((ptr_ch->HCCHAR & (1U << 15)) != 0U) { // If endpoint IN
if ((ptr_pipe->num != ptr_pipe->num_transferred_total) && // If all data was not transferred
(ptr_pipe->num_transferring != 0U) && // If zero-length packet was not received
((ptr_pipe->num_transferred_total%ptr_pipe->ep_max_packet_size) == 0U)){ // If short packet was not received
ptr_ch->HCCHAR |= OTG_FS_HCCHARx_CHENA;
}
} else { // If endpoint OUT
hchalt = 1U;
}
} else if ((hcint & (OTG_FS_HCINTx_STALL | // If STALL received
OTG_FS_HCINTx_NAK | // If NAK received
OTG_FS_HCINTx_ERR )) != 0U) { // If any error occurred
if ((ptr_ch->HCCHAR & (1U << 15)) == 0U) { // If endpoint OUT
// Update transferred count
pktcnt = (ptr_ch->HCTSIZ >> 19) & 0x000003FFU;
mpsiz = (ptr_ch->HCCHAR ) & 0x000007FFU;
if ((ptr_pipe->num_transferring >= mpsiz) && (pktcnt > 0U)) {
ptr_pipe->num_transferred_total += ptr_pipe->num_transferring - mpsiz * pktcnt;
}
ptr_pipe->num_transferring = 0U;
}
if ((hcint & OTG_FS_HCINTx_NAK)!=0U){ // If NAK received
ptr_ch->HCINT = OTG_FS_HCINTx_NAK; // Clear NAK interrupt
// On NAK, NAK is not returned to middle layer but transfer is
// restarted from driver for remaining data, unless it is interrupt
// endpoint in which case transfer is restarted on SOF event
// when period has expired
if ((ptr_ch->HCCHAR & (1U << 15)) != 0U) {// If endpoint IN
if (ptr_pipe->ep_type == ARM_USB_ENDPOINT_INTERRUPT) {
hchalt = 1U;
} else {
ptr_ch->HCCHAR |= OTG_FS_HCCHARx_CHENA;
}
} else { // If endpoint OUT
hchalt = 1U;
}
} else if ((hcint&OTG_FS_HCINTx_STALL)!=0U){// If STALL received
ptr_ch->HCINT = OTG_FS_HCINTx_STALL; // Clear STALL interrupt
ptr_pipe->event = ARM_USBH_EVENT_HANDSHAKE_STALL;
hchalt = 1U;
} else {
ptr_ch->HCINT = OTG_FS_HCINTx_ERR; // Clear all error interrupts
ptr_pipe->event = ARM_USBH_EVENT_BUS_ERROR;
hchalt = 1U;
}
}
}
if (hchalt != 0U) { // If channel should be halted
ptr_ch->HCINTMSK = OTG_FS_HCINTx_CHH; // Enable halt interrupt
ptr_ch->HCCHAR |= OTG_FS_HCCHARx_CHENA | OTG_FS_HCCHARx_CHDIS;
}
if ((ptr_pipe->in_progress == 0U) && (ptr_pipe->event != 0U)) {
ptr_pipe->active = 0U;
SignalPipeEvent((ARM_USBH_EP_HANDLE)ptr_ch, ptr_pipe->event);
}
}
}
}
// Handle periodic transfer timings
if ((gintsts & OTG_FS_GINTSTS_SOF) != 0U) { // If start of frame interrupt
OTG->GINTSTS = OTG_FS_GINTSTS_SOF; // Clear SOF interrupt
ptr_pipe = (PIPE_t *)(pipe);
for (ch = 0U; ch < USBH_MAX_PIPE_NUM; ch++) {
// If interrupt transfer is active handle period (interval)
if ((ptr_pipe->ep_type == ARM_USB_ENDPOINT_INTERRUPT) && (ptr_pipe->active != 0U) && (ptr_pipe->interval != 0U)) {
ptr_pipe->interval--;
}
ptr_pipe++;
}
}
// Handle restarts of unfinished transfers (due to NAK or ACK)
ptr_pipe = (PIPE_t *)(pipe);
for (ch = 0U; ch < USBH_MAX_PIPE_NUM; ch++) {
if ((ptr_pipe->active != 0U) && (ptr_pipe->in_progress == 0U)) {
// Restart periodic transfer if not in progress and interval expired
if (ptr_pipe->ep_type == ARM_USB_ENDPOINT_INTERRUPT) {
if (ptr_pipe->interval == 0U) {
ptr_pipe->interval = ptr_pipe->interval_reload;
} else {
continue;
}
}
ptr_pipe->in_progress = 1;
if (USBH_HW_StartTransfer (ptr_pipe, USBH_CH_GetAddressFromIndex (ch)) == 0U) {
ptr_pipe->in_progress = 0U;
ptr_pipe->active = 0U;
}
}
ptr_pipe++;
}
}
ARM_DRIVER_USBH Driver_USBH0 = {
USBH_GetVersion,
USBH_GetCapabilities,
USBH_Initialize,
USBH_Uninitialize,
USBH_PowerControl,
USBH_PortVbusOnOff,
USBH_PortReset,
USBH_PortSuspend,
USBH_PortResume,
USBH_PortGetState,
USBH_PipeCreate,
USBH_PipeModify,
USBH_PipeDelete,
USBH_PipeReset,
USBH_PipeTransfer,
USBH_PipeTransferGetResult,
USBH_PipeTransferAbort,
USBH_GetFrameNumber
};