SCSI2SD/software/SCSI2SD/v3/SCSI2SD.cydsn/Generated_Source/PSoC5/USBFS.c
2017-05-01 09:07:22 +10:00

2821 lines
117 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************************//**
* \file USBFS.c
* \version 3.10
*
* \brief
* This file contains the global USBFS API functions.
*
* Note:
* Many of the functions use an endpoint number. SRAM arrays are sized with 9
* elements, so they are indexed directly by epNumber. The SIE and ARB
* registers are indexed by variations of epNumber - 1.
*
********************************************************************************
* \copyright
* Copyright 2008-2016, Cypress Semiconductor Corporation. All rights reserved.
* You may use this file only in accordance with the license, terms, conditions,
* disclaimers, and limitations in the end user license agreement accompanying
* the software package with which this file was provided.
*******************************************************************************/
#include "USBFS_pvt.h"
#include "USBFS_cydmac.h"
#include "USBFS_hid.h"
#include "USBFS_Dp.h"
/***************************************
* Global data allocation
***************************************/
/** Indicates whether the USBFS has been initialized. The variable is
* initialized to 0 after device reset and set to 1 the first time USBFS_Start()
* is called. This allows the Component to restart without reinitialization after
* the first call to the USBFS_Start() routine.
* If re-initialization of the Component is required, the variable should be set
* to 0 before the USBFS_Start() routine is called. Alternatively, the USBFS can
* be reinitialized by calling both USBFS_Init() and USBFS_InitComponent()
* functions.
*/
uint8 USBFS_initVar = 0u;
#if (USBFS_EP_MANAGEMENT_DMA)
#if (CY_PSOC4)
static void USBFS_InitEpDma(void);
/* DMA chanels assigend for endpoints. */
const uint8 USBFS_DmaChan[USBFS_MAX_EP] =
{
0u,
0u,
0u,
0u,
0u,
0u,
0u,
0u,
0u,
};
#else
/* DMA chanels assigend for endpoints. */
uint8 USBFS_DmaChan[USBFS_MAX_EP];
/* DMA TDs require for PSoC 3/5LP operation. */
uint8 USBFS_DmaTd[USBFS_MAX_EP];
#endif /* (CY_PSOC4) */
#endif /* (USBFS_EP_MANAGEMENT_DMA) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
#if (CY_PSOC4)
/* Number of DMA bursts. */
uint8 USBFS_DmaEpBurstCnt [USBFS_MAX_EP];
/* Number of bytes to transfer in last DMA burst. */
uint8 USBFS_DmaEpLastBurstEl[USBFS_MAX_EP];
/* Storage for arrays above. */
uint8 USBFS_DmaEpBurstCntBackup [USBFS_MAX_EP];
uint32 USBFS_DmaEpBufferAddrBackup[USBFS_MAX_EP];
/* DMA trigger mux output for usb.dma_req[0-7]. */
const uint8 USBFS_DmaReqOut[USBFS_MAX_EP] =
{
0u,
USBFS_ep1_dma__TR_OUTPUT,
USBFS_ep2_dma__TR_OUTPUT,
USBFS_ep3_dma__TR_OUTPUT,
USBFS_ep4_dma__TR_OUTPUT,
0u,
0u,
0u,
0u,
};
/* DMA trigger mux output for usb.dma_burstend[0-7]. */
const uint8 USBFS_DmaBurstEndOut[USBFS_MAX_EP] =
{
0u,
USBFS_BURSTEND_0_TR_OUTPUT,
USBFS_BURSTEND_1_TR_OUTPUT,
USBFS_BURSTEND_2_TR_OUTPUT,
USBFS_BURSTEND_3_TR_OUTPUT,
USBFS_BURSTEND_4_TR_OUTPUT,
USBFS_BURSTEND_5_TR_OUTPUT,
USBFS_BURSTEND_6_TR_OUTPUT,
USBFS_BURSTEND_7_TR_OUTPUT
};
#else
#if (USBFS_EP_DMA_AUTO_OPT == 0u)
static uint8 clearInDataRdyStatus = USBFS_ARB_EPX_CFG_DEFAULT;
uint8 USBFS_DmaNextTd[USBFS_MAX_EP];
const uint8 USBFS_epX_TD_TERMOUT_EN[USBFS_MAX_EP] =
{
0u,
0u,
0u,
0u,
0u,
0u,
0u,
0u,
0u,
};
volatile uint16 USBFS_inLength[USBFS_MAX_EP];
const uint8 *USBFS_inDataPointer[USBFS_MAX_EP];
volatile uint8 USBFS_inBufFull[USBFS_MAX_EP];
#endif /* (USBFS_EP_DMA_AUTO_OPT == 0u) */
#endif /* (CY_PSOC4) */
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
/*******************************************************************************
* Function Name: USBFS_Start
****************************************************************************//**
*
* This function performs all required initialization for the USBFS component.
* After this function call, the USB device initiates communication with the
* host by pull-up D+ line. This is the preferred method to begin component
* operation.
*
* Note that global interrupts have to be enabled because interrupts are
* required for USBFS component operation.
*
* PSoC 4200L devices: when USBFS component configured to DMA with Automatic
* Buffer Management, the DMA interrupt priority is changed to the highest
* (priority 0) inside this function.
*
* PSoC 3/PSoC 5LP devices: when USBFS component configured to DMA with
* Automatic Buffer Management, the Arbiter interrupt priority is changed to
* the highest (priority 0) inside this function.
*
* \param device
* Contains the device number of the desired device descriptor.
* The device number can be found in the Device Descriptor Tab of
* "Configure" dialog, under the settings of desired Device Descriptor,
* in the "Device Number" field.
* \param mode:
* The operating voltage. This determines whether the voltage regulator
* is enabled for 5V operation or if pass through mode is used for 3.3V
* operation. Symbolic names and their associated values are given in the
* following list.
*
* *USBFS_3V_OPERATION* - Disable voltage regulator and pass-
* through Vcc for pull-up
*
* *USBFS_5V_OPERATION* - Enable voltage regulator and use
* regulator for pull-up
*
* *USBFS_DWR_POWER_OPERATION* - Enable or disable the voltage
* regulator depending on the power supply
* voltage configuration in the DWR tab.
* For PSoC 3/5LP devices, the VDDD supply
* voltage is considered and for PSoC 4A-L,
* the VBUS supply voltage is considered.*
* \globalvars
* \ref USBFS_initVar
*
* \sideeffect
* This function will reset all communication states to default.
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_Start(uint8 device, uint8 mode)
{
if (0u == USBFS_initVar)
{
USBFS_Init();
USBFS_initVar = 1u;
}
USBFS_InitComponent(device, mode);
}
/*******************************************************************************
* Function Name: USBFS_Init
****************************************************************************//**
*
* This function initializes or restores the component according to the
* customizer Configure dialog settings. It is not necessary to call
* USBFS_Init() because the USBFS_Start() routine calls
* this function and is the preferred method to begin component operation.
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_Init(void)
{
#if (CY_PSOC4)
/* Enable clock to USB IP. */
USBFS_USB_CLK_EN_REG = USBFS_USB_CLK_CSR_CLK_EN;
/* The internal regulator (CR1.REG_ENABLE) is enabled in
* USBFS_InitComponent() if it is required.
*/
/* Enable USBIO control on drive mode of D+ and D- pins. */
USBFS_USBIO_CR1_REG &= ~ (uint32) USBFS_USBIO_CR1_IOMODE;
/* Set number of LF CLK to detect UBS bus reset. */
USBFS_BUS_RST_CNT_REG = USBFS_DEFUALT_BUS_RST_CNT;
/* Select VBUS detection source and clear PHY isolate. The application level
* must ensure that VBUS is valid. There is no need to wait 2us before VBUS is valid.
*/
USBFS_POWER_CTRL_REG = USBFS_DEFAULT_POWER_CTRL_VBUS;
/* Enable PHY detector and single-ended and differential receivers. */
USBFS_POWER_CTRL_REG |= USBFS_DEFAULT_POWER_CTRL_PHY;
/* Suspend clear sequence. */
USBFS_POWER_CTRL_REG &= (uint32) ~USBFS_POWER_CTRL_SUSPEND;
CyDelayUs(USBFS_WAIT_SUSPEND_DEL_DISABLE);
USBFS_POWER_CTRL_REG &= (uint32) ~USBFS_POWER_CTRL_SUSPEND_DEL;
/* Sets IMO lock options and clear all other bits. */
USBFS_CR1_REG = USBFS_DEFUALT_CR1;
/* Configure level (hi, lo, med) for each interrupt source. */
USBFS_INTR_LVL_SEL_REG = USBFS_DEFAULT_INTR_LVL_SEL;
/* Configure interrupt sources from: SOF, Bus Reset and EP0. */
USBFS_INTR_SIE_MASK_REG = USBFS_DEFAULT_INTR_SIE_MASK;
#else
uint8 enableInterrupts = CyEnterCriticalSection();
#if (USBFS_EP_MANAGEMENT_DMA)
uint16 i;
#endif /* (USBFS_EP_MANAGEMENT_DMA) */
/* Enable USB block. */
USBFS_PM_ACT_CFG_REG |= USBFS_PM_ACT_EN_FSUSB;
/* Enable USB block for Standby Power Mode. */
USBFS_PM_STBY_CFG_REG |= USBFS_PM_STBY_EN_FSUSB;
/* Enable core clock. */
USBFS_USB_CLK_EN_REG = USBFS_USB_CLK_ENABLE;
USBFS_CR1_REG = USBFS_CR1_ENABLE_LOCK;
/* ENABLING USBIO PADS IN USB MODE FROM I/O MODE. */
/* Ensure USB transmit enable is low (USB_USBIO_CR0.ten). - Manual Transmission - Disabled. */
USBFS_USBIO_CR0_REG &= (uint8) ~USBFS_USBIO_CR0_TEN;
CyDelayUs(USBFS_WAIT_REG_STABILITY_50NS); /* ~50ns delay. */
/* Disable USBIO by asserting PM.USB_CR0.fsusbio_pd_n(Inverted.
* high. These bits will be set low by the power manager out-of-reset.
* Also confirm USBIO pull-up is disabled.
*/
USBFS_PM_USB_CR0_REG &= (uint8) ~(USBFS_PM_USB_CR0_PD_N |
USBFS_PM_USB_CR0_PD_PULLUP_N);
/* Select IOMODE to USB mode. */
USBFS_USBIO_CR1_REG &= (uint8) ~USBFS_USBIO_CR1_IOMODE;
/* Enable USBIO reference by setting PM.USB_CR0.fsusbio_ref_en. */
USBFS_PM_USB_CR0_REG |= USBFS_PM_USB_CR0_REF_EN;
/* Reference is available for 1us after regulator is enabled. */
CyDelayUs(USBFS_WAIT_REG_STABILITY_1US);
/* OR 40us after power is restored. */
CyDelayUs(USBFS_WAIT_VREF_RESTORE);
/* Ensure single-ended disable bits are low (PRT15.INP_DIS[7:6])(input receiver enabled). */
USBFS_DM_INP_DIS_REG &= (uint8) ~USBFS_DM_MASK;
USBFS_DP_INP_DIS_REG &= (uint8) ~USBFS_DP_MASK;
/* Enable USBIO. */
USBFS_PM_USB_CR0_REG |= USBFS_PM_USB_CR0_PD_N;
CyDelayUs(USBFS_WAIT_PD_PULLUP_N_ENABLE);
/* Set USBIO pull-up enable. */
USBFS_PM_USB_CR0_REG |= USBFS_PM_USB_CR0_PD_PULLUP_N;
/* Reset Arbiter Write Address register for endpoint 1. */
CY_SET_REG8(USBFS_ARB_RW1_WA_PTR, 0u);
CY_SET_REG8(USBFS_ARB_RW1_WA_MSB_PTR, 0u);
#if (USBFS_EP_MANAGEMENT_DMA)
/* Initialize transfer descriptor. This will be used to detect DMA state - initialized or not. */
for (i = 0u; i < USBFS_MAX_EP; ++i)
{
USBFS_DmaTd[i] = DMA_INVALID_TD;
#if (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u))
USBFS_DmaNextTd[i] = DMA_INVALID_TD;
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u)) */
}
#endif /* (USBFS_EP_MANAGEMENT_DMA) */
CyExitCriticalSection(enableInterrupts);
#endif /* (CY_PSOC4) */
/* Configure interrupts from USB block. */
#if (CY_PSOC4)
/* Configure hi_int: set handler and priority. */
CyIntSetPriority (USBFS_INTR_HI_VECT_NUM, USBFS_INTR_HI_PRIORITY);
(void) CyIntSetVector(USBFS_INTR_HI_VECT_NUM, &USBFS_INTR_HI_ISR);
/* Configure lo_int: set handler and priority. */
CyIntSetPriority (USBFS_INTR_LO_VECT_NUM, USBFS_INTR_LO_PRIORITY);
(void) CyIntSetVector(USBFS_INTR_LO_VECT_NUM, &USBFS_INTR_LO_ISR);
/* Configure med_int: set handler and priority (routed through DSI). */
CyIntSetPriority (USBFS_INTR_MED_VECT_NUM, USBFS_INTR_MED_PRIORITY);
(void) CyIntSetVector(USBFS_INTR_MED_VECT_NUM, &USBFS_INTR_MED_ISR);
#else
/* Set bus reset interrupt. */
CyIntSetPriority(USBFS_BUS_RESET_VECT_NUM, USBFS_BUS_RESET_PRIOR);
(void) CyIntSetVector(USBFS_BUS_RESET_VECT_NUM, &USBFS_BUS_RESET_ISR);
/* Set Control Endpoint Interrupt. */
CyIntSetPriority(USBFS_EP_0_VECT_NUM, USBFS_EP_0_PRIOR);
(void) CyIntSetVector(USBFS_EP_0_VECT_NUM, &USBFS_EP_0_ISR);
/* Set SOF interrupt. */
#if (USBFS_SOF_ISR_ACTIVE)
CyIntSetPriority (USBFS_SOF_VECT_NUM, USBFS_SOF_PRIOR);
(void) CyIntSetVector(USBFS_SOF_VECT_NUM, &USBFS_SOF_ISR);
#endif /* (USBFS_SOF_ISR_ACTIVE) */
/* Set Data Endpoint 1 Interrupt. */
#if (USBFS_EP1_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_1_VECT_NUM, USBFS_EP_1_PRIOR);
(void) CyIntSetVector(USBFS_EP_1_VECT_NUM, &USBFS_EP_1_ISR);
#endif /* (USBFS_EP1_ISR_ACTIVE) */
/* Set Data Endpoint 2 Interrupt. */
#if (USBFS_EP2_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_2_VECT_NUM, USBFS_EP_2_PRIOR);
(void) CyIntSetVector(USBFS_EP_2_VECT_NUM, &USBFS_EP_2_ISR);
#endif /* (USBFS_EP2_ISR_ACTIVE) */
/* Set Data Endpoint 3 Interrupt. */
#if (USBFS_EP3_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_3_VECT_NUM, USBFS_EP_3_PRIOR);
(void) CyIntSetVector(USBFS_EP_3_VECT_NUM, &USBFS_EP_3_ISR);
#endif /* (USBFS_EP3_ISR_ACTIVE) */
/* Set Data Endpoint 4 Interrupt. */
#if (USBFS_EP4_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_4_VECT_NUM, USBFS_EP_4_PRIOR);
(void) CyIntSetVector(USBFS_EP_4_VECT_NUM, &USBFS_EP_4_ISR);
#endif /* (USBFS_EP4_ISR_ACTIVE) */
/* Set Data Endpoint 5 Interrupt. */
#if (USBFS_EP5_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_5_VECT_NUM, USBFS_EP_5_PRIOR);
(void) CyIntSetVector(USBFS_EP_5_VECT_NUM, &USBFS_EP_5_ISR);
#endif /* (USBFS_EP5_ISR_ACTIVE) */
/* Set Data Endpoint 6 Interrupt. */
#if (USBFS_EP6_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_6_VECT_NUM, USBFS_EP_6_PRIOR);
(void) CyIntSetVector(USBFS_EP_6_VECT_NUM, &USBFS_EP_6_ISR);
#endif /* (USBFS_EP6_ISR_ACTIVE) */
/* Set Data Endpoint 7 Interrupt. */
#if (USBFS_EP7_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_7_VECT_NUM, USBFS_EP_7_PRIOR);
(void) CyIntSetVector(USBFS_EP_7_VECT_NUM, &USBFS_EP_7_ISR);
#endif /* (USBFS_EP7_ISR_ACTIVE) */
/* Set Data Endpoint 8 Interrupt. */
#if (USBFS_EP8_ISR_ACTIVE)
CyIntSetPriority (USBFS_EP_8_VECT_NUM, USBFS_EP_8_PRIOR);
(void) CyIntSetVector(USBFS_EP_8_VECT_NUM, &USBFS_EP_8_ISR);
#endif /* (USBFS_EP8_ISR_ACTIVE) */
/* Set ARB Interrupt. */
#if (USBFS_EP_MANAGEMENT_DMA && USBFS_ARB_ISR_ACTIVE)
CyIntSetPriority (USBFS_ARB_VECT_NUM, USBFS_ARB_PRIOR);
(void) CyIntSetVector(USBFS_ARB_VECT_NUM, &USBFS_ARB_ISR);
#endif /* (USBFS_EP_MANAGEMENT_DMA && USBFS_ARB_ISR_ACTIVE) */
#endif /* (CY_PSOC4) */
/* Common: Configure GPIO interrupt for wakeup. */
#if (USBFS_DP_ISR_ACTIVE)
CyIntSetPriority (USBFS_DP_INTC_VECT_NUM, USBFS_DP_INTC_PRIORITY);
(void) CyIntSetVector(USBFS_DP_INTC_VECT_NUM, &USBFS_DP_ISR);
#endif /* (USBFS_DP_ISR_ACTIVE) */
#if (USBFS_EP_MANAGEMENT_DMA && CY_PSOC4)
/* Initialize DMA channels. */
USBFS_InitEpDma();
#endif /* (USBFS_EP_MANAGEMENT_DMA && CY_PSOC4) */
}
/*******************************************************************************
* Function Name: USBFS_InitComponent
****************************************************************************//**
*
* This function initializes the components global variables and initiates
* communication with the host by pull-up D+ line.
*
* \param device:
* Contains the device number of the desired device descriptor. The device
* number can be found in the Device Descriptor Tab of "Configure" dialog,
* under the settings of desired Device Descriptor, in the *Device Number*
* field.
* \param mode:
* The operating voltage. This determines whether the voltage regulator
* is enabled for 5V operation or if pass through mode is used for 3.3V
* operation. Symbolic names and their associated values are given in the
* following list.
*
* *USBFS_3V_OPERATION* - Disable voltage regulator and pass-
* through Vcc for pull-up
*
* *USBFS_5V_OPERATION* - Enable voltage regulator and use
* regulator for pull-up
*
* *USBFS_DWR_POWER_OPERATION* - Enable or disable the voltage
* regulator depending on the power supply
* voltage configuration in the DWR tab.
* For PSoC 3/5LP devices, the VDDD supply
* voltage is considered and for PSoC 4A-L,
* the VBUS supply voltage is considered.
*
* \globalvars
* \ref USBFS_device
* \ref USBFS_transferState
* \ref USBFS_configuration
* \ref USBFS_deviceStatus
*
* \ref USBFS_deviceAddress - Contains the current device address. This
* variable is initialized to zero in this API. The Host starts to communicate
* to the device with address 0 and then sets it to a whatever value using a
* SET_ADDRESS request.
*
* \ref USBFS_lastPacketSize - Initialized to 0;
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_InitComponent(uint8 device, uint8 mode)
{
/* Initialize _hidProtocol variable to comply with
* HID 7.2.6 Set_Protocol Request:
* "When initialized, all devices default to report protocol."
*/
#if defined(USBFS_ENABLE_HID_CLASS)
uint8 i;
for (i = 0u; i < USBFS_MAX_INTERFACES_NUMBER; i++)
{
USBFS_hidProtocol[i] = USBFS_PROTOCOL_REPORT;
}
#endif /* USBFS_ENABLE_HID_CLASS */
/* Store device number to access descriptor. */
USBFS_device = device;
/* Reset component internal variables. */
USBFS_transferState = USBFS_TRANS_STATE_IDLE;
USBFS_configurationChanged = 0u;
USBFS_configuration = 0u;
USBFS_interfaceNumber = 0u;
USBFS_deviceAddress = 0u;
USBFS_deviceStatus = 0u;
USBFS_lastPacketSize = 0u;
/* Enable component interrupts. */
#if (CY_PSOC4)
CyIntEnable(USBFS_INTR_HI_VECT_NUM);
CyIntEnable(USBFS_INTR_MED_VECT_NUM);
CyIntEnable(USBFS_INTR_LO_VECT_NUM);
#else
CyIntEnable(USBFS_BUS_RESET_VECT_NUM);
CyIntEnable(USBFS_EP_0_VECT_NUM);
#if (USBFS_SOF_ISR_ACTIVE)
CyIntEnable(USBFS_SOF_VECT_NUM);
#endif /* (USBFS_SOF_ISR_ACTIVE) */
#if (USBFS_EP1_ISR_ACTIVE)
CyIntEnable(USBFS_EP_1_VECT_NUM);
#endif /* (USBFS_EP1_ISR_ACTIVE) */
#if (USBFS_EP2_ISR_ACTIVE)
CyIntEnable(USBFS_EP_2_VECT_NUM);
#endif /* (USBFS_EP5_ISR_ACTIVE) */
#if (USBFS_EP3_ISR_ACTIVE)
CyIntEnable(USBFS_EP_3_VECT_NUM);
#endif /* (USBFS_EP5_ISR_ACTIVE) */
#if (USBFS_EP4_ISR_ACTIVE)
CyIntEnable(USBFS_EP_4_VECT_NUM);
#endif /* (USBFS_EP5_ISR_ACTIVE) */
#if (USBFS_EP5_ISR_ACTIVE)
CyIntEnable(USBFS_EP_5_VECT_NUM);
#endif /* (USBFS_EP5_ISR_ACTIVE) */
#if (USBFS_EP6_ISR_ACTIVE)
CyIntEnable(USBFS_EP_6_VECT_NUM);
#endif /* USBFS_EP6_ISR_REMOVE */
#if (USBFS_EP7_ISR_ACTIVE)
CyIntEnable(USBFS_EP_7_VECT_NUM);
#endif /* (USBFS_EP7_ISR_ACTIVE) */
#if (USBFS_EP8_ISR_ACTIVE)
CyIntEnable(USBFS_EP_8_VECT_NUM);
#endif /* (USBFS_EP8_ISR_ACTIVE) */
#endif /* (CY_PSOC4) */
#if (USBFS_EP_MANAGEMENT_DMA && USBFS_ARB_ISR_ACTIVE)
/* Enable ARB EP interrupt sources. */
USBFS_ARB_INT_EN_REG = USBFS_DEFAULT_ARB_INT_EN;
#if (CY_PSOC3 || CY_PSOC5)
CyIntEnable(USBFS_ARB_VECT_NUM);
#endif /* (CY_PSOC3 || CY_PSOC5) */
#endif /* (USBFS_EP_MANAGEMENT_DMA && USBFS_ARB_ISR_ACTIVE) */
/* Arbiter configuration for DMA transfers. */
#if (USBFS_EP_MANAGEMENT_DMA)
/* Configure Arbiter for Manual or Auto DMA operation and clear configuration completion. */
USBFS_ARB_CFG_REG = USBFS_DEFAULT_ARB_CFG;
#if (CY_PSOC4)
/* Enable DMA operation. */
CyDmaEnable();
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
/* Change DMA priority to be highest. */
CyIntSetPriority(CYDMA_INTR_NUMBER, USBFS_DMA_AUTO_INTR_PRIO);
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
#endif /* (CY_PSOC4) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
#if (CY_PSOC4)
/* Enable DMA interrupt to handle DMA management. */
CyIntEnable(CYDMA_INTR_NUMBER);
#else
#if (USBFS_EP_DMA_AUTO_OPT == 0u)
/* Initialize interrupts which handle verification of successful DMA transaction. */
USBFS_EP_DMA_Done_isr_StartEx(&USBFS_EP_DMA_DONE_ISR);
USBFS_EP17_DMA_Done_SR_InterruptEnable();
USBFS_EP8_DMA_Done_SR_InterruptEnable();
#endif /* (USBFS_EP_DMA_AUTO_OPT == 0u) */
#endif /* (CY_PSOC4) */
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
#endif /* (USBFS_EP_MANAGEMENT_DMA) */
/* Enable USB regulator depends on operation voltage. IMO Locking is enabled in Init(). */
switch(mode)
{
case USBFS_3V_OPERATION:
/* Disable regulator for 3V operation. */
USBFS_CR1_REG &= (uint8) ~USBFS_CR1_REG_ENABLE;
break;
case USBFS_5V_OPERATION:
/* Enable regulator for 5V operation. */
USBFS_CR1_REG |= (uint8) USBFS_CR1_REG_ENABLE;
break;
default: /* Check DWR settings of USB power supply. */
#if (USBFS_VDDD_MV < USBFS_3500MV)
/* Disable regulator for 3V operation. */
USBFS_CR1_REG &= (uint8) ~USBFS_CR1_REG_ENABLE;
#else
/* Enable regulator for 5V operation. */
USBFS_CR1_REG |= (uint8) USBFS_CR1_REG_ENABLE;
#endif /* (USBFS_VDDD_MV < USBFS_3500MV) */
break;
}
#if (CY_PSOC4)
/* Clear bus activity. */
USBFS_CR1_REG &= (uint32) ~USBFS_CR1_BUS_ACTIVITY;
/* Clear EP0 count register. */
USBFS_EP0_CNT_REG = USBFS_CLEAR_REG;
/* Set EP0.CR: ACK Setup, NAK IN/OUT. */
USBFS_EP0_CR_REG = USBFS_MODE_NAK_IN_OUT;
#if (USBFS_LPM_ACTIVE)
if (NULL != USBFS_GetBOSPtr())
{
/* Enable LPM and acknowledge LPM packets for active device.
* Reset NYET_EN and SUB_RESP bits in the LPM_CTRL register.
*/
USBFS_LPM_CTRL_REG = (USBFS_LPM_CTRL_LPM_EN | \
USBFS_LPM_CTRL_LPM_ACK_RESP);
}
else
{
/* Disable LPM for active device. */
USBFS_LPM_CTRL_REG &= (uint32) ~USBFS_LPM_CTRL_LPM_EN;
}
#endif /* (USBFS_LPM_ACTIVE) */
/* Enable device to responds to USB traffic with address 0. */
USBFS_CR0_REG = USBFS_DEFUALT_CR0;
#else
/* Set EP0.CR: ACK Setup, STALL IN/OUT. */
USBFS_EP0_CR_REG = USBFS_MODE_STALL_IN_OUT;
/* Enable device to respond to USB traffic with address 0. */
USBFS_CR0_REG = USBFS_DEFUALT_CR0;
CyDelayCycles(USBFS_WAIT_CR0_REG_STABILITY);
#endif /* (CY_PSOC4) */
/* Enable D+ pull-up and keep USB control on IO. */
USBFS_USBIO_CR1_REG = USBFS_USBIO_CR1_USBPUEN;
}
/*******************************************************************************
* Function Name: USBFS_ReInitComponent
****************************************************************************//**
*
* This function reinitialize the component configuration and is
* intend to be called from the Reset interrupt.
*
* \globalvars
* USBFS_device - Contains the device number of the desired Device
* Descriptor. The device number can be found in the Device Descriptor tab
* of the Configure dialog, under the settings of the desired Device Descriptor,
* in the Device Number field.
* USBFS_transferState - This variable is used by the communication
* functions to handle the current transfer state. Initialized to
* TRANS_STATE_IDLE in this API.
* USBFS_configuration - Contains the current configuration number
* set by the Host using a SET_CONFIGURATION request.
* Initialized to zero in this API.
* USBFS_deviceAddress - Contains the current device address. This
* variable is initialized to zero in this API. The Host starts to communicate
* to the device with address 0 and then sets it to a whatever value using
* a SET_ADDRESS request.
* USBFS_deviceStatus - Initialized to 0.
* This is a two-bit variable which contains the power status in the first bit
* (DEVICE_STATUS_BUS_POWERED or DEVICE_STATUS_SELF_POWERED) and the remote
* wakeup status (DEVICE_STATUS_REMOTE_WAKEUP) in the second bit.
* USBFS_lastPacketSize - Initialized to 0;
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_ReInitComponent(void)
{
/* Initialize _hidProtocol variable to comply with HID 7.2.6 Set_Protocol
* Request: "When initialized, all devices default to report protocol."
*/
#if defined(USBFS_ENABLE_HID_CLASS)
uint8 i;
for (i = 0u; i < USBFS_MAX_INTERFACES_NUMBER; i++)
{
USBFS_hidProtocol[i] = USBFS_PROTOCOL_REPORT;
}
#endif /* USBFS_ENABLE_HID_CLASS */
/* Reset component internal variables. */
USBFS_transferState = USBFS_TRANS_STATE_IDLE;
USBFS_configurationChanged = 0u;
USBFS_configuration = 0u;
USBFS_interfaceNumber = 0u;
USBFS_deviceAddress = 0u;
USBFS_deviceStatus = 0u;
USBFS_lastPacketSize = 0u;
#if (CY_PSOC4)
/* Set EP0.CR: ACK Setup, NAK IN/OUT. */
USBFS_EP0_CR_REG = USBFS_MODE_NAK_IN_OUT;
#else
/* Set EP0.CR: ACK Setup, STALL IN/OUT. */
USBFS_EP0_CR_REG = USBFS_MODE_STALL_IN_OUT;
#endif /* (CY_PSOC4) */
/* Enable device to respond to USB traffic with address 0. */
USBFS_CR0_REG = USBFS_DEFUALT_CR0;
}
/*******************************************************************************
* Function Name: USBFS_Stop
****************************************************************************//**
*
* This function shuts down the USB function including to release
* the D+ pull-up and disabling the SIE.
*
* \globalvars
* \ref USBFS_configuration
*
* USBFS_deviceAddress - Contains the current device address. This
* variable is initialized to zero in this API. The Host starts to communicate
* to the device with address 0 and then sets it to a whatever value using
* a SET_ADDRESS request.
*
* \ref USBFS_deviceStatus
*
* \ref USBFS_configurationChanged
*
* USBFS_intiVar - This variable is set to zero
*
*******************************************************************************/
void USBFS_Stop(void)
{
uint8 enableInterrupts;
#if (USBFS_EP_MANAGEMENT_DMA)
/* Stop all DMA channels. */
USBFS_Stop_DMA(USBFS_MAX_EP);
#endif /* (USBFS_EP_MANAGEMENT_DMA) */
enableInterrupts = CyEnterCriticalSection();
/* Disable USB IP to respond to USB traffic. */
USBFS_CR0_REG &= (uint8) ~USBFS_CR0_ENABLE;
/* Disable D+ pull-up. */
USBFS_USBIO_CR1_REG &= (uint8) ~ USBFS_USBIO_CR1_USBPUEN;
#if (CY_PSOC4)
/* Disable USBFS block. */
USBFS_POWER_CTRL_REG &= (uint32) ~USBFS_POWER_CTRL_ENABLE;
#else
/* Clear power active and standby mode templates. */
USBFS_PM_ACT_CFG_REG &= (uint8) ~USBFS_PM_ACT_EN_FSUSB;
USBFS_PM_STBY_CFG_REG &= (uint8) ~USBFS_PM_STBY_EN_FSUSB;
/* Ensure single-ended disable bits are high (PRT15.INP_DIS[7:6])
* (input receiver disabled). */
USBFS_DM_INP_DIS_REG |= (uint8) USBFS_DM_MASK;
USBFS_DP_INP_DIS_REG |= (uint8) USBFS_DP_MASK;
#endif /* (CY_PSOC4) */
CyExitCriticalSection(enableInterrupts);
/* Disable component interrupts. */
#if (CY_PSOC4)
CyIntDisable(USBFS_INTR_HI_VECT_NUM);
CyIntDisable(USBFS_INTR_LO_VECT_NUM);
CyIntDisable(USBFS_INTR_MED_VECT_NUM);
#else
CyIntDisable(USBFS_BUS_RESET_VECT_NUM);
CyIntDisable(USBFS_EP_0_VECT_NUM);
#if (USBFS_SOF_ISR_ACTIVE)
CyIntDisable(USBFS_SOF_VECT_NUM);
#endif /* (USBFS_SOF_ISR_ACTIVE) */
#if (USBFS_EP1_ISR_ACTIVE)
CyIntDisable(USBFS_EP_1_VECT_NUM);
#endif /* (USBFS_EP1_ISR_ACTIVE) */
#if (USBFS_EP2_ISR_ACTIVE)
CyIntDisable(USBFS_EP_2_VECT_NUM);
#endif /* (USBFS_EP2_ISR_ACTIVE) */
#if (USBFS_EP3_ISR_ACTIVE)
CyIntDisable(USBFS_EP_3_VECT_NUM);
#endif /* (USBFS_EP3_ISR_ACTIVE) */
#if (USBFS_EP4_ISR_ACTIVE)
CyIntDisable(USBFS_EP_4_VECT_NUM);
#endif /* (USBFS_EP4_ISR_ACTIVE) */
#if (USBFS_EP5_ISR_ACTIVE)
CyIntDisable(USBFS_EP_5_VECT_NUM);
#endif /* (USBFS_EP5_ISR_ACTIVE) */
#if (USBFS_EP6_ISR_ACTIVE)
CyIntDisable(USBFS_EP_6_VECT_NUM);
#endif /* USBFS_EP6_ISR_REMOVE */
#if (USBFS_EP7_ISR_ACTIVE)
CyIntDisable(USBFS_EP_7_VECT_NUM);
#endif /* (USBFS_EP7_ISR_ACTIVE) */
#if (USBFS_EP8_ISR_ACTIVE)
CyIntDisable(USBFS_EP_8_VECT_NUM);
#endif /* (USBFS_EP8_ISR_ACTIVE) */
#if (USBFS_DP_ISR_ACTIVE)
/* Clear active mode Dp interrupt source history. */
(void) USBFS_Dp_ClearInterrupt();
CyIntClearPending(USBFS_DP_INTC_VECT_NUM);
#endif /* (USBFS_DP_ISR_ACTIVE). */
#endif /* (CY_PSOC4) */
/* Reset component internal variables. */
USBFS_configurationChanged = 0u;
USBFS_configuration = 0u;
USBFS_interfaceNumber = 0u;
USBFS_deviceAddress = 0u;
USBFS_deviceStatus = 0u;
/* It is mandatory for correct device startup. */
USBFS_initVar = 0u;
}
/*******************************************************************************
* Function Name: USBFS_CheckActivity
****************************************************************************//**
*
* This function returns the activity status of the bus. It clears the hardware
* status to provide updated status on the next call of this function. It
* provides a way to determine whether any USB bus activity occurred. The
* application should use this function to determine if the USB suspend
* conditions are met.
*
*
* \return
* cystatus: Status of the bus since the last call of the function.
* Return Value | Description
* -------------|---------------------------------------------------------------
* 1 |Bus activity was detected since the last call to this function
* 0 |Bus activity was not detected since the last call to this function
*
*
*******************************************************************************/
uint8 USBFS_CheckActivity(void)
{
uint8 cr1Reg = USBFS_CR1_REG;
/* Clear bus activity. */
USBFS_CR1_REG = (cr1Reg & (uint8) ~USBFS_CR1_BUS_ACTIVITY);
/* Get bus activity. */
return ((0u != (cr1Reg & USBFS_CR1_BUS_ACTIVITY)) ? (1u) : (0u));
}
/*******************************************************************************
* Function Name: USBFS_GetConfiguration
****************************************************************************//**
*
* This function gets the current configuration of the USB device.
*
* \return
* Returns the currently assigned configuration. Returns 0 if the device
* is not configured
*
*******************************************************************************/
uint8 USBFS_GetConfiguration(void)
{
return (USBFS_configuration);
}
/*******************************************************************************
* Function Name: USBFS_IsConfigurationChanged
****************************************************************************//**
*
* This function returns the clear-on-read configuration state. It is useful
* when the host sends double SET_CONFIGURATION request with the same
* configuration number or changes alternate settings of the interface.
* After configuration has been changed the OUT endpoints must be enabled and IN
* endpoint must be loaded with data to start communication with the host.
*
* \return
* None-zero value when new configuration has been changed, otherwise zero is
* returned.
*
* \globalvars
*
* \ref USBFS_configurationChanged - This variable is set to 1 after
* a SET_CONFIGURATION request and cleared in this function.
*
*******************************************************************************/
uint8 USBFS_IsConfigurationChanged(void)
{
uint8 res = 0u;
if (USBFS_configurationChanged != 0u)
{
res = USBFS_configurationChanged;
USBFS_configurationChanged = 0u;
}
return (res);
}
/*******************************************************************************
* Function Name: USBFS_GetInterfaceSetting
****************************************************************************//**
*
* This function gets the current alternate setting for the specified interface.
* It is useful to identify which alternate settings are active in the specified
* interface.
*
* \param
* interfaceNumber interface number
*
* \return
* Returns the current alternate setting for the specified interface.
*
*******************************************************************************/
uint8 USBFS_GetInterfaceSetting(uint8 interfaceNumber)
{
return (USBFS_interfaceSetting[interfaceNumber]);
}
/*******************************************************************************
* Function Name: USBFS_GetEPState
****************************************************************************//**
*
* This function returns the state of the requested endpoint.
*
* \param epNumber Data endpoint number
*
* \return
* Returns the current state of the specified USBFS endpoint. Symbolic names and
* their associated values are given in the following table. Use these constants
* whenever you write code to change the state of the endpoints, such as ISR
* code, to handle data sent or received.
*
* Return Value | Description
* -----------------------|-----------------------------------------------------
* USBFS_NO_EVENT_PENDING |The endpoint is awaiting SIE action
* USBFS_EVENT_PENDING |The endpoint is awaiting CPU action
* USBFS_NO_EVENT_ALLOWED |The endpoint is locked from access
* USBFS_IN_BUFFER_FULL |The IN endpoint is loaded and the mode is set to ACK IN
* USBFS_IN_BUFFER_EMPTY |An IN transaction occurred and more data can be loaded
* USBFS_OUT_BUFFER_EMPTY |The OUT endpoint is set to ACK OUT and is waiting for data
* USBFS_OUT_BUFFER_FULL |An OUT transaction has occurred and data can be read
*
*******************************************************************************/
uint8 USBFS_GetEPState(uint8 epNumber)
{
return (USBFS_EP[epNumber].apiEpState);
}
/*******************************************************************************
* Function Name: USBFS_GetEPCount
****************************************************************************//**
*
* This function supports Data Endpoints only(EP1-EP8).
* Returns the transfer count for the requested endpoint. The value from
* the count registers includes 2 counts for the two byte checksum of the
* packet. This function subtracts the two counts.
*
* \param epNumber Data Endpoint Number.
* Valid values are between 1 and 8.
*
* \return
* Returns the current byte count from the specified endpoint or 0 for an
* invalid endpoint.
*
*******************************************************************************/
uint16 USBFS_GetEPCount(uint8 epNumber)
{
uint16 cntr = 0u;
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
/* Get 11-bits EP counter where epCnt0 - 3 bits MSB and epCnt1 - 8 bits LSB. */
cntr = ((uint16) USBFS_SIE_EP_BASE.sieEp[epNumber].epCnt0) & USBFS_EPX_CNT0_MASK;
cntr = ((uint16) (cntr << 8u)) | ((uint16) USBFS_SIE_EP_BASE.sieEp[epNumber].epCnt1);
cntr -= USBFS_EPX_CNTX_CRC_COUNT;
}
return (cntr);
}
#if (USBFS_EP_MANAGEMENT_DMA)
#if (CY_PSOC4)
/*******************************************************************************
* Function Name: USBFS_InitEpDma
****************************************************************************//**
*
* This function configures priority for all DMA channels utilized by the
* component. Also sets callbacks for DMA auto mode.
*
*******************************************************************************/
static void USBFS_InitEpDma(void)
{
#if (USBFS_DMA1_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep1_dma_CHANNEL] = USBFS_ep1_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA1_ACTIVE) */
#if (USBFS_DMA2_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep2_dma_CHANNEL] = USBFS_ep2_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA2_ACTIVE) */
#if (USBFS_DMA3_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep3_dma_CHANNEL] = USBFS_ep3_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA3_ACTIVE) */
#if (USBFS_DMA4_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep4_dma_CHANNEL] = USBFS_ep4_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA4_ACTIVE) */
#if (USBFS_DMA5_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep5_dma_CHANNEL] = USBFS_ep5_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA5_ACTIVE) */
#if (USBFS_DMA6_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep6_dma_CHANNEL] = USBFS_ep6_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA6_ACTIVE) */
#if (USBFS_DMA7_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep7_dma_CHANNEL] = USBFS_ep7_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA7_ACTIVE) */
#if (USBFS_DMA8_ACTIVE)
CYDMA_CH_CTL_BASE.ctl[USBFS_ep8_dma_CHANNEL] = USBFS_ep8_dma_CHANNEL_CFG;
#endif /* (USBFS_DMA8_ACTIVE) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
/* Initialize DMA channel callbacks. */
#if (USBFS_DMA1_ACTIVE)
(void) USBFS_ep1_dma_SetInterruptCallback(&USBFS_EP1_DMA_DONE_ISR);
#endif /* (USBFS_DMA1_ACTIVE) */
#if (USBFS_DMA2_ACTIVE)
(void) USBFS_ep2_dma_SetInterruptCallback(&USBFS_EP2_DMA_DONE_ISR);
#endif /* (USBFS_DMA2_ACTIVE) */
#if (USBFS_DMA3_ACTIVE)
(void) USBFS_ep3_dma_SetInterruptCallback(&USBFS_EP3_DMA_DONE_ISR);
#endif /* (USBFS_DMA3_ACTIVE) */
#if (USBFS_DMA4_ACTIVE)
(void) USBFS_ep4_dma_SetInterruptCallback(&USBFS_EP4_DMA_DONE_ISR);
#endif /* (USBFS_DMA4_ACTIVE) */
#if (USBFS_DMA5_ACTIVE)
(void) USBFS_ep5_dma_SetInterruptCallback(&USBFS_EP5_DMA_DONE_ISR);
#endif /* (USBFS_DMA5_ACTIVE) */
#if (USBFS_DMA6_ACTIVE)
(void) USBFS_ep6_dma_SetInterruptCallback(&USBFS_EP6_DMA_DONE_ISR);
#endif /* (USBFS_DMA6_ACTIVE) */
#if (USBFS_DMA7_ACTIVE)
(void) USBFS_ep7_dma_SetInterruptCallback(&USBFS_EP7_DMA_DONE_ISR);
#endif /* (USBFS_DMA7_ACTIVE) */
#if (USBFS_DMA8_ACTIVE)
(void) USBFS_ep8_dma_SetInterruptCallback(&USBFS_EP8_DMA_DONE_ISR);
#endif /* (USBFS_DMA8_ACTIVE) */
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
}
#else
/***************************************************************************
* Function Name: USBFS_InitEP_DMA
************************************************************************//**
*
* This function allocates and initializes a DMA channel to be used by the
* USBFS_LoadInEP() or USBFS_ReadOutEP() APIs for data
* transfer. It is available when the Endpoint Memory Management parameter
* is set to DMA.
*
* This function is automatically called from the USBFS_LoadInEP() and USBFS_ReadOutEP() APIs.
*
* \param epNumber Contains the data endpoint number.
* Valid values are between 1 and 8.
* \param *pData Pointer to a data array that is related to the EP transfers.
*
* \reentrant No.
*
***************************************************************************/
void USBFS_InitEP_DMA(uint8 epNumber, const uint8 *pData)
{
uint16 src;
uint16 dst;
#if (CY_PSOC3)
src = HI16(CYDEV_SRAM_BASE);
dst = HI16(CYDEV_PERIPH_BASE);
pData = pData;
#else
if ((USBFS_EP[epNumber].addr & USBFS_DIR_IN) != 0u)
{
/* IN endpoint: source is memory buffer. */
src = HI16(pData);
dst = HI16(CYDEV_PERIPH_BASE);
}
else
{
/* OUT endpoint: source is USB IP memory buffer. */
src = HI16(CYDEV_PERIPH_BASE);
dst = HI16(pData);
}
#endif /* (CY_PSOC3) */
switch(epNumber)
{
#if (USBFS_DMA1_ACTIVE)
case USBFS_EP1:
USBFS_DmaChan[epNumber] = USBFS_ep1_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA1_ACTIVE) */
#if (USBFS_DMA2_ACTIVE)
case USBFS_EP2:
USBFS_DmaChan[epNumber] = USBFS_ep2_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA2_ACTIVE) */
#if (USBFS_DMA3_ACTIVE)
case USBFS_EP3:
USBFS_DmaChan[epNumber] = USBFS_ep3_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA3_ACTIVE) */
#if (USBFS_DMA4_ACTIVE)
case USBFS_EP4:
USBFS_DmaChan[epNumber] = USBFS_ep4_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA4_ACTIVE) */
#if (USBFS_DMA5_ACTIVE)
case USBFS_EP5:
USBFS_DmaChan[epNumber] = USBFS_ep5_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA5_ACTIVE) */
#if (USBFS_DMA6_ACTIVE)
case USBFS_EP6:
USBFS_DmaChan[epNumber] = USBFS_ep6_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA6_ACTIVE) */
#if (USBFS_DMA7_ACTIVE)
case USBFS_EP7:
USBFS_DmaChan[epNumber] = USBFS_ep7_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA7_ACTIVE) */
#if (USBFS_DMA8_ACTIVE)
case USBFS_EP8:
USBFS_DmaChan[epNumber] = USBFS_ep8_DmaInitialize(USBFS_DMA_BYTES_PER_BURST,
USBFS_DMA_REQUEST_PER_BURST, src, dst);
break;
#endif /* (USBFS_DMA8_ACTIVE) */
default:
/* Do nothing for endpoints other than 1-8. */
break;
}
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
USBFS_DmaTd[epNumber] = CyDmaTdAllocate();
#if (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u))
USBFS_DmaNextTd[epNumber] = CyDmaTdAllocate();
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u)) */
}
}
#endif /* (CY_PSOC4) */
/***************************************************************************
* Function Name: USBFS_Stop_DMA
************************************************************************//**
*
* This function stops DMA channel associated with endpoint. It is available
* when the Endpoint Buffer Management parameter is set to DMA. Call this
* function when endpoint direction is changed from IN to OUT or vice versa
* to trigger DMA re-configuration when USBFS_LoadInEP() or
* USBFS_ReadOutEP() functions are called the first time.
*
* \param epNumber: The data endpoint number for which associated DMA
* channel is stopped. The range of valid values is between 1 and 8. To stop
* all DMAs associated with endpoints call this function with
* USBFS_MAX_EP argument.
*
* \reentrant
* No.
*
***************************************************************************/
void USBFS_Stop_DMA(uint8 epNumber)
{
uint8 i;
i = (epNumber < USBFS_MAX_EP) ? epNumber : USBFS_EP1;
do
{
#if (CY_PSOC4)
if (0u != USBFS_DmaChan[i])
{
USBFS_CyDmaChDisable(USBFS_DmaChan[i]);
}
#else
if(USBFS_DmaTd[i] != DMA_INVALID_TD)
{
(void) CyDmaChDisable(USBFS_DmaChan[i]);
CyDmaTdFree(USBFS_DmaTd[i]);
USBFS_DmaTd[i] = DMA_INVALID_TD;
}
#if (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u))
if(USBFS_DmaNextTd[i] != DMA_INVALID_TD)
{
CyDmaTdFree(USBFS_DmaNextTd[i]);
USBFS_DmaNextTd[i] = DMA_INVALID_TD;
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u)) */
#endif /* (CY_PSOC4) */
i++;
}
while ((i < USBFS_MAX_EP) && (epNumber == USBFS_MAX_EP));
}
#endif /* (USBFS_EP_MANAGEMENT_DMA) */
#if (CY_PSOC3 || CY_PSOC5)
#if (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u))
/***************************************************************************
* Function Name: USBFS_LoadNextInEP
************************************************************************//**
*
* Summary:
* This internal function is used for IN endpoint DMA reconfiguration in
* Auto DMA mode.
*
* Parameters:
* epNumber: Contains the data endpoint number.
* mode: 0 - Configure DMA to send the the rest of data.
* 1 - Configure DMA to repeat 2 last bytes of the first burst.
*
***************************************************************************/
void USBFS_LoadNextInEP(uint8 epNumber, uint8 mode)
{
reg16 *convert;
if (mode == 0u)
{
/* Configure DMA to send rest of data. */
/* CyDmaTdSetConfiguration API is optimized to change transfer length only and configure TD. */
convert = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[USBFS_DmaTd[epNumber]].TD0[0u];
/* Set transfer length. */
CY_SET_REG16(convert, USBFS_inLength[epNumber] - USBFS_DMA_BYTES_PER_BURST);
/* CyDmaTdSetAddress API is optimized to change source address only. */
convert = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[USBFS_DmaTd[epNumber]].TD1[0u];
CY_SET_REG16(convert, LO16((uint32)USBFS_inDataPointer[epNumber] +
USBFS_DMA_BYTES_PER_BURST));
USBFS_inBufFull[epNumber] = 1u;
}
else
{
/* Configure DMA to repeat 2 last bytes of the first burst. */
/* CyDmaTdSetConfiguration API is optimized to change transfer length only and configure TD. */
convert = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[USBFS_DmaTd[epNumber]].TD0[0u];
/* Set transfer length. */
CY_SET_REG16(convert, USBFS_DMA_BYTES_REPEAT);
/* CyDmaTdSetAddress API is optimized to change source address only. */
convert = (reg16 *) &CY_DMA_TDMEM_STRUCT_PTR[USBFS_DmaTd[epNumber]].TD1[0u];
CY_SET_REG16(convert, LO16((uint32)USBFS_inDataPointer[epNumber] +
(USBFS_DMA_BYTES_PER_BURST - USBFS_DMA_BYTES_REPEAT)));
}
/* CyDmaChSetInitialTd API is optimized to initialize TD. */
CY_DMA_CH_STRUCT_PTR[USBFS_DmaChan[epNumber]].basic_status[1u] = USBFS_DmaTd[epNumber];
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO && (USBFS_EP_DMA_AUTO_OPT == 0u)) */
#endif /* (CY_PSOC3 || CY_PSOC5) */
/*******************************************************************************
* Function Name: USBFS_LoadInEP
****************************************************************************//**
*
* This function performs different functionality depending on the Components
* configured Endpoint Buffer Management. This parameter is defined in
* the Descriptor Root in Component Configure window.
*
* *Manual (Static/Dynamic Allocation):*
* This function loads and enables the specified USB data endpoint for an IN
* data transfer.
*
* *DMA with Manual Buffer Management:*
* Configures DMA for a data transfer from system RAM to endpoint buffer.
* Generates request for a transfer.
*
* *DMA with Automatic Buffer Management:*
* Configures DMA. This is required only once, so it is done only when parameter
* pData is not NULL. When the pData pointer is NULL, the function skips this
* task. Sets Data ready status: This generates the first DMA transfer and
* prepares data in endpoint buffer.
*
* \param epNumber Contains the data endpoint number.
* Valid values are between 1 and 8.
* \param *pData A pointer to a data array from which the data for the endpoint space
* is loaded.
* \param length The number of bytes to transfer from the array and then send as
* a result of an IN request. Valid values are between 0 and 512
* (1023 for DMA with Automatic Buffer Management mode). The value 512
* is applicable if only one endpoint is used.
*
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_LoadInEP(uint8 epNumber, const uint8 pData[], uint16 length)
{
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
#if (!USBFS_EP_MANAGEMENT_DMA_AUTO)
/* Limit length to available buffer USB IP buffer size.*/
if (length > (USBFS_EPX_DATA_BUF_MAX - USBFS_EP[epNumber].buffOffset))
{
length = USBFS_EPX_DATA_BUF_MAX - USBFS_EP[epNumber].buffOffset;
}
#endif /* (!USBFS_EP_MANAGEMENT_DMA_AUTO) */
/* Set count and data toggle. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCnt0 = (uint8) HI8(length) | USBFS_EP[epNumber].epToggle;
USBFS_SIE_EP_BASE.sieEp[epNumber].epCnt1 = (uint8) LO8(length);
#if (USBFS_EP_MANAGEMENT_MANUAL)
if (NULL != pData)
{
/* Copy data using arbiter data register. */
uint16 i;
for (i = 0u; i < length; ++i)
{
USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr = pData[i];
}
}
/* IN endpoint buffer is full - read to be read. */
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
/* Arm IN endpoint. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
#else
#if (CY_PSOC3 || CY_PSOC5LP)
/* Initialize DMA if it was not initialized. */
if (DMA_INVALID_TD == USBFS_DmaTd[epNumber])
{
USBFS_InitEP_DMA(epNumber, pData);
}
#endif /* (CY_PSOC3 || CY_PSOC5LP) */
#if (USBFS_EP_MANAGEMENT_DMA_MANUAL)
/* IN endpoint buffer will be fully loaded by DMA shortly. */
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
if ((pData != NULL) && (length > 0u))
{
#if (CY_PSOC4)
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Configure source and destination. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) pData);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr);
/* Configure DMA descriptor. */
--length;
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG | length |
CYDMA_BYTE | CYDMA_ELEMENT_WORD | CYDMA_INC_SRC_ADDR | CYDMA_INVALIDATE | CYDMA_PREEMPTABLE);
/* Validate descriptor to execute on following DMA request. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
#else
/* Configure DMA to transfer data. */
(void) CyDmaChDisable(USBFS_DmaChan[epNumber]);
(void) CyDmaTdSetConfiguration(USBFS_DmaTd[epNumber], length, CY_DMA_DISABLE_TD, TD_TERMIN_EN | TD_INC_SRC_ADR);
(void) CyDmaTdSetAddress(USBFS_DmaTd[epNumber], LO16((uint32) pData), LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr));
/* Enable DMA channel. */
(void) CyDmaChSetInitialTd(USBFS_DmaChan[epNumber], USBFS_DmaTd[epNumber]);
(void) CyDmaChEnable(USBFS_DmaChan[epNumber], 1u);
#endif /* (CY_PSOC4) */
/* Generate DMA request. */
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg |= (uint8) USBFS_ARB_EPX_CFG_DMA_REQ;
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg &= (uint8) ~USBFS_ARB_EPX_CFG_DMA_REQ;
/* IN endpoint will be armed in ARB_ISR(source: IN_BUF_FULL) after first DMA transfer has been completed. */
}
else
{
/* When zero-length packet: arm IN endpoint directly. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_MANUAL) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
if (pData != NULL)
{
#if (CY_PSOC4)
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Store address of buffer. */
USBFS_DmaEpBufferAddrBackup[epNumber] = (uint32) pData;
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Set destination address. */
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR1, (void*) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG |
CYDMA_BYTE | CYDMA_ELEMENT_WORD | CYDMA_INC_SRC_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR1, USBFS_DMA_COMMON_CFG |
CYDMA_BYTE | CYDMA_ELEMENT_WORD | CYDMA_INC_SRC_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Enable interrupt from DMA channel. */
USBFS_CyDmaSetInterruptMask(channelNum);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
#else
(void) CyDmaChDisable(USBFS_DmaChan[epNumber]);
#if (USBFS_EP_DMA_AUTO_OPT == 0u)
USBFS_inLength[epNumber] = length;
USBFS_inDataPointer[epNumber] = pData;
/* Configure DMA to send data only for first burst */
(void) CyDmaTdSetConfiguration(USBFS_DmaTd[epNumber],
(length > USBFS_DMA_BYTES_PER_BURST) ? USBFS_DMA_BYTES_PER_BURST : length,
USBFS_DmaNextTd[epNumber], TD_TERMIN_EN | TD_INC_SRC_ADR);
(void) CyDmaTdSetAddress(USBFS_DmaTd[epNumber], LO16((uint32) pData),
LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr));
/* The second TD will be executed only when the first one fails.
* The intention of this TD is to generate NRQ interrupt
* and repeat 2 last bytes of the first burst.
*/
(void) CyDmaTdSetConfiguration(USBFS_DmaNextTd[epNumber], 1u,
USBFS_DmaNextTd[epNumber],
USBFS_epX_TD_TERMOUT_EN[epNumber]);
/* Configure DmaNextTd to clear Data Ready status. */
(void) CyDmaTdSetAddress(USBFS_DmaNextTd[epNumber], LO16((uint32) &clearInDataRdyStatus),
LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg));
#else
/* Configure DMA to send all data. */
(void) CyDmaTdSetConfiguration(USBFS_DmaTd[epNumber], length,
USBFS_DmaTd[epNumber], TD_TERMIN_EN | TD_INC_SRC_ADR);
(void) CyDmaTdSetAddress(USBFS_DmaTd[epNumber], LO16((uint32) pData),
LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr));
#endif /* (USBFS_EP_DMA_AUTO_OPT == 0u) */
/* Clear any potential pending DMA requests before starting DMA channel to transfer data. */
(void) CyDmaClearPendingDrq(USBFS_DmaChan[epNumber]);
/* Enable DMA. */
(void) CyDmaChSetInitialTd(USBFS_DmaChan[epNumber], USBFS_DmaTd[epNumber]);
(void) CyDmaChEnable(USBFS_DmaChan[epNumber], 1u);
#endif /* (CY_PSOC4) */
}
else
{
/* IN endpoint buffer (32 bytes) will shortly be preloaded by DMA. */
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
if (length > 0u)
{
#if (CY_PSOC4)
uint32 lengthDescr0, lengthDescr1;
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Get number of full bursts. */
USBFS_DmaEpBurstCnt[epNumber] = (uint8) (length / USBFS_DMA_BYTES_PER_BURST);
/* Get number of elements in the last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (uint8) (length % USBFS_DMA_BYTES_PER_BURST);
/* Get total number of bursts. */
USBFS_DmaEpBurstCnt[epNumber] += (0u != USBFS_DmaEpLastBurstEl[epNumber]) ? 1u : 0u;
/* Adjust number of data elements transferred in last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (0u != USBFS_DmaEpLastBurstEl[epNumber]) ?
(USBFS_DmaEpLastBurstEl[epNumber] - 1u) :
(USBFS_DMA_BYTES_PER_BURST - 1u);
/* Get number of data elements to transfer for descriptor 0 and 1. */
lengthDescr0 = (1u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_BYTES_PER_BURST - 1u);
lengthDescr1 = (2u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_BYTES_PER_BURST - 1u);
/* Mark which descriptor is last one to execute. */
USBFS_DmaEpLastBurstEl[epNumber] |= (0u != (USBFS_DmaEpBurstCnt[epNumber] & 0x1u)) ?
USBFS_DMA_DESCR0_MASK : USBFS_DMA_DESCR1_MASK;
/* Restore DMA settings for current transfer. */
USBFS_CyDmaChDisable(channelNum);
/* Restore destination address for input endpoint. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) ((uint32) USBFS_DmaEpBufferAddrBackup[epNumber]));
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR1, (void*) ((uint32) USBFS_DmaEpBufferAddrBackup[epNumber] +
USBFS_DMA_BYTES_PER_BURST));
/* Set number of elements to transfer. */
USBFS_CyDmaSetNumDataElements(channelNum, USBFS_DMA_DESCR0, lengthDescr0);
USBFS_CyDmaSetNumDataElements(channelNum, USBFS_DMA_DESCR1, lengthDescr1);
/* Validate descriptor 0 and command to start with it. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
USBFS_CyDmaSetDescriptor0Next(channelNum);
/* Validate descriptor 1. */
if (USBFS_DmaEpBurstCnt[epNumber] > 1u)
{
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR1);
}
/* Adjust burst counter taking to account: 2 valid descriptors and interrupt trigger after valid descriptor were executed. */
USBFS_DmaEpBurstCnt[epNumber] = USBFS_DMA_GET_BURST_CNT(USBFS_DmaEpBurstCnt[epNumber]);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
#elif (USBFS_EP_DMA_AUTO_OPT == 0u)
USBFS_inLength[epNumber] = length;
USBFS_inBufFull[epNumber] = 0u;
(void) CyDmaChDisable(USBFS_DmaChan[epNumber]);
/* Configure DMA to send data only for first burst. */
(void) CyDmaTdSetConfiguration(
USBFS_DmaTd[epNumber], (length > USBFS_DMA_BYTES_PER_BURST) ?
USBFS_DMA_BYTES_PER_BURST : length,
USBFS_DmaNextTd[epNumber], TD_TERMIN_EN | TD_INC_SRC_ADR );
(void) CyDmaTdSetAddress(USBFS_DmaTd[epNumber], LO16((uint32) USBFS_inDataPointer[epNumber]),
LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr));
/* Clear Any potential pending DMA requests before starting DMA channel to transfer data. */
(void) CyDmaClearPendingDrq(USBFS_DmaChan[epNumber]);
/* Enable DMA. */
(void) CyDmaChSetInitialTd(USBFS_DmaChan[epNumber], USBFS_DmaTd[epNumber]);
(void) CyDmaChEnable(USBFS_DmaChan[epNumber], 1u);
#endif /* (CY_PSOC4) */
#if !defined (USBFS_MANUAL_IN_EP_ARM)
/* Set IN data ready to generate DMA request to load data into endpoint buffer. */
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg |= USBFS_ARB_EPX_CFG_IN_DATA_RDY;
#endif /* (USBFS_MANUAL_IN_EP_ARM) */
/* IN endpoint will be armed in ARB_ISR(source: IN_BUF_FULL) after first DMA transfer has been completed. */
}
else
{
/* When zero-length packet: arm IN endpoint directly. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
}
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
#endif /* (USBFS_EP_MANAGEMENT_MANUAL) */
}
}
/*******************************************************************************
* Function Name: USBFS_ReadOutEP
****************************************************************************//**
*
* This function performs different functionality depending on the Components
* configured Endpoint Buffer Management. This parameter is defined in the
* Descriptor Root in Component Configure window.
*
* *Manual (Static/Dynamic Allocation):*
* This function moves the specified number of bytes from endpoint buffer to
* system RAM. The number of bytes actually transferred from endpoint buffer to
* system RAM is the lesser of the actual number of bytes sent by the host or
* the number of bytes requested by the length parameter.
*
* *DMA with Manual Buffer Management:*
* Configure DMA to transfer data from endpoint buffer to system RAM. Generate
* a DMA request. The firmware must wait until the DMA completes the data
* transfer after calling the USBFS_ReadOutEP() API. For example,
* by checking EPstate:
*
* \snippet /USBFS_sut_02.cydsn/main.c checking EPstatey
*
* The USBFS_EnableOutEP() has to be called to allow host to write data into
* the endpoint buffer after DMA has completed transfer data from OUT endpoint
* buffer to SRAM.
*
* *DMA with Automatic Buffer Management:*
* Configure DMA. This is required only once and automatically generates DMA
* requests as data arrives
*
* \param epNumber: Contains the data endpoint number.
* Valid values are between 1 and 8.
* \param pData: A pointer to a data array from which the data for the endpoint
* space is loaded.
* \param length: The number of bytes to transfer from the USB Out endpoint and
* loads it into data array. Valid values are between 0 and 1023. The
* function moves fewer than the requested number of bytes if the host
* sends fewer bytes than requested.
*
* \return
* Number of bytes received, 0 for an invalid endpoint.
*
* \reentrant
* No.
*
*******************************************************************************/
uint16 USBFS_ReadOutEP(uint8 epNumber, uint8 pData[], uint16 length)
{
if ((pData != NULL) && (epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
#if (!USBFS_EP_MANAGEMENT_DMA_AUTO)
/* Adjust requested length to available data. */
length = (length > USBFS_GetEPCount(epNumber)) ? USBFS_GetEPCount(epNumber) : length;
#endif /* (!USBFS_EP_MANAGEMENT_DMA_AUTO) */
#if (USBFS_EP_MANAGEMENT_MANUAL)
{
/* Copy data using arbiter data register. */
uint16 i;
for (i = 0u; i < length; ++i)
{
pData[i] = (uint8) USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr;
}
}
/* Arm OUT endpoint after data has been copied from endpoint buffer. */
USBFS_EnableOutEP(epNumber);
#else
#if (CY_PSOC3 || CY_PSOC5LP)
/* Initialize DMA if it was not initialized. */
if (DMA_INVALID_TD == USBFS_DmaTd[epNumber])
{
USBFS_InitEP_DMA(epNumber, pData);
}
#endif /* (CY_PSOC3 || CY_PSOC5LP) */
#if (USBFS_EP_MANAGEMENT_DMA_MANUAL)
#if (CY_PSOC4)
{
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Configure source and destination. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) pData);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG | (uint16)(length - 1u) |
CYDMA_BYTE | CYDMA_WORD_ELEMENT | CYDMA_INC_DST_ADDR | CYDMA_INVALIDATE | CYDMA_PREEMPTABLE);
/* Validate descriptor to execute on following DMA request. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
}
#else
/* Configure DMA to transfer data. */
(void) CyDmaChDisable(USBFS_DmaChan[epNumber]);
(void) CyDmaTdSetConfiguration(USBFS_DmaTd[epNumber], length, CY_DMA_DISABLE_TD, TD_TERMIN_EN | TD_INC_DST_ADR);
(void) CyDmaTdSetAddress(USBFS_DmaTd[epNumber], LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr), LO16((uint32)pData));
/* Enable DMA channel. */
(void) CyDmaChSetInitialTd(USBFS_DmaChan[epNumber], USBFS_DmaTd[epNumber]);
(void) CyDmaChEnable(USBFS_DmaChan[epNumber], 1u);
#endif /* (CY_PSOC4) */
/* Generate DMA request. */
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg |= (uint8) USBFS_ARB_EPX_CFG_DMA_REQ;
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg &= (uint8) ~USBFS_ARB_EPX_CFG_DMA_REQ;
/* OUT endpoint has to be armed again by user when DMA transfers have been completed.
* NO_EVENT_PENDING: notifies that data has been copied from endpoint buffer.
*/
#endif /* (USBFS_EP_MANAGEMENT_DMA_MANUAL) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
#if (CY_PSOC4)
{
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
uint32 lengthDescr0, lengthDescr1;
/* Get number of full bursts. */
USBFS_DmaEpBurstCnt[epNumber] = (uint8) (length / USBFS_DMA_BYTES_PER_BURST);
/* Get number of elements in the last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (uint8) (length % USBFS_DMA_BYTES_PER_BURST);
/* Get total number of bursts. */
USBFS_DmaEpBurstCnt[epNumber] += (0u != USBFS_DmaEpLastBurstEl[epNumber]) ? 1u : 0u;
/* Adjust number of the data elements transfered in last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (0u != USBFS_DmaEpLastBurstEl[epNumber]) ?
(USBFS_DmaEpLastBurstEl[epNumber] - 1u) :
(USBFS_DMA_BYTES_PER_BURST - 1u);
/* Get number of data elements to transfer for descriptor 0 and 1. */
lengthDescr0 = (1u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_BYTES_PER_BURST - 1u);
lengthDescr1 = (2u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_BYTES_PER_BURST - 1u);
/* Mark if revert number of data elements in descriptor after transfer completion. */
USBFS_DmaEpLastBurstEl[epNumber] |= (USBFS_DmaEpBurstCnt[epNumber] > 2u) ? USBFS_DMA_DESCR_REVERT : 0u;
/* Mark last descriptor to be executed. */
USBFS_DmaEpLastBurstEl[epNumber] |= (0u != (USBFS_DmaEpBurstCnt[epNumber] & 0x1u)) ?
USBFS_DMA_DESCR0_MASK : USBFS_DMA_DESCR1_MASK;
/* Store address of buffer and burst counter for endpoint. */
USBFS_DmaEpBufferAddrBackup[epNumber] = (uint32) pData;
USBFS_DmaEpBurstCntBackup[epNumber] = USBFS_DmaEpBurstCnt[epNumber];
/* Adjust burst counter taking to account: 2 valid descriptors and interrupt trigger after valid descriptor were executed. */
USBFS_DmaEpBurstCnt[epNumber] = USBFS_DMA_GET_BURST_CNT(USBFS_DmaEpBurstCnt[epNumber]);
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Set destination address. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr);
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR1, (void*) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) ((uint32) pData));
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR1, (void*) ((uint32) pData + USBFS_DMA_BYTES_PER_BURST));
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG | lengthDescr0 |
CYDMA_BYTE | CYDMA_WORD_ELEMENT | CYDMA_INC_DST_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR1, USBFS_DMA_COMMON_CFG | lengthDescr1 |
CYDMA_BYTE | CYDMA_WORD_ELEMENT | CYDMA_INC_DST_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Enable interrupt from DMA channel. */
USBFS_CyDmaSetInterruptMask(channelNum);
/* Validate DMA descriptor 0 and 1. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
if (USBFS_DmaEpBurstCntBackup[epNumber] > 1u)
{
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR1);
}
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
}
#else
(void) CyDmaChDisable(USBFS_DmaChan[epNumber]);
(void) CyDmaTdSetConfiguration(USBFS_DmaTd[epNumber], length, USBFS_DmaTd[epNumber], TD_TERMIN_EN | TD_INC_DST_ADR);
(void) CyDmaTdSetAddress(USBFS_DmaTd[epNumber], LO16((uint32) &USBFS_ARB_EP_BASE.arbEp[epNumber].rwDr), LO16((uint32) pData));
/* Clear Any potential pending DMA requests before starting DMA channel to transfer data. */
(void) CyDmaClearPendingDrq(USBFS_DmaChan[epNumber]);
/* Enable DMA channel. */
(void) CyDmaChSetInitialTd(USBFS_DmaChan[epNumber], USBFS_DmaTd[epNumber]);
(void) CyDmaChEnable(USBFS_DmaChan[epNumber], 1u);
#endif /* (CY_PSOC4) */
/* OUT endpoint has to be armed again by user when DMA transfers have been completed.
* NO_EVENT_PENDING: notifies that data has been copied from endpoint buffer.
*/
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
#endif /* (USBFS_EP_MANAGEMENT_MANUAL) */
}
else
{
length = 0u;
}
return (length);
}
#if (USBFS_16BITS_EP_ACCESS_ENABLE)
/*******************************************************************************
* Function Name: USBFS_LoadInEP16
****************************************************************************//**
*
* This function performs different functionality depending on the Components
* configured Endpoint Buffer Management. This parameter is defined in
* the Descriptor Root in Component Configure window.
*
* *Manual (Static/Dynamic Allocation):*
* This function loads and enables the specified USB data endpoint for an IN
* data transfer.
*
* *DMA with Manual Buffer Management:*
* Configures DMA for a data transfer from system RAM to endpoint buffer.
* Generates request for a transfer.
*
* *DMA with Automatic Buffer Management:*
* Configures DMA. This is required only once, so it is done only when parameter
* pData is not NULL. When the pData pointer is NULL, the function skips this
* task. Sets Data ready status: This generates the first DMA transfer and
* prepares data in endpoint buffer.
*
* \param epNumber Contains the data endpoint number.
* Valid values are between 1 and 8.
* \param *pData A pointer to a data array from which the data for the endpoint
* space is loaded. It shall be ensured that this pointer address is even
* to ensure the 16-bit transfer is aligned to even address. Else, a hard
* fault condition can occur.
* \param length The number of bytes to transfer from the array and then send as
* a result of an IN request. Valid values are between 0 and 512 (1023 for
* DMA with Automatic Buffer Management mode). The value 512 is applicable
* if only one endpoint is used.
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_LoadInEP16(uint8 epNumber, const uint8 pData[], uint16 length)
{
/* Check array alignment on half-word boundary. */
CYASSERT(0u == (((uint32) pData) & 0x01u));
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
#if (!USBFS_EP_MANAGEMENT_DMA_AUTO)
/* Limit length to available buffer USB IP buffer size. */
if (length > (USBFS_EPX_DATA_BUF_MAX - USBFS_EP[epNumber].buffOffset))
{
length = USBFS_EPX_DATA_BUF_MAX - USBFS_EP[epNumber].buffOffset;
}
#endif /* (!USBFS_EP_MANAGEMENT_DMA_AUTO) */
/* Set count and data toggle. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCnt0 = (uint32) HI8(length) | USBFS_EP[epNumber].epToggle;
USBFS_SIE_EP_BASE.sieEp[epNumber].epCnt1 = (uint32) LO8(length);
/* Adjust requested length: 2 bytes are handled at one data register access. */
length += (length & 0x01u);
#if (USBFS_EP_MANAGEMENT_MANUAL)
if (NULL != pData)
{
/* Convert uint8 array to uint16. */
const uint16 *dataBuf = (uint16 *) pData;
/* Copy data using 16-bits arbiter data register. */
uint16 i;
for (i = 0u; i < (length >> 1u); ++i)
{
USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16 = dataBuf[i];
}
}
/* IN endpoint buffer is full - read to be read. */
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
/* Arm IN endpoint. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
#else
#if (USBFS_EP_MANAGEMENT_DMA_MANUAL)
/* IN endpoint buffer will be fully loaded by DMA shortly. */
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
if ((pData != NULL) && (length > 0u))
{
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Configure source and destination. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) pData);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16);
/* Configure DMA descriptor. */
length = (length >> 1u) - 1u;
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG | length |
CYDMA_HALFWORD | CYDMA_ELEMENT_WORD | CYDMA_INC_SRC_ADDR | CYDMA_INVALIDATE | CYDMA_PREEMPTABLE);
/* Validate descriptor to execute on following DMA request. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
/* Generate DMA request. */
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg |= (uint32) USBFS_ARB_EPX_CFG_DMA_REQ;
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg &= (uint32) ~USBFS_ARB_EPX_CFG_DMA_REQ;
/* IN endpoint will be armed in ARB_ISR(source: IN_BUF_FULL) after first DMA transfer has been completed. */
}
else
{
/* When zero-length packet: arm IN endpoint directly. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_MANUAL) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
if (pData != NULL)
{
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Store address of buffer. */
USBFS_DmaEpBufferAddrBackup[epNumber] = (uint32) pData;
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Set destination address. */
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR1, (void*) &USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG |
CYDMA_HALFWORD | CYDMA_ELEMENT_WORD | CYDMA_INC_SRC_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR1, USBFS_DMA_COMMON_CFG |
CYDMA_HALFWORD | CYDMA_ELEMENT_WORD | CYDMA_INC_SRC_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Enable interrupt from DMA channel. */
USBFS_CyDmaSetInterruptMask(channelNum);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
}
else
{
/* IN endpoint buffer (32 bytes) will shortly be preloaded by DMA. */
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
if (length > 0u)
{
uint32 lengthDescr0, lengthDescr1;
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Get number of full bursts. */
USBFS_DmaEpBurstCnt[epNumber] = (uint8) (length / USBFS_DMA_BYTES_PER_BURST);
/* Get number of elements in the last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (uint8) (length % USBFS_DMA_BYTES_PER_BURST);
/* Get total number of bursts. */
USBFS_DmaEpBurstCnt[epNumber] += (0u != USBFS_DmaEpLastBurstEl[epNumber]) ? 1u : 0u;
/* Adjust number of data elements transferred in last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (0u != USBFS_DmaEpLastBurstEl[epNumber]) ?
((USBFS_DmaEpLastBurstEl[epNumber] >> 1u) - 1u) :
(USBFS_DMA_HALFWORDS_PER_BURST - 1u);
/* Get number of data elements to transfer for descriptor 0 and 1. */
lengthDescr0 = (1u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_HALFWORDS_PER_BURST - 1u);
lengthDescr1 = (2u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_HALFWORDS_PER_BURST - 1u);
/* Mark which descriptor is last one to execute. */
USBFS_DmaEpLastBurstEl[epNumber] |= (0u != (USBFS_DmaEpBurstCnt[epNumber] & 0x1u)) ?
USBFS_DMA_DESCR0_MASK : USBFS_DMA_DESCR1_MASK;
/* Restore DMA settings for current transfer. */
USBFS_CyDmaChDisable(channelNum);
/* Restore destination address for input endpoint. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) ((uint32) USBFS_DmaEpBufferAddrBackup[epNumber]));
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR1, (void*) ((uint32) USBFS_DmaEpBufferAddrBackup[epNumber] +
USBFS_DMA_BYTES_PER_BURST));
/* Set number of elements to transfer. */
USBFS_CyDmaSetNumDataElements(channelNum, USBFS_DMA_DESCR0, lengthDescr0);
USBFS_CyDmaSetNumDataElements(channelNum, USBFS_DMA_DESCR1, lengthDescr1);
/* Validate descriptor 0 and command to start with it. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
USBFS_CyDmaSetDescriptor0Next(channelNum);
/* Validate descriptor 1. */
if (USBFS_DmaEpBurstCnt[epNumber] > 1u)
{
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR1);
}
/* Adjust burst counter taking to account: 2 valid descriptors and interrupt trigger after valid descriptor were executed. */
USBFS_DmaEpBurstCnt[epNumber] = USBFS_DMA_GET_BURST_CNT(USBFS_DmaEpBurstCnt[epNumber]);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
#if !defined (USBFS_MANUAL_IN_EP_ARM)
/* Set IN data ready to generate DMA request to load data into endpoint buffer. */
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg |= USBFS_ARB_EPX_CFG_IN_DATA_RDY;
#endif /* (USBFS_MANUAL_IN_EP_ARM) */
/* IN endpoint will be armed in ARB_ISR(source: IN_BUF_FULL) after first DMA transfer has been completed. */
}
else
{
/* When zero-length packet: arm IN endpoint directly. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
}
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
#endif /* (USBFS_EP_MANAGEMENT_MANUAL) */
}
}
/*******************************************************************************
* Function Name: USBFS_ReadOutEP16
****************************************************************************//**
*
* This function performs different functionality depending on the Components
* configured Endpoint Buffer Management. This parameter is defined in the
* Descriptor Root in Component Configure window.
*
* *Manual (Static/Dynamic Allocation):*
* This function moves the specified number of bytes from endpoint buffer to
* system RAM. The number of bytes actually transferred from endpoint buffer to
* system RAM is the lesser of the actual number of bytes sent by the host or
* the number of bytes requested by the length parameter.
*
* *DMA with Manual Buffer Management:*
* Configure DMA to transfer data from endpoint buffer to system RAM. Generate
* a DMA request. The firmware must wait until the DMA completes the data
* transfer after calling the USBFS_ReadOutEP() API. For example,
* by checking EPstate:
*
* \snippet /USBFS_sut_02.cydsn/main.c checking EPstatey
*
* The USBFS_EnableOutEP() has to be called to allow host to write data into
* the endpoint buffer after DMA has completed transfer data from OUT endpoint
* buffer to SRAM.
*
* *DMA with Automatic Buffer Management:*
* Configure DMA. This is required only once and automatically generates DMA
* requests as data arrives
*
* \param epNumber: Contains the data endpoint number.
* Valid values are between 1 and 8.
* \param pData: A pointer to a data array into which the data for the endpoint
* space is copied. It shall be ensured that this pointer address is
* even to ensure the 16-bit transfer is aligned to even address. Else,
* a hard fault condition can occur.
* \param length: The number of bytes to transfer from the USB Out endpoint and
* loads it into data array. Valid values are between 0 and 1023. The
* function moves fewer than the requested number of bytes if the host
* sends fewer bytes than requested.
*
* \return
* Number of bytes received, 0 for an invalid endpoint.
*
* \reentrant
* No.
*
*******************************************************************************/
uint16 USBFS_ReadOutEP16(uint8 epNumber, uint8 pData[], uint16 length)
{
uint32 adjLength;
/* Check array alignment on half-word boundary */
CYASSERT(0u == (((uint32) pData) & 0x01u));
if ((pData != NULL) && (epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
#if (!USBFS_EP_MANAGEMENT_DMA_AUTO)
/* Adjust requested length to available data. */
length = (length > USBFS_GetEPCount(epNumber)) ? USBFS_GetEPCount(epNumber) : length;
#endif /* (!USBFS_EP_MANAGEMENT_DMA_AUTO) */
/* Adjust requested length: 2 bytes are handled at one data register access. */
adjLength = length + ((uint32)length & 1u);
#if (USBFS_EP_MANAGEMENT_MANUAL)
{
/* Convert uint8 array to uint16. */
uint16 *dataBuf = (uint16 *) pData;
/* Copy data using 16-bits arbiter data register. */
uint16 i;
for (i = 0u; i < (adjLength >> 1u); ++i)
{
dataBuf[i] = (uint16) USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16;
}
}
/* Arm OUT endpoint after data has been read from endpoint buffer. */
USBFS_EnableOutEP(epNumber);
#else
#if (USBFS_EP_MANAGEMENT_DMA_MANUAL)
{
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Configure source and destination. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) pData);
/* Configure DMA descriptor. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG | (uint16)((adjLength >> 1u) - 1u) |
CYDMA_HALFWORD | CYDMA_WORD_ELEMENT | CYDMA_INC_DST_ADDR | CYDMA_INVALIDATE | CYDMA_PREEMPTABLE);
/* Validate descriptor to execute on following DMA request. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
/* Generate DMA request. */
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg |= (uint32) USBFS_ARB_EPX_CFG_DMA_REQ;
USBFS_ARB_EP_BASE.arbEp[epNumber].epCfg &= (uint32) ~USBFS_ARB_EPX_CFG_DMA_REQ;
/* OUT endpoint has to be armed again by user when DMA transfers have been completed.
* NO_EVENT_PENDING: notifies that data has been copied from endpoint buffer.
*/
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_MANUAL) */
#if (USBFS_EP_MANAGEMENT_DMA_AUTO)
{
uint32 lengthDescr0, lengthDescr1;
uint32 channelNum = (uint32) USBFS_DmaChan[epNumber];
/* Get number of full bursts. */
USBFS_DmaEpBurstCnt[epNumber] = (uint8) (adjLength / USBFS_DMA_BYTES_PER_BURST);
/* Get number of elements in last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (uint8) (adjLength % USBFS_DMA_BYTES_PER_BURST);
/* Get total number of bursts. */
USBFS_DmaEpBurstCnt[epNumber] += (0u != USBFS_DmaEpLastBurstEl[epNumber]) ? 1u : 0u;
/* Adjust number of data elements transferred in last burst. */
USBFS_DmaEpLastBurstEl[epNumber] = (0u != USBFS_DmaEpLastBurstEl[epNumber]) ?
((USBFS_DmaEpLastBurstEl[epNumber] >> 1u) - 1u) :
(USBFS_DMA_HALFWORDS_PER_BURST - 1u);
/* Get number of data elements to transfer for descriptor 0 and 1. */
lengthDescr0 = (1u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_HALFWORDS_PER_BURST - 1u);
lengthDescr1 = (2u == USBFS_DmaEpBurstCnt[epNumber]) ? USBFS_DmaEpLastBurstEl[epNumber] : (USBFS_DMA_HALFWORDS_PER_BURST - 1u);
/* Mark last descriptor to be executed. */
USBFS_DmaEpLastBurstEl[epNumber] |= (0u != (USBFS_DmaEpBurstCnt[epNumber] & 0x1u)) ?
USBFS_DMA_DESCR0_MASK : USBFS_DMA_DESCR1_MASK;
/* Mark if revert number of data elements in descriptor after transfer completion. */
USBFS_DmaEpLastBurstEl[epNumber] |= (USBFS_DmaEpBurstCnt[epNumber] > 2u) ? USBFS_DMA_DESCR_REVERT : 0u;
/* Mark that 16-bits access to data register is performed. */
USBFS_DmaEpLastBurstEl[epNumber] |= USBFS_DMA_DESCR_16BITS;
/* Store address of buffer and burst counter for endpoint. */
USBFS_DmaEpBufferAddrBackup[epNumber] = (uint32) pData;
USBFS_DmaEpBurstCntBackup[epNumber] = USBFS_DmaEpBurstCnt[epNumber];
/* Adjust burst counter taking to account: 2 valid descriptors and interrupt trigger after valid descriptor were executed. */
USBFS_DmaEpBurstCnt[epNumber] = USBFS_DMA_GET_BURST_CNT(USBFS_DmaEpBurstCnt[epNumber]);
/* Disable DMA channel: start configuration. */
USBFS_CyDmaChDisable(channelNum);
/* Set destination address. */
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR0, (void*) &USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16);
USBFS_CyDmaSetSrcAddress(channelNum, USBFS_DMA_DESCR1, (void*) &USBFS_ARB_EP16_BASE.arbEp[epNumber].rwDr16);
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR0, (void*) ((uint32) pData));
USBFS_CyDmaSetDstAddress(channelNum, USBFS_DMA_DESCR1, (void*) ((uint32) pData + USBFS_DMA_BYTES_PER_BURST));
/* Configure DMA descriptor 0. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR0, USBFS_DMA_COMMON_CFG | lengthDescr0 |
CYDMA_HALFWORD | CYDMA_WORD_ELEMENT | CYDMA_INC_DST_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Configure DMA descriptor 1. */
USBFS_CyDmaSetConfiguration(channelNum, USBFS_DMA_DESCR1, USBFS_DMA_COMMON_CFG | lengthDescr1 |
CYDMA_HALFWORD | CYDMA_WORD_ELEMENT | CYDMA_INC_DST_ADDR | CYDMA_INVALIDATE | CYDMA_CHAIN);
/* Enable interrupt from DMA channel. */
USBFS_CyDmaSetInterruptMask(channelNum);
/* Validate DMA descriptor 0 and 1. */
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR0);
if (USBFS_DmaEpBurstCntBackup[epNumber] > 1u)
{
USBFS_CyDmaValidateDescriptor(channelNum, USBFS_DMA_DESCR1);
}
/* Enable DMA channel: configuration complete. */
USBFS_CyDmaChEnable(channelNum);
/* OUT endpoint has to be armed again by user when DMA transfers have been completed.
* NO_EVENT_PENDING: notifies that data has been copied from endpoint buffer.
*/
}
#endif /* (USBFS_EP_MANAGEMENT_DMA_AUTO) */
#endif /* (USBFS_EP_MANAGEMENT_MANUAL) */
}
else
{
length = 0u;
}
return (length);
}
#endif /* (USBFS_16BITS_EP_ACCESS_ENABLE) */
/*******************************************************************************
* Function Name: USBFS_EnableOutEP
****************************************************************************//**
*
* This function enables the specified endpoint for OUT transfers. Do not call
* this function for IN endpoints.
*
* \param epNumber: Contains the data endpoint number. Valid values are between
* 1 and 8.
*
* \globalvars
*
* \ref USBFS_EP[epNumber].apiEpState - set to NO_EVENT_PENDING
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_EnableOutEP(uint8 epNumber)
{
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
USBFS_EP[epNumber].apiEpState = USBFS_NO_EVENT_PENDING;
/* Enable OUT endpoint to be written by Host. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_EP[epNumber].epMode;
}
}
/*******************************************************************************
* Function Name: USBFS_DisableOutEP
****************************************************************************//**
*
* This function disables the specified USBFS OUT endpoint. Do not call this
* function for IN endpoints.
*
* \param epNumber: Contains the data endpoint number.
* Valid values are between 1 and 8.
*
*******************************************************************************/
void USBFS_DisableOutEP(uint8 epNumber)
{
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
/* Set NAK response for OUT endpoint. */
USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 = USBFS_MODE_NAK_OUT;
}
}
/*******************************************************************************
* Function Name: USBFS_Force
****************************************************************************//**
*
* This function forces a USB J, K, or SE0 state on the D+/D lines. It provides
* the necessary mechanism for a USB device application to perform a USB Remote
* Wakeup. For more information, see the USB 2.0 Specification for details on
* Suspend and Resume.
*
* \param state A byte indicating which of the four bus states to enable.
* Symbolic names and their associated values are listed here:
* State |Description
* ---------------------------|----------------------------------------------
* USBFS_FORCE_J | Force a J State onto the D+/D lines
* USBFS_FORCE_K | Force a K State onto the D+/D lines
* USBFS_FORCE_SE0 | Force a Single Ended 0 onto the D+/D lines
* USBFS_FORCE_NONE| Return bus to SIE control
*
*
*******************************************************************************/
void USBFS_Force(uint8 bState)
{
/* This registers is used only for manual control of SIE (no masking is
* needed before write into it).
*/
USBFS_USBIO_CR0_REG = bState;
}
/*******************************************************************************
* Function Name: USBFS_GetEPAckState
****************************************************************************//**
*
* This function determines whether an ACK transaction occurred on this endpoint
* by reading the ACK bit in the control register of the endpoint. It does not
* clear the ACK bit.
*
* \param epNumber Contains the data endpoint number.
* Valid values are between 1 and 8.
*
* \return
* If an ACKed transaction occurred, this function returns a non-zero value.
* Otherwise, it returns zero.
*
*******************************************************************************/
uint8 USBFS_GetEPAckState(uint8 epNumber)
{
uint8 cr = 0u;
if ((epNumber > USBFS_EP0) && (epNumber < USBFS_MAX_EP))
{
cr = USBFS_SIE_EP_BASE.sieEp[epNumber].epCr0 & USBFS_MODE_ACKD;
}
return ((uint8) cr);
}
/*******************************************************************************
* Function Name: USBFS_SetPowerStatus
****************************************************************************//**
*
* This function sets the current power status. The device replies to USB
* GET_STATUS requests based on this value. This allows the device to properly
* report its status for USB Chapter 9 compliance. Devices can change their
* power source from self powered to bus powered at any time and report their
* current power source as part of the device status. You should call this
* function any time your device changes from self powered to bus powered or
* vice versa, and set the status appropriately.
*
* \param powerStatus: Contains the desired power status, one for self powered
* or zero for bus powered. Symbolic names and their associated values are
* given here:
* Power Status |Description
* --------------------------------------------|---------------------------
* USBFS_DEVICE_STATUS_BUS_POWERED | Set the device to bus powered
* USBFS_DEVICE_STATUS_SELF_POWERED | Set the device to self powered
*
* \globalvars
*
* \ref USBFS_deviceStatus - set power status
*
* \reentrant
* No.
*
*******************************************************************************/
void USBFS_SetPowerStatus(uint8 powerStatus)
{
if (powerStatus != USBFS_DEVICE_STATUS_BUS_POWERED)
{
USBFS_deviceStatus |= (uint8) USBFS_DEVICE_STATUS_SELF_POWERED;
}
else
{
USBFS_deviceStatus &= (uint8) ~USBFS_DEVICE_STATUS_SELF_POWERED;
}
}
#if (USBFS_VBUS_MONITORING_ENABLE)
/***************************************************************************
* Function Name: USBFS_VBusPresent
************************************************************************//**
*
* Determines VBUS presence for self-powered devices. This function is
* available when the VBUS Monitoring option is enabled in the Advanced tab.
*
* \return
* The return value can be the following:
* Return Value | Description
* -------------|-----------------
* 1 | VBUS is present
* 0 | VBUS is absent
*
*
***************************************************************************/
uint8 USBFS_VBusPresent(void)
{
return ((0u != (USBFS_VBUS_STATUS_REG & USBFS_VBUS_VALID)) ? (uint8) 1u : (uint8) 0u);
}
#endif /* (USBFS_VBUS_MONITORING_ENABLE) */
/*******************************************************************************
* Function Name: USBFS_RWUEnabled
****************************************************************************//**
*
* This function returns the current remote wakeup status.
* If the device supports remote wakeup, the application should use this
* function to determine if remote wakeup was enabled by the host. When the
* device is suspended and it determines the conditions to initiate a remote
* wakeup are met, the application should use the USBFS_Force() function to
* force the appropriate J and K states onto the USB bus, signaling a remote
* wakeup.
*
*
* \return
* Returns non-zero value if remote wakeup is enabled and zero otherwise.
*
* \globalvars
* USBFS_deviceStatus - checked to determine remote status
*
*******************************************************************************/
uint8 USBFS_RWUEnabled(void)
{
uint8 result = USBFS_FALSE;
if (0u != (USBFS_deviceStatus & USBFS_DEVICE_STATUS_REMOTE_WAKEUP))
{
result = USBFS_TRUE;
}
return (result);
}
/*******************************************************************************
* Function Name: USBFS_GetDeviceAddress
****************************************************************************//**
*
* This function returns the currently assigned address for the USB device.
*
* \return
* Returns the currently assigned address.
* Returns 0 if the device has not yet been assigned an address.
*
*******************************************************************************/
uint8 USBFS_GetDeviceAddress(void)
{
return (uint8)(USBFS_CR0_REG & USBFS_CR0_DEVICE_ADDRESS_MASK);
}
/*******************************************************************************
* Function Name: USBFS_EnableSofInt
****************************************************************************//**
*
* This function enables interrupt generation when a Start-of-Frame (SOF)
* packet is received from the host.
*
*******************************************************************************/
void USBFS_EnableSofInt(void)
{
#if (CY_PSOC4)
/* Enable SOF interrupt interrupt source. */
USBFS_INTR_SIE_MASK_REG |= (uint32) USBFS_INTR_SIE_SOF_INTR;
#else
/* Enable SOF interrupt if it is present. */
#if (USBFS_SOF_ISR_ACTIVE)
CyIntEnable(USBFS_SOF_VECT_NUM);
#endif /* (USBFS_SOF_ISR_ACTIVE) */
#endif /* (CY_PSOC4) */
}
/*******************************************************************************
* Function Name: USBFS_DisableSofInt
****************************************************************************//**
*
* This function disables interrupt generation when a Start-of-Frame (SOF)
* packet is received from the host.
*
*******************************************************************************/
void USBFS_DisableSofInt(void)
{
#if (CY_PSOC4)
/* Disable SOF interrupt interrupt source. */
USBFS_INTR_SIE_MASK_REG &= (uint32) ~USBFS_INTR_SIE_SOF_INTR;
#else
/* Disable SOF interrupt if it is present. */
#if (USBFS_SOF_ISR_ACTIVE)
CyIntDisable(USBFS_SOF_VECT_NUM);
#endif /* (USBFS_SOF_ISR_ACTIVE) */
#endif /* (CY_PSOC4) */
}
#if (USBFS_BATT_CHARG_DET_ENABLE)
/***************************************************************************
* Function Name: USBFS_DetectPortType
************************************************************************//**
*
* This function implements the USB Battery Charger Detection (BCD)
* algorithm to determine the type of USB host downstream port. This API
* is available only for PSoC 4 devices, and should be called when the VBUS
* voltage transition (OFF to ON) is detected on the bus. If the USB device
* functionality is enabled, this API first calls USBFS_Stop() API
* internally to disable the USB device functionality, and then proceeds to
* implement the BCD algorithm to detect the USB host port type.
* The USBFS_Start() API should be called after this API if the USB
* communication needs to be initiated with the host.
* *Note* This API is generated only if the “Enable Battery Charging
* Detection” option is enabled in the “Advanced” tab of the component GUI.
* *Note* API implements the steps 2-4 of the BCD algorithm which are
* - Data Contact Detect
* - Primary Detection
* - Secondary Detection
*
* The first step of BCD algorithm, namely, VBUS detection shall be handled
* at the application firmware level.
*
* \return
* The return value can be the following:
* Return Value |Description
* ----------------------------------|-------------------------------------
* USBFS_BCD_PORT_SDP | Standard downstream port detected
* USBFS_BCD_PORT_CDP | Charging downstream port detected
* USBFS_BCD_PORT_DCP | Dedicated charging port detected
* USBFS_BCD_PORT_UNKNOWN | Unable to detect charging port type (proprietary charger type)
* USBFS_BCD_PORT_ERR | Error condition in detection process
*
*
* \sideeffects
*
* USB device functionality is disabled by this API if not already disabled.
*
***************************************************************************/
uint8 USBFS_Bcd_DetectPortType(void)
{
uint32 bkPwrCtrl;
uint32 cr1RegVal;
uint32 secondaryDetection = 0u;
uint8 result = USBFS_BCD_PORT_UNKNOWN;
/*Check USB Started and Stop it*/
if(0u != USBFS_initVar)
{
USBFS_Stop();
}
/*Initialize USBFS IP for Charger detection*/
/*Enable clock to USB IP. */
USBFS_USB_CLK_EN_REG = USBFS_USB_CLK_CSR_CLK_EN;
/* Enable USBIO control on drive mode of D+ and D- pins. */
USBFS_USBIO_CR1_REG &= ~ (uint32) USBFS_USBIO_CR1_IOMODE;
/* Select VBUS detection source and clear PHY isolate. The application
* level must ensure that VBUS is valid. There is no need to wait 2us
* before VBUS is valid.
*/
bkPwrCtrl = USBFS_POWER_CTRL_REG;
USBFS_POWER_CTRL_REG = USBFS_DEFAULT_POWER_CTRL_VBUS\
& (~USBFS_POWER_CTRL_ENABLE_VBUS_PULLDOWN)\
& (~USBFS_POWER_CTRL_ENABLE_DM_PULLDOWN);
/* Enable PHY detector and single-ended and differential receivers.
* Enable charger detection. */
USBFS_POWER_CTRL_REG |= USBFS_DEFAULT_POWER_CTRL_PHY\
| USBFS_POWER_CTRL_ENABLE_CHGDET;
/* Suspend clear sequence. */
USBFS_POWER_CTRL_REG &= (uint32) ~USBFS_POWER_CTRL_SUSPEND;
CyDelayUs(USBFS_WAIT_SUSPEND_DEL_DISABLE);
USBFS_POWER_CTRL_REG &= (uint32) ~USBFS_POWER_CTRL_SUSPEND_DEL;
/* Data connection detection
* Realization with delay as Hard IP does not support DCD 300 ms.
*/
#if defined (USBFS_NO_DCD)
CyDelay(USBFS_BCD_TIMEOUT);
#else
/* DCD implementation:*/
{
uint16 timeout = USBFS_BCD_TIMEOUT;
uint8 connectionApproved = 0u;
uint8 connected = 0u;
/* BCD spec 1.2: Turns on Idp_src and D- pull-down resistor */
USBFS_POWER_CTRL_REG |= USBFS_POWER_CTRL_ENABLE_DM_PULLDOWN;
USBFS_CHGDET_CTRL_REG |= USBFS_CHGDET_CTRL_DCD_SRC_EN;
/* BCD spec 1.2: Waits for D+ to be low for a time of Tdcd_dbnc*/
while ((0u != timeout) && (0u == connectionApproved))
{
if (0u == (USBFS_USBIO_CR1_REG & USBFS_USBIO_CR1_DP0))
{
connected++;
}
else
{
connected = 0u;
}
connectionApproved = (USBFS_BCD_TDCD_DBNC < connected) ? 1u:0u;
CyDelay(1u);
timeout--;
}
/* BCD spec 1.2: Turns off Idp_src. */
USBFS_CHGDET_CTRL_REG &= ~USBFS_CHGDET_CTRL_DCD_SRC_EN;
}
#endif /*(USBFS_NO_DCD)*/
/* Primary detection: enable VDP_SRC on D+ and IDM_SINK on D-. */
USBFS_CHGDET_CTRL_REG = USBFS_CHGDET_CTRL_PRIMARY;
CyDelay(USBFS_BCD_PRIMARY_WAIT);
cr1RegVal = USBFS_USBIO_CR1_REG;
/* Check is it SDP or DCP/CDP, read comparator 2 output. */
if (0u == (USBFS_CHGDET_CTRL_REG & USBFS_CHGDET_CTRL_COMP_OUT))
{
/* Check status of D- line. */
if (0u == (cr1RegVal & USBFS_USBIO_CR1_DM0))
{
result = USBFS_BCD_PORT_SDP;
}
else
{
/* ERROR: such combination is impossible. Abort charger
* detection.
*/
result = USBFS_BCD_PORT_ERR;
}
}
else
{
/* Need Secondary detection. Charging port: DCP or proprietary*/
secondaryDetection = 1u;
}
/* Secondary detection: Set CHGDET_CTRL register to enable VDM_SRC on D- and IDP_SINK on D+. */
if (0u != secondaryDetection)
{
USBFS_CHGDET_CTRL_REG = USBFS_CHGDET_CTRL_DEFAULT \
| USBFS_CHGDET_CTRL_SECONDARY;
CyDelay(USBFS_BCD_SECONDARY_WAIT);
cr1RegVal = USBFS_USBIO_CR1_REG;
/* Check is it SDP or DCP/CDP, read comparator 1 output. */
if (0u == (USBFS_CHGDET_CTRL_REG & USBFS_CHGDET_CTRL_COMP_OUT))
{
/* Check status of D+ line. */
if (0u == (cr1RegVal & USBFS_USBIO_CR1_DP0))
{
result = USBFS_BCD_PORT_CDP;
}
else
{
/* ERROR: such combination is impossible. Abort charger
* detection.
*/
result = USBFS_BCD_PORT_ERR;
}
}
else
{
/* Check status of D+ line. */
if (0u == (cr1RegVal & USBFS_USBIO_CR1_DP0))
{
result = USBFS_BCD_PORT_DCP;
}
else
{
/* It is may be proprietary charger. Proprietary charge is
* not supported byHardware IP block.
*/
result = USBFS_BCD_PORT_UNKNOWN;
}
}
}
/* Restore CHGDET_CTRL. */
USBFS_CHGDET_CTRL_REG = 0u;
/*Revert registers back*/
USBFS_POWER_CTRL_REG = bkPwrCtrl;
USBFS_USBIO_CR1_REG |= (uint32) USBFS_USBIO_CR1_IOMODE;
USBFS_USB_CLK_EN_REG = ~USBFS_USB_CLK_CSR_CLK_EN;
return (result);
}
#endif /* (USBFS_BATT_CHARG_DET_ENABLE) */
#if (USBFS_LPM_ACTIVE)
/***************************************************************************
* Function Name: USBFS_Lpm_GetBeslValue
************************************************************************//**
*
* This function returns the Best Effort Service Latency (BESL) value
* sent by the host as part of the LPM token transaction.
*
* \return
* 4-bit BESL value received in the LPM token packet from the host
*
*
***************************************************************************/
uint32 USBFS_Lpm_GetBeslValue(void)
{
return (uint32) (USBFS_LPM_STAT_REG & USBFS_LPM_STAT_LPM_BESL_MASK);
}
/***************************************************************************
* Function Name: USBFS_Lpm_RemoteWakeUpAllowed
************************************************************************//**
*
* This function returns the remote wakeup permission set for the device by
* the host as part of the LPM token transaction.
*
* \return
* 0 - remote wakeup not allowed, 1 - remote wakeup allowed
*
*
***************************************************************************/
uint32 USBFS_Lpm_RemoteWakeUpAllowed(void)
{
return (uint32) (USBFS_LPM_STAT_REG & USBFS_LPM_STAT_LPM_REMOTE_WAKE);
}
/***************************************************************************
* Function Name: USBFS_Lpm_SetResponse
************************************************************************//**
*
* This function configures the response in the handshake packet the device
* has to send when an LPM token packet is received.
*
* \param response
* type of response to return for an LPM token packet
* Allowed response values:
* - USBFS_LPM_REQ_ACK - next LPM request will be
* responded with ACK
* - USBFS_LPM_REQ_NACK - next LPM request will be
* responded with NACK
* - USBFS_LPM_REQ_NYET - next LPM request will be
* responded with NYET
*
***************************************************************************/
void USBFS_Lpm_SetResponse(uint32 response)
{
uint32 lpmCtrl = USBFS_LPM_CTRL_REG & (uint32) ~USBFS_LPM_CTRL_ACK_NYET_MASK;
USBFS_LPM_CTRL_REG = lpmCtrl | ((uint32) response & USBFS_LPM_CTRL_ACK_NYET_MASK);
}
/***************************************************************************
* Function Name: USBFS_Lpm_GetResponse
************************************************************************//**
*
* This function returns the currently configured response value that the
* device will send as part of the handshake packet when an LPM token
* packet is received.
*
* \return
* type of handshake response that will be returned by the device
* for an LPM token packet
* Possible response values:
* - USBFS_LPM_REQ_ACK - next LPM request will be responded
* with ACK
* - USBFS_LPM_REQ_NACK - next LPM request will be responded
* with NACK
* - USBFS_LPM_REQ_NYET - next LPM request will be responded
* with NYET
*
***************************************************************************/
uint32 USBFS_Lpm_GetResponse(void)
{
return ((uint32) USBFS_LPM_CTRL_REG & (uint32)USBFS_LPM_CTRL_ACK_NYET_MASK);
}
#endif /* (USBFS_LPM_ACTIVE) */
/* [] END OF FILE */