openblt/Target/Demo/ARMCM4_XMC4_XMC4700_Relax_K.../Boot/Libraries/XMCLib/src/xmc_usbd.c

1628 lines
48 KiB
C

/**
* @file xmc_usbd.c
* @date 2015-06-20
*
* @cond
**********************************************************************************
* XMClib v2.1.12 - XMC Peripheral Driver Library
*
* Copyright (c) 2015-2017, Infineon Technologies AG
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification,are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the copyright holders nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* To improve the quality of the software, users are encouraged to share
* modifications, enhancements or bug fixes with Infineon Technologies AG
* dave@infineon.com).
**********************************************************************************
*
* Change History
* --------------
*
* 2015-02-16:
* - Initial Version.<br>
* 2015-03-18:
* - Updated the XMC_USBD_EndpointStall() to fix issue on USB clear stall. <br>
* - Updated the XMC_USBD_EndpointConfigure() to fix issue in EP0 configuration.<br>
* - Updated the XMC_USBD_IRQHandler()(Removed the DAVE_CE check on SOF event).<br>
* 2015-06-20:
* - Removed GetDriverVersion API.<br>
* - Updated the XMC_USBD_IsEnumDone() API.<br>
* - Updated the copy right in the file header.<br>
* - Updated the XMC_USBD_Disable() API to gate the clock after programming the SCU registers.<br>
*
* @endcond
*
*/
/*******************************************************************************
* HEADER FILES
*******************************************************************************/
#include <xmc_usbd.h>
#if defined(USB0)
/**< macro to check the maximum number of endpoints used*/
#define XMC_USBD_CHECK_INPUT_MAX_NUM_EPS(usbd_max_num_eps) \
((usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_1 ) || \
(usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_2 ) || \
(usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_3 ) || \
(usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_4 ) || \
(usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_5 ) || \
(usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_6 ) || \
(usbd_max_num_eps == XMC_USBD_MAX_NUM_EPS_7 ))
/*******************************************************************************
*GLOBAL DATA
*******************************************************************************/
/*
* Endpoint Out Fifo Size
*/
uint32_t XMC_USBD_EP_OUT_BUFFERSIZE[7] = {0U,0U,0U,0U,0U,0U,0U};
/*
* Endpoint In Fifo Size
*/
uint32_t XMC_USBD_EP_IN_BUFFERSIZE[7] = {0U,0U,0U,0U,0U,0U,0U};
/*
* Device definition
*/
XMC_USBD_DEVICE_t xmc_device;
#ifdef __GNUC__ /*GCC*/
/*
* Endpoint Out Fifo
*/
static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_OUT_BUFFER[7][256] __attribute__((section("USB_RAM")));
/*
* Endpoint In Fifo
*/
static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_IN_BUFFER[7][256] __attribute__((section("USB_RAM")));
#endif
#if defined(__ICCARM__)
#pragma data_alignment=4
/*
* Endpoint Out Fifo
*/
static uint8_t XMC_USBD_EP_OUT_BUFFER[7][256] @ ".dram";
/*
* Endpoint In Fifo
*/
#pragma data_alignment=4
static uint8_t XMC_USBD_EP_IN_BUFFER[7][256] @ ".dram";
#endif
#if defined(__CC_ARM)
/*
* Endpoint Out Fifo
*/
static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_OUT_BUFFER[7][256] __attribute__((section ("RW_IRAM1")));
/*
* Endpoint In Fifo
*/
static __attribute__((aligned(4))) uint8_t XMC_USBD_EP_IN_BUFFER[7][256] __attribute__((section ("RW_IRAM1")));
#endif
XMC_USBD_t *usbd_init;
/*******************************************************************************
*LOCAL ROUTINES
*******************************************************************************/
/*Local routines prototypes*/
uint8_t XMC_USBD_lDeviceActive(const XMC_USBD_t *const obj);
static void XMC_USBD_lReadFifo(const uint32_t ep_num,const uint32_t byte_count);
static uint32_t XMC_USBD_lWriteFifo(XMC_USBD_EP_t *ep);
static void XMC_USBD_lFlushTXFifo(const uint8_t fifo_num);
static void XMC_USBD_lFlushRXFifo(void);
static uint8_t XMC_USBD_lAssignTXFifo(void);
static void XMC_USBD_lStartReadXfer(XMC_USBD_EP_t *const ep);
static void XMC_USBD_lStartWriteXfer(XMC_USBD_EP_t *const ep);
static void XMC_USBD_lHandleEnumDone(void);
static void XMC_USBD_lHandleOEPInt(const XMC_USBD_t *const obj);
static void XMC_USBD_lHandleRxFLvl(void);
static void XMC_USBD_lHandleIEPInt(const XMC_USBD_t *const obj);
static void XMC_USBD_lUnassignFifo(const uint8_t fifo_nr);
static void XMC_USBD_lHandleUSBReset(const XMC_USBD_t *const obj);
static void XMC_USBD_lHandleOTGInt(void);
static void XMC_USBD_lClearEventOTG(uint32_t event);
/**
* The device driver
*/
const XMC_USBD_DRIVER_t Driver_USBD0 =
{
.GetCapabilities = XMC_USBD_GetCapabilities,
.Initialize = XMC_USBD_Init,
.Uninitialize = XMC_USBD_Uninitialize,
.DeviceConnect = XMC_USBD_DeviceConnect,
.DeviceDisconnect = XMC_USBD_DeviceDisconnect,
.DeviceGetState = XMC_USBD_DeviceGetState,
.DeviceSetAddress = XMC_USBD_DeviceSetAddress,
.EndpointConfigure = XMC_USBD_EndpointConfigure,
.EndpointUnconfigure = XMC_USBD_EndpointUnconfigure,
.EndpointStall = XMC_USBD_EndpointStall,
.EndpointReadStart = XMC_USBD_EndpointReadStart,
.EndpointRead = XMC_USBD_EndpointRead,
.EndpointWrite = XMC_USBD_EndpointWrite,
.EndpointAbort = XMC_USBD_EndpointAbort,
.GetFrameNumber = XMC_USBD_GetFrameNumber,
.IsEnumDone = XMC_USBD_IsEnumDone
};
/**
* @brief Checks if device is active
*
* Therefore the endpoint inInUse flag are checked and if one endpoint is in use, 1 is returned,
* else 0 is returned.
* @return 1 if an endpoint is active else 0
*/
uint8_t XMC_USBD_lDeviceActive(const XMC_USBD_t *const obj)
{
uint8_t i;
uint8_t result = 0U;
for (i = 0U; i < (uint8_t)obj->usbd_max_num_eps; i++)
{
if (xmc_device.ep[i].inInUse || xmc_device.ep[i].outInUse)
{
result = 1U;
}
}
return result;
}
/**
* @brief Read data from the rx fifo
*
* The data from the fifo is copied in to the buffer specified by @ref xfer_buffer and
* the transfer values get updated. If the endpoint is disabled or the buffer not existent
* the function exits.
*
* @arg ep_num the endpoint to read for
* @arg byte_count the byte count to read
*/
static void XMC_USBD_lReadFifo(const uint32_t ep_num,const uint32_t byte_count)
{
XMC_USBD_EP_t * ep = &xmc_device.ep[ep_num];
uint32_t word_count;
uint32_t temp_data;
uint32_t temp_word_count;
volatile uint32_t *fifo = xmc_device.fifo[0U];
uint32_t i;
depctl_data_t data;
data.d32 = xmc_device.endpoint_out_register[ep_num]->doepctl;
word_count = (byte_count >> 2U );
temp_word_count = (word_count << 2U);
/* Check if ep is enabled and has buffer */
if (!data.b.usbactep)
{
/*Do Nothing*/
}
else if (ep->xferBuffer == NULL)
{
/*Do Nothing*/
}
else
{
/* store the data */
for (i = 0U;i < word_count; i++)
{
*(((uint32_t*)ep->xferBuffer)+i) = *fifo;
}
/* space is not devidable by 4 */
if (byte_count!=temp_word_count)
{
temp_data = *fifo;
for (i = 0U;(temp_word_count + i) < byte_count;i++)
{
ep->xferBuffer[(word_count << 2)+i] = (uint8_t)((temp_data & ((uint32_t)0xFFU << (i * 8U))) >> (i * 8U));
}
}
/* save the amount of data */
ep->xferCount += byte_count;
ep->xferBuffer += byte_count;
}
}
/**
* @brief Write data to an endpoint fifo
*
* The data from the @ref xfer_buffer gets copied in to the tx fifo of the endpoint until the buffer has been read
*completely or the tx fifo is full. The transfer values are not updated.
*
* @arg[in] ep the endpoint to use
* @return the number of bytes written to the fifo
*/
static uint32_t XMC_USBD_lWriteFifo(XMC_USBD_EP_t *const ep)
{
dtxfsts_data_t freeSpace;
volatile uint32_t *fifo;
uint32_t byte_count;
uint32_t word_count;
uint32_t result;
uint32_t i;
fifo = xmc_device.fifo[ep->address_u.address_st.number]; /* fifo */
freeSpace.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->dtxfsts;
/* calculate the length and the amount of dwords to copy based on the fifo status */
byte_count = ep->xferLength - ep->xferCount;
if (!byte_count)
{
result = 0U;
}
else
{
/* add the unaligned bytes to the word count to compare with the fifo space */
word_count = ((uint32_t)byte_count + 3U) >> 2U;
if (word_count > (uint32_t)freeSpace.b.txfspcavail )
{
word_count = (uint32_t)freeSpace.b.txfspcavail;
byte_count = (uint32_t)word_count << (uint32_t)2U;
}
/* copy data dword wise */
for (i = 0U; i < word_count;ep->xferBuffer+= 4U)
{
*fifo = *(uint32_t*)ep->xferBuffer;
i++;
}
result=byte_count;
}
return result;
}
/**
* @brief Flush a tx fifo
*
* @param[in] fifo_num Fifo number to flush
*
* @note Use 0x10 as parameter to flush all tx fifos.
*/
static void XMC_USBD_lFlushTXFifo(const uint8_t fifo_num)
{
volatile grstctl_t data;
uint32_t count;
data.d32 = 0U;
/*flush fifo */
data.b.txfflsh = 1U;
data.b.txfnum = fifo_num;
xmc_device.global_register->grstctl = data.d32;
for (count = 0U;count < 1000U; count++){}
do
{
data.d32 = xmc_device.global_register->grstctl;
} while (data.b.txfflsh);
count = 0U;
while (count++ < 1000U)
{
/* wait 3 phy clocks */
}
}
/**
* @brief Flush the rx fifo
*/
static void XMC_USBD_lFlushRXFifo(void)
{
volatile grstctl_t data;
uint32_t count;
data.d32 = 0U;
data.b.rxfflsh = 1U;
/* flush FIFO */
xmc_device.global_register->grstctl = data.d32;
do
{
for (count = 0U; count < 1000U; count++){}
data.d32 = xmc_device.global_register->grstctl;
} while (data.b.rxfflsh);
count = 0U;
while (count++ < 1000U)
{
/* wait 3 phy clocks */
}
}
/*
* Support Functions
*/
/**
* @brief Assign a free tx fifo
*
* A free tx fifo will be searched and the number will be returned.
*
* @return Fifo number for a free fifo
*/
static uint8_t XMC_USBD_lAssignTXFifo(void)
{
uint16_t mask = 1U;
uint8_t i = 0U;
uint8_t result = 0U;
while( (i < (uint8_t)XMC_USBD_NUM_TX_FIFOS)&&((xmc_device.txfifomsk & mask) != 0U))
{
mask = (uint16_t)(mask << 1U);
i++;
}
if ((xmc_device.txfifomsk & mask) == 0U)
{
xmc_device.txfifomsk |= mask;
result=i;
}
return result;
}
/**
* @brief Free a tx fifo
*
* Mark an used tx fifo as free.
* @param[in] fifo_nr Fifo number to free
*/
static void XMC_USBD_lUnassignFifo(const uint8_t fifo_nr)
{
xmc_device.txfifomsk = (uint16_t)((uint32_t)xmc_device.txfifomsk & (uint32_t)(~((uint32_t)((uint32_t)1U << fifo_nr))));
}
/**
* @brief Start a transfer for an out endpoint
*
* Based on the transfer values of the endpoint, the out endpoint registers will be programmed
* to start a new out transfer.
*
* @note No checking of the transfer values are done in this function. Be sure,
* that the transfer values are reasonable (e.g. buffer size is not exceeded).
*
* @param[in] ep Endpoint to start the transfer
*/
static void XMC_USBD_lStartReadXfer(XMC_USBD_EP_t *const ep)
{
deptsiz_data_t data;
depctl_data_t epctl;
data.d32 = 0U;
if ((ep->xferTotal - ep->xferLength) > ep->maxTransferSize)
{
ep->xferLength += ep->maxTransferSize;
}
else
{
ep->xferLength = ep->xferTotal;
}
if (ep->address_u.address_st.number == 0U)
{
/* Setup the endpoint to receive 3 setup packages and one normal package.*/
/* Cast the data pointer to use only one variable */
deptsiz0_data_t *ep0_data = (deptsiz0_data_t*)&data;
ep0_data->b.pktcnt = 0x1U;
ep0_data->b.supcnt = 0x3U;
ep0_data->b.xfersize = (uint8_t)ep->xferTotal;
}
else
{
/* If requested length is zero, just receive one zero length packet */
if (ep->xferLength == 0U)
{
data.b.xfersize = 0U;
data.b.pktcnt = 1U;
}
else
{
/* setup endpoint to recive a amount of packages by given size */
data.b.pktcnt = (uint16_t)(((ep->xferLength - ep->xferCount) + (ep->maxPacketSize -(uint32_t)1U))/ep->maxPacketSize);
data.b.xfersize =(uint32_t)(ep->xferLength - ep->xferCount);
}
}
if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
/* Programm dma address if needed */
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepdma = (uint32_t)(ep->xferBuffer);
}
/* setup endpoint size and enable endpoint */
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doeptsiz = data.d32;
epctl.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
epctl.b.cnak = 1U;
epctl.b.epena = 1U;
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = epctl.d32;
}
/**
* @brief Start a new in transfer
*
* Based on the transfer values of the endpoint the in endpoint registers will be programmed
* to start a new in transfer
*
* @param[in] ep Endpoint to start the transfer
*/
static void XMC_USBD_lStartWriteXfer(XMC_USBD_EP_t *const ep)
{
deptsiz_data_t size;
depctl_data_t ctl;
size.d32 = 0U;
ctl.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
if ((ep->xferTotal - ep->xferLength) < ep->maxTransferSize)
{
ep->xferLength = ep->xferTotal;
}
else
{
ep->xferLength += ep->maxTransferSize;
}
if (ep->xferLength == 0U)
{
size.b.xfersize = 0U;
size.b.pktcnt = 1U;
}
else
{
if (ep->address_u.address_st.number == 0U)
{
size.b.pktcnt = 1U;
/* ep->maxXferSize equals maxPacketSize */
size.b.xfersize = (uint32_t)(ep->xferLength - ep->xferCount);
}
else
{
size.b.xfersize =(uint32_t)(ep->xferLength - ep->xferCount);
size.b.pktcnt = (uint16_t)(((uint16_t)(ep->xferLength - ep->xferCount) + (uint16_t)((uint16_t)ep->maxPacketSize - 1U))/
ep->maxPacketSize);
}
if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
/* Program dma*/
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepdma = (uint32_t)ep->xferBuffer;
}
if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
/* enable fifo empty interrupt */
xmc_device.device_register->dtknqr4_fifoemptymsk |= (uint32_t)((uint32_t)1U << (uint8_t)ep->address_u.address_st.number);
}
}
/* Program size of transfer and enable endpoint */
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->dieptsiz = size.d32;
ctl.b.epena = 1U;
ctl.b.cnak = 1U;
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = ctl.d32;
}
/**
* @brief Handles the USBD reset interrupt
*
* When ever the host sets the bus into reset condition the usb otg_core generates
* an interrupt, which is handled by this function. It resets the complete otg_core
* into the default state.
*/
static void XMC_USBD_lHandleUSBReset(const XMC_USBD_t *const obj)
{
uint32_t i;
depctl_data_t epctl;
dctl_data_t dctl;
fifosize_data_t gnptxfsiz;
daint_data_t daint;
dcfg_data_t dcfg;
/* Clear the Remote Wakeup Signaling */
dctl.d32 = xmc_device.device_register->dctl;
dctl.b.rmtwkupsig = 1U;
xmc_device.device_register->dctl = dctl.d32;
/* enable naks for all eps */
for (i = 0U;i < (uint8_t)XMC_USBD_NUM_EPS;i++)
{
epctl.d32 = xmc_device.endpoint_out_register[i]->doepctl;
epctl.b.snak = 1U;
epctl.b.stall = 0U;
xmc_device.endpoint_out_register[i]->doepctl = epctl.d32;
}
/* Configure fifos */
/* Calculate the size of the rx fifo */
xmc_device.global_register->grxfsiz = 64U;
/* Calculate the size of the tx fifo for ep 0 */
gnptxfsiz.d32 = 0U;
gnptxfsiz.b.depth = 16U;
gnptxfsiz.b.startaddr = 64U;
xmc_device.global_register->gnptxfsiz = gnptxfsiz.d32;
/* calculate the size for the rest */
for (i = 1U;i < (uint8_t)XMC_USBD_NUM_TX_FIFOS;i++)
{
xmc_device.global_register->dtxfsiz[i- 1U] = (uint32_t)(((256U + (i*(64U)))/4U) | ((uint32_t)16U << 16U));
}
/* flush the fifos for proper operation */
XMC_USBD_lFlushTXFifo(0x10U); /* 0x10 == all fifos, see doc */
XMC_USBD_lFlushTXFifo(0x0U);
XMC_USBD_lFlushRXFifo();
/* Flush learning queue not needed due to fifo config */
/* enable ep0 interrupts */
daint.d32 = 0U;
daint.b.inep0 = 1U;
daint.b.outep0 = 1U;
xmc_device.device_register->daintmsk = daint.d32;
/* enable endpoint interrupts */
/* out ep interrupts */
XMC_USBD_EnableEventOUTEP(((uint32_t)XMC_USBD_EVENT_OUT_EP_TX_COMPLET | (uint32_t)XMC_USBD_EVENT_OUT_EP_DISABLED |
(uint32_t)XMC_USBD_EVENT_OUT_EP_SETUP | (uint32_t)XMC_USBD_EVENT_OUT_EP_AHB_ERROR));
/*in ep interrupts */
XMC_USBD_EnableEventINEP(((uint32_t)XMC_USBD_EVENT_IN_EP_TX_COMPLET | (uint32_t)XMC_USBD_EVENT_IN_EP_DISABLED |
(uint32_t)XMC_USBD_EVENT_IN_EP_AHB_ERROR | (uint32_t)XMC_USBD_EVENT_IN_EP_TIMEOUT));
/* Clear device Address */
dcfg.d32 = xmc_device.device_register->dcfg;
dcfg.b.devaddr = 0U;
xmc_device.device_register->dcfg = dcfg.d32;
if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
/* Clear Empty interrupt */
xmc_device.device_register->dtknqr4_fifoemptymsk = 0U;
}
xmc_device.ep[0U].outInUse = 0U;
xmc_device.ep[0U].inInUse = 0U;
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_RESET);
/* clear reset intr */
XMC_USBD_ClearEvent(XMC_USBD_EVENT_RESET);
}
/**
* @brief Handle OTG Interrupt
*
* It detects especially connect and disconnect events.
*/
static void XMC_USBD_lHandleOTGInt(void)
{
gotgint_data_t data;
data.d32 = xmc_device.global_register->gotgint;
if (data.b.sesenddet)
{
xmc_device.IsPowered = 0U;
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_POWER_OFF);
}
XMC_USBD_lClearEventOTG(data.d32);
}
/**
* @brief Interrupt handler for device enumeration done.
*
* Handles the enumeration done from dwc_otg, when the host has enumerated the device.
*/
static void XMC_USBD_lHandleEnumDone(void)
{
/* Normaly we need to check dctl
* We are always fullspeed, so max it up. */
depctl_data_t epctl;
gusbcfg_data_t gusbcfg;
epctl.d32=xmc_device.endpoint_in_register[0U]->diepctl;
epctl.b.mps = 0x00U; /* 64 Byte, this is also automatically set for out ep */
xmc_device.endpoint_in_register[0U]->diepctl = epctl.d32;
/* update device connected flag */
xmc_device.IsConnected = 1U;
xmc_device.IsPowered = 1U;
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_CONNECT);
/* Set Trim */
gusbcfg.d32 = xmc_device.global_register->gusbcfg;
gusbcfg.b.usbtrdtim = 9U; /* default value for LS/FS */
xmc_device.global_register->gusbcfg = gusbcfg.d32;
/* clear interrupt */
XMC_USBD_ClearEvent(XMC_USBD_EVENT_ENUMDONE);
}
/**
* @brief Handles all interrupts for all out endpoints
*
* The interrupt handler first checks, which endpoint has caused the interrupt and then
* determines, which interrupt should be handled.
*/
static void XMC_USBD_lHandleOEPInt(const XMC_USBD_t *const obj)
{
daint_data_t daint;
daint_data_t daintmsk;
doepmsk_data_t doepmsk;
doepint_data_t doepint;
deptsiz_data_t doeptsiz;
XMC_USBD_EP_t *ep;
uint16_t temp;
uint16_t temp1;
uint16_t mask;
uint8_t ep_num;
daint.d32 = xmc_device.device_register->daint;
daintmsk.d32 = xmc_device.device_register->daintmsk;
doepmsk.d32 = xmc_device.device_register->doepmsk;
mask = daint.ep.out & daintmsk.ep.out;
ep_num = 0U;
doeptsiz.d32 = 0U;
while ((uint16_t)mask >> ep_num)
{
temp1 = (mask >> (uint16_t)ep_num);
temp = temp1 & 0x1U;
if (temp)
{
/* load register data for endpoint */
ep = &xmc_device.ep[ep_num];
doepint.d32 = xmc_device.endpoint_out_register[ep_num]->doepint & doepmsk.d32;
if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
doeptsiz.d32 = xmc_device.endpoint_out_register[ep_num]->doeptsiz;
}
/* Setup Phase Complete */
if (doepint.b.setup)
{
/* ep0 not stalled any more */
ep->isStalled = 0U;
if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
/* calculate size for setup packet */
ep->outBytesAvailable = (uint32_t)(((uint32_t)XMC_USBD_SETUP_COUNT -
(uint32_t)((deptsiz0_data_t*)&doeptsiz)->b.supcnt)*(uint32_t)XMC_USBD_SETUP_SIZE);
}
if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
ep->outBytesAvailable += ep->xferCount;
}
ep->outInUse = 0U;
xmc_device.EndpointEvent_cb(0U,XMC_USBD_EP_EVENT_SETUP); /* signal endpoint event */
/* clear the interrupt */
XMC_USBD_ClearEventOUTEP((uint32_t)XMC_USBD_EVENT_OUT_EP_SETUP,ep_num);
}
if (doepint.b.xfercompl)
{
if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
uint32_t bytes = (ep->xferLength - ep->xferCount) - doeptsiz.b.xfersize;
ep->xferCount += bytes;
ep->xferBuffer += bytes;
}
if (ep->xferTotal == ep->xferLength)
{
ep->outBytesAvailable = ep->xferCount;
ep->outInUse = 0U;
xmc_device.EndpointEvent_cb(ep_num,XMC_USBD_EP_EVENT_OUT);
}
else
{
XMC_USBD_lStartReadXfer(ep);
}
}
XMC_USBD_ClearEventOUTEP(doepint.d32,ep_num);
}
ep_num++;
}
/* clear interrupt */
XMC_USBD_ClearEvent(XMC_USBD_EVENT_OUTEP);
}
/**
* @brief Handles all interrupts for all in endpoints
*
* The interrupt handler first checks, which endpoint has caused the interrupt and then
* determines, which interrupt should be handled.
*/
static void XMC_USBD_lHandleIEPInt(const XMC_USBD_t *const obj)
{
XMC_USBD_EP_t *ep;
daint_data_t daint;
diepmsk_data_t diepmsk;
diepint_data_t diepint;
deptsiz_data_t dieptsiz;
uint16_t temp;
uint16_t temp1;
uint16_t mask;
uint8_t ep_num;
uint32_t inepint;
daint.d32 = xmc_device.device_register->daint;
diepmsk.d32 = xmc_device.device_register->diepmsk;
dieptsiz.d32 = 0U;
mask = daint.ep.in;
ep_num = 0U;
while ((uint16_t)mask >> ep_num)
{
temp1 = ((uint16_t)mask >> (uint16_t)ep_num);
temp = (uint16_t)temp1 & (uint16_t)0x1U;
if ((uint16_t)temp)
{
ep = &xmc_device.ep[ep_num];
inepint = (uint32_t)xmc_device.endpoint_in_register[ep_num]->diepint;
diepint.d32 = inepint &
((((uint32_t)((uint32_t)xmc_device.device_register->dtknqr4_fifoemptymsk >> ep->address_u.address_st.number) &
0x1U) << 7U) | (uint32_t)diepmsk.d32);
if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
dieptsiz.d32 = xmc_device.endpoint_in_register[ep_num]->dieptsiz;
}
if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
if (diepint.b.emptyintr)
{
uint32_t bytes;
bytes = XMC_USBD_lWriteFifo(ep);
ep->xferCount += bytes;
ep->xferBuffer += bytes;
}
}
if (diepint.b.xfercompl)
{
if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
/* update xfer values */
if ((dieptsiz.b.pktcnt == 0U) && (dieptsiz.b.xfersize == 0U))
{
uint32_t Bytes = ep->xferLength - ep->xferCount;
ep->xferCount += Bytes;
ep->xferBuffer += Bytes;
}
}
if (ep->xferTotal==ep->xferLength)
{
ep->inInUse = 0U;
if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
/* mask fifo empty interrupt */
xmc_device.device_register->dtknqr4_fifoemptymsk =
(uint32_t)(xmc_device.device_register->dtknqr4_fifoemptymsk & ~(((uint32_t)1U << ep_num)));
}
xmc_device.EndpointEvent_cb(0x80U | ep_num,XMC_USBD_EP_EVENT_IN);
}
else
{
/* start next step of transfer */
XMC_USBD_lStartWriteXfer(ep);
}
}
XMC_USBD_ClearEventINEP((uint32_t)diepint.d32,ep_num);
}
ep_num++;
}
XMC_USBD_ClearEvent(XMC_USBD_EVENT_INEP);
}
/**
* @brief RX Fifo interrupt handler
*
* This function handles the interrupt, when the rx fifo is not empty anymore.
*/
static void XMC_USBD_lHandleRxFLvl(void)
{
device_grxsts_data_t data;
data.d32 = xmc_device.global_register->grxstsp;
switch (data.b.pktsts)
{
case XMC_USBD_GRXSTS_PKTSTS_GOUTNAK:
break;
case XMC_USBD_GRXSTS_PKTSTS_OUTCMPL:
break;
case XMC_USBD_GRXSTS_PKTSTS_OUTDATA:
XMC_USBD_lReadFifo((uint32_t)data.b.epnum,(uint32_t)data.b.bcnt);
break;
case XMC_USBD_GRXSTS_PKTSTS_SETUP:
XMC_USBD_lReadFifo((uint32_t)data.b.epnum,(uint32_t)data.b.bcnt);
break;
case XMC_USBD_GRXSTS_PKTSTS_SETUPCMPL:
break;
default:
break;
}
/* no need to clear */
}
/**
* @brief Global interrupt handler
*
* The handler first checks, which global interrupt has caused the interrupt
* and then dispatches interrupt to the corresponding sub-handler.
*/
void XMC_USBD_IRQHandler(const XMC_USBD_t *const obj)
{
gintmsk_data_t gintmsk;
gintsts_data_t data;
gintmsk.d32 = xmc_device.global_register->gintmsk;
data.d32 = xmc_device.global_register->gintsts & gintmsk.d32;
if (data.b.sofintr)
{
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_SOF);
XMC_USBD_ClearEvent(XMC_USBD_EVENT_SOF);
}
if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
if (data.b.rxstsqlvl)
{
/* Masked that interrupt so its only done once */
gintmsk.b.rxstsqlvl = 0U;
xmc_device.global_register->gintmsk = gintmsk.d32;
XMC_USBD_lHandleRxFLvl(); /* handle the interrupt */
gintmsk.b.rxstsqlvl = 1U;
xmc_device.global_register->gintmsk = gintmsk.d32;
}
}
if (data.b.erlysuspend)
{
XMC_USBD_ClearEvent(XMC_USBD_EVENT_EARLYSUSPEND);
}
if (data.b.usbsuspend)
{
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_SUSPEND);
XMC_USBD_ClearEvent(XMC_USBD_EVENT_SUSPEND);
}
if (data.b.wkupintr)
{
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_REMOTE_WAKEUP);
XMC_USBD_ClearEvent(XMC_USBD_EVENT_REMOTE_WAKEUP);
}
if (data.b.sessreqintr)
{
xmc_device.IsPowered = 1U;
xmc_device.DeviceEvent_cb(XMC_USBD_EVENT_POWER_ON);
XMC_USBD_ClearEvent(XMC_USBD_EVENT_POWER_ON);
}
if (data.b.usbreset)
{
XMC_USBD_lHandleUSBReset(obj);
}
if (data.b.enumdone)
{
XMC_USBD_lHandleEnumDone();
}
if (data.b.inepint)
{
XMC_USBD_lHandleIEPInt(obj);
}
if (data.b.outepintr)
{
XMC_USBD_lHandleOEPInt(obj);
}
if (data.b.otgintr)
{
XMC_USBD_lHandleOTGInt();
}
}
/*******************************************************************************
* API IMPLEMENTATION
*******************************************************************************/
/**
* Enables the USB0 module
**/
void XMC_USBD_Enable(void)
{
#if defined(CLOCK_GATING_SUPPORTED)
XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_USB0);
#endif
/* Reset and power up */
XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0);
XMC_SCU_POWER_EnableUsb();
}
/**
* Disables the USB0 module
**/
void XMC_USBD_Disable(void)
{
/* Clear Reset and power up */
XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0);
#if defined(CLOCK_GATING_SUPPORTED)
XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_USB0);
#endif
XMC_SCU_POWER_DisableUsb();
}
/**
* Clear the USB device event
**/
void XMC_USBD_ClearEvent(const XMC_USBD_EVENT_t event)
{
gintsts_data_t clear;
clear.d32 = 0U;
switch(event)
{
case (XMC_USBD_EVENT_POWER_ON):
clear.b.sessreqintr = 1U;
break;
case (XMC_USBD_EVENT_RESET):
clear.b.usbreset = 1U;
break;
case (XMC_USBD_EVENT_SUSPEND):
clear.b.usbsuspend = 1U;
break;
case (XMC_USBD_EVENT_RESUME):
clear.b.wkupintr = 1U;
break;
case (XMC_USBD_EVENT_REMOTE_WAKEUP):
clear.b.wkupintr = 1U;
break;
case (XMC_USBD_EVENT_SOF):
clear.b.sofintr = 1U;
break;
case (XMC_USBD_EVENT_EARLYSUSPEND):
clear.b.erlysuspend = 1U;
break;
case (XMC_USBD_EVENT_ENUMDONE):
clear.b.enumdone = 1U;
break;
case (XMC_USBD_EVENT_OUTEP):
clear.b.outepintr = 1U;
break;
default:
break;
}
xmc_device.global_register->gintsts = clear.d32;
}
/**
* Clear the USB OTG events
**/
static void XMC_USBD_lClearEventOTG(uint32_t event)
{
gotgint_data_t clear = { .d32 = 0U};
clear.d32 = event;
xmc_device.global_register->gotgint = clear.d32;
}
/**
* Clear the USB IN EP events
**/
void XMC_USBD_ClearEventINEP(uint32_t event,const uint8_t ep_num)
{
diepint_data_t clear;
clear.d32 = event;
xmc_device.endpoint_in_register[ep_num]->diepint = clear.d32;
}
/**
* Clear the USB OUT EP events
**/
void XMC_USBD_ClearEventOUTEP(uint32_t event,const uint8_t ep_num)
{
doepint_data_t clear;
clear.d32 = event;
xmc_device.endpoint_out_register[ep_num]->doepint = clear.d32;
}
/**
* Enable the USB OUT EP events
**/
void XMC_USBD_EnableEventOUTEP(uint32_t event)
{
doepint_data_t doepint;
doepint.d32 = event;
xmc_device.device_register->doepmsk |= doepint.d32;
}
/**
* Enable the USB IN EP events
**/
void XMC_USBD_EnableEventINEP(uint32_t event)
{
diepint_data_t diepint;
diepint.d32 = event;
xmc_device.device_register->diepmsk |= diepint.d32;
}
/**
* Gets the USB device capabilities
**/
XMC_USBD_CAPABILITIES_t XMC_USBD_GetCapabilities()
{
XMC_USBD_CAPABILITIES_t cap={0U};
cap.event_connect = 1U;
cap.event_disconnect = 1U;
#if UC_SERIES == 45
cap.event_power_off = 1U;
cap.event_power_on = 1U;
#else
cap.event_power_off = 0U;
cap.event_power_on = 0U;
#endif
cap.event_high_speed = 0U;
cap.event_remote_wakeup = 1U;
cap.event_reset = 1U;
cap.event_resume = 1U;
cap.event_suspend = 1U;
cap.reserved = 0U;
return cap;
}
/**
* Initializes the USB device
**/
XMC_USBD_STATUS_t XMC_USBD_Init(XMC_USBD_t *obj)
{
uint8_t *XMC_USBD_BASE_ADDRESS;
uint32_t i;
gahbcfg_data_t gahbcfg;
gusbcfg_data_t gusbcfg;
dcfg_data_t dcfg;
dctl_data_t dctl;
gintmsk_data_t gintmsk;
XMC_ASSERT("XMC_USBD_Init: obj.usbd_max_num_eps not of type XMC_USBD_MAX_NUM_EPS_t",
XMC_USBD_CHECK_INPUT_MAX_NUM_EPS(obj->usbd_max_num_eps))
XMC_USBD_Enable();
usbd_init = obj;
/* Filling out buffer size */
for(i = 0U;i < (uint32_t)XMC_USBD_NUM_EPS;i++)
{
XMC_USBD_EP_OUT_BUFFERSIZE[i] = XMC_USBD_EP0_BUFFER_SIZE;
XMC_USBD_EP_IN_BUFFERSIZE[i] = XMC_USBD_EP0_BUFFER_SIZE;
}
/* clear device status */
memset((void*)&xmc_device,0x0U,sizeof(XMC_USBD_DEVICE_t));
/* assign callbacks */
xmc_device.DeviceEvent_cb = obj->cb_xmc_device_event;
xmc_device.EndpointEvent_cb = obj->cb_endpoint_event;
XMC_USBD_BASE_ADDRESS = (uint8_t *)(obj->usbd);
/* assign register address */
xmc_device.global_register = (dwc_otg_core_global_regs_t*)(obj->usbd);
xmc_device.device_register = ((dwc_otg_device_global_regs_t*)(XMC_USBD_BASE_ADDRESS + DWC_DEV_GLOBAL_REG_OFFSET));
for (i = 0U;i < (uint32_t)XMC_USBD_NUM_EPS;i++)
{
xmc_device.endpoint_in_register[i] = (dwc_otg_dev_in_ep_regs_t*)(XMC_USBD_BASE_ADDRESS + DWC_DEV_IN_EP_REG_OFFSET +
((uint32_t)DWC_EP_REG_OFFSET*i));
}
for (i = 0U;i < (uint32_t)XMC_USBD_NUM_EPS;i++)
{
xmc_device.endpoint_out_register[i] = (dwc_otg_dev_out_ep_regs_t*)(XMC_USBD_BASE_ADDRESS +
DWC_DEV_OUT_EP_REG_OFFSET +
((uint32_t)DWC_EP_REG_OFFSET*i));
}
for (i = 0U;i < (uint32_t)XMC_USBD_NUM_TX_FIFOS;i++)
{
xmc_device.fifo[i] = (uint32_t*)(XMC_USBD_BASE_ADDRESS +
XMC_USBD_TX_FIFO_REG_OFFSET +
(i * XMC_USBD_TX_FIFO_OFFSET));
}
/* obj data structure for endpoint 0 */
/* Done by driver core */
/* configure ahb details */
gahbcfg.d32 = xmc_device.global_register->gahbcfg;
gahbcfg.b.glblintrmsk = 1U; /* enable interrupts ( global mask ) */
gahbcfg.b.nptxfemplvl_txfemplvl = 1U;
if(obj->usbd_transfer_mode == XMC_USBD_USE_DMA)
{
/* Enable dma if needed */
gahbcfg.b.dmaenable = 1U; /* enable dma if needed */
}
else
{
gahbcfg.b.dmaenable = 0U;
}
xmc_device.global_register->gahbcfg = gahbcfg.d32;
/* configure usb details */
gusbcfg.d32= xmc_device.global_register->gusbcfg;
gusbcfg.b.force_dev_mode = 1U; /* force us into device mode */
gusbcfg.b.srpcap = 1U; /* enable session request protocoll */
xmc_device.global_register->gusbcfg = gusbcfg.d32;
/* Device init */
/* configure device speed */
dcfg.d32 = xmc_device.device_register->dcfg;
dcfg.b.devspd = XMC_USBD_DCFG_DEVSPD_FS;
dcfg.b.descdma = 0U;
xmc_device.device_register->dcfg = dcfg.d32;
/* configure device functions */
dctl.d32 = xmc_device.device_register->dctl;
dctl.b.sftdiscon = 1U; /* disconnect the device until its connected by the user */
/* all other config is done by default register value */
xmc_device.device_register->dctl = dctl.d32;
/* flush the fifos for proper operation */
XMC_USBD_lFlushTXFifo((uint8_t)0x10U); /* 0x10 == all fifos, see doc */
XMC_USBD_lFlushRXFifo();
/* Enable Global Interrupts */
/* clear interrupt status bits prior to unmasking */
xmc_device.global_register->gintmsk = 0U; /* disable all interrupts */
xmc_device.global_register->gintsts = 0xFFFFFFFFU; /* clear all interrupts */
gintmsk.d32 = 0U;
/* enable common interrupts */
gintmsk.b.modemismatch = 1U;
gintmsk.b.otgintr = 1U;
gintmsk.b.sessreqintr = 1U;
/* enable device interrupts */
gintmsk.b.usbreset = 1U;
gintmsk.b.enumdone = 1U;
gintmsk.b.erlysuspend = 1U;
gintmsk.b.usbsuspend = 1U;
gintmsk.b.wkupintr = 1U;
gintmsk.b.sofintr = 1U;
if(obj->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
gintmsk.b.rxstsqlvl = 1U;
}
gintmsk.b.outepintr = 1U;
gintmsk.b.inepintr = 1U;
xmc_device.global_register->gintmsk = gintmsk.d32;
return XMC_USBD_STATUS_OK;
}
/**
* Uninitializes the USB device
**/
XMC_USBD_STATUS_t XMC_USBD_Uninitialize()
{
/* Disconnect the device */
dctl_data_t dctl;
dctl.d32 = xmc_device.device_register->dctl;
dctl.b.sftdiscon = 1U;
xmc_device.device_register->dctl = dctl.d32;
/* clean up */
memset((void*)&xmc_device,0U,sizeof(xmc_device));
return XMC_USBD_STATUS_OK;
}
/**
* Connects the USB device to host
**/
XMC_USBD_STATUS_t XMC_USBD_DeviceConnect()
{
/* Just disable softdisconnect */
dctl_data_t dctl;
dctl.d32 = xmc_device.device_register->dctl;
dctl.b.sftdiscon = 0U;
xmc_device.device_register->dctl = dctl.d32;
return XMC_USBD_STATUS_OK;
}
/**
* Disconnects the USB device from host
**/
XMC_USBD_STATUS_t XMC_USBD_DeviceDisconnect()
{
dctl_data_t dctl;
dctl.d32 = xmc_device.device_register->dctl;
dctl.b.sftdiscon = 1U;
xmc_device.device_register->dctl = dctl.d32;
return XMC_USBD_STATUS_OK;
}
/**
* Gets the USB device state.
**/
XMC_USBD_STATE_t XMC_USBD_DeviceGetState(const XMC_USBD_t *const obj)
{
XMC_USBD_STATE_t state={0U};
state.speed = XMC_USBD_SPEED_FULL;
state.connected = xmc_device.IsConnected;
state.active = XMC_USBD_lDeviceActive(obj);
state.powered = xmc_device.IsPowered;
return state;
}
/**
* Prepares the endpoint to read next OUT packet
**/
XMC_USBD_STATUS_t XMC_USBD_EndpointReadStart(const uint8_t ep_addr, uint32_t size)
{
XMC_USBD_EP_t *ep = &xmc_device.ep[ep_addr & (uint8_t)XMC_USBD_EP_NUM_MASK];
XMC_USBD_STATUS_t result;
if (ep->outInUse || !ep->isConfigured)
{
result = XMC_USBD_STATUS_ERROR;
}
else
{
/* short the length to buffer size if needed */
if (size > ep->outBufferSize)
{
size = ep->outBufferSize;
}
/* set ep values */
ep->xferTotal = size;
ep->xferCount = 0U;
ep->xferLength = 0U;
ep->xferBuffer = ep->outBuffer;
ep->outBytesAvailable = 0U;
XMC_USBD_lStartReadXfer(ep);
result= XMC_USBD_STATUS_OK;
}
return result;
}
/**
* Reads the number of bytes from the USB OUT endpoint
**/
int32_t XMC_USBD_EndpointRead(const uint8_t ep_num,uint8_t * buffer,uint32_t length)
{
XMC_USBD_EP_t *ep = &xmc_device.ep[ep_num];
if (length > ep->outBytesAvailable)
{
length = ep->outBytesAvailable;
}
memcpy(buffer,&ep->outBuffer[ep->outOffset],length);
ep->outBytesAvailable -= length;
if (ep->outBytesAvailable)
{
ep->outOffset += length;
}
else
{
ep->outOffset = 0U;
}
return (int32_t)length;
}
/**
* Writes number of bytes in to the USB IN endpoint.
**/
int32_t XMC_USBD_EndpointWrite(const uint8_t ep_num,const uint8_t * buffer,uint32_t length)
{
XMC_USBD_EP_t * ep = &xmc_device.ep[ep_num & (uint8_t)XMC_USBD_EP_NUM_MASK];
int32_t result;
if (!ep->isConfigured)
{
result = (int32_t)XMC_USBD_STATUS_ERROR;
}
else if (ep->inInUse == 1U)
{
result=(int32_t)0;
}
else
{
if (length > ep->inBufferSize)
{
length = ep->inBufferSize;
}
/* copy data into input buffer for DMA and FIFO mode */
memcpy(ep->inBuffer,(const void *)buffer,length);
ep->xferBuffer = ep->inBuffer;
ep->xferTotal = length;
/* set transfer values */
ep->xferLength = 0U;
ep->xferCount = 0U;
ep->inInUse = 1U;
/* start the transfer */
XMC_USBD_lStartWriteXfer(ep);
result=(int32_t)ep->xferTotal;
}
return result;
}
/**
* Sets the USB device address.
**/
XMC_USBD_STATUS_t XMC_USBD_DeviceSetAddress(const uint8_t address,const XMC_USBD_SET_ADDRESS_STAGE_t stage)
{
dcfg_data_t data;
data.d32 = xmc_device.device_register->dcfg;
if (stage == XMC_USBD_SET_ADDRESS_STAGE_SETUP)
{
data.b.devaddr = address;
xmc_device.device_register->dcfg = data.d32;
}
return XMC_USBD_STATUS_OK;
}
/**
* Set/clear stall on the selected endpoint.
**/
XMC_USBD_STATUS_t XMC_USBD_EndpointStall(const uint8_t ep_addr, const bool stall)
{
depctl_data_t data;
XMC_USBD_EP_t *ep = &xmc_device.ep[(ep_addr & (uint8_t)XMC_USBD_EP_NUM_MASK)];
if (stall)
{
if (ep_addr & (uint8_t)XMC_USBD_ENDPOINT_DIRECTION_MASK)
{
/*set stall bit */
data.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
data.b.stall = 1U;
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32;
}
else
{
/*set stall bit */
data.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
data.b.stall = 1U;
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32;
}
ep->isStalled = 1U;
}
else
{
/* just clear stall bit */
if (ep_addr & (uint8_t)XMC_USBD_ENDPOINT_DIRECTION_MASK)
{
data.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
data.b.stall = 0U;
data.b.setd0pid = 1U; /* reset pid to 0 */
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32;
}
else
{
data.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
data.b.stall = 0U;
data.b.setd0pid = 1U; /* reset pid to 0 */
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32;
}
ep->isStalled = 0U;
}
return XMC_USBD_STATUS_OK;
}
/**
* Aborts the data transfer on the selected endpoint
**/
XMC_USBD_STATUS_t XMC_USBD_EndpointAbort(const uint8_t ep_addr) {
XMC_USBD_EP_t *ep = &xmc_device.ep[ep_addr & (uint8_t)XMC_USBD_ENDPOINT_NUMBER_MASK];
if (ep->address_u.address_st.direction)
{
ep->inInUse = 0U;
}
if (!ep->address_u.address_st.direction)
{
ep->outInUse = 0U;
}
ep->isStalled = 0U;
ep->outBytesAvailable = 0U;
ep->outOffset = 0U;
ep->xferLength = 0U;
ep->xferCount = 0U;
ep->xferTotal = 0U;
return XMC_USBD_STATUS_OK;
}
/**
* Configures the given endpoint
**/
XMC_USBD_STATUS_t XMC_USBD_EndpointConfigure(const uint8_t ep_addr,
const XMC_USBD_ENDPOINT_TYPE_t ep_type,
const uint16_t ep_max_packet_size)
{
daint_data_t daintmsk;
XMC_USBD_EP_t *ep;
daintmsk.d32 = xmc_device.device_register->daintmsk;
ep =&xmc_device.ep[ep_addr & (uint32_t)XMC_USBD_ENDPOINT_NUMBER_MASK];
memset((void*)ep,0x0U,sizeof(XMC_USBD_EP_t)); /* clear endpoint structure */
/* do ep configuration */
ep->address_u.address = ep_addr;
ep->isConfigured = 1U;
ep->maxPacketSize = (uint8_t)ep_max_packet_size;
if (ep->address_u.address != 0U)
{
ep->maxTransferSize = (uint32_t)XMC_USBD_MAX_TRANSFER_SIZE;
}
else
{
ep->maxTransferSize = (uint32_t)XMC_USBD_MAX_TRANSFER_SIZE_EP0;
}
/* transfer buffer */
ep->inBuffer = XMC_USBD_EP_IN_BUFFER[ep->address_u.address_st.number];
ep->outBuffer = XMC_USBD_EP_OUT_BUFFER[ep->address_u.address_st.number];
/* buffer size*/
ep->inBufferSize = XMC_USBD_EP_IN_BUFFERSIZE[ep->address_u.address_st.number];
ep->outBufferSize = XMC_USBD_EP_OUT_BUFFERSIZE[ep->address_u.address_st.number];
/* is in */
if ((ep->address_u.address_st.direction == 1U) || (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL))
{
depctl_data_t data;
data.d32 = xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl;
/*enable endpoint */
data.b.usbactep = 1U;
/* set ep type */
data.b.eptype = (uint8_t)ep_type;
/* set mps */
if (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL)
{
switch(ep_max_packet_size)
{
case (64U):
data.b.mps = 0x0U;
break;
case (32U):
data.b.mps = 0x1U;
break;
case (16U):
data.b.mps = 0x2U;
break;
case (8U):
data.b.mps = 0x3U;
break;
default:
break;
}
}
else
{
data.b.mps = ep_max_packet_size;
}
/* set first data0 pid */
data.b.setd0pid = 1U;
/* clear stall */
data.b.stall = 0U;
/* set tx fifo */
ep->txFifoNum = XMC_USBD_lAssignTXFifo(); /* get tx fifo */
data.b.txfnum = ep->txFifoNum;
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32; /* configure endpoint */
daintmsk.ep.in |= (uint16_t)((uint16_t)1U << (uint8_t)ep->address_u.address_st.number); /* enable interrupts for endpoint */
}
if ((ep->address_u.address_st.direction == 0U) || (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL))
{
/* is out */
depctl_data_t data;
data.d32 = xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl;
/*enable endpoint */
data.b.usbactep = 1U;
/* set ep type */
data.b.eptype = (uint8_t)ep_type;
/* set mps */
if (ep_type == XMC_USBD_ENDPOINT_TYPE_CONTROL)
{
switch(ep_max_packet_size)
{
case (64U):
data.b.mps = 0x0U;
break;
case (32U):
data.b.mps = 0x1U;
break;
case (16U):
data.b.mps = 0x2U;
break;
case (8U):
data.b.mps = 0x3U;
break;
default:
break;
}
}
else
{
data.b.mps = ep_max_packet_size;
}
/* set first data0 pid */
data.b.setd0pid = 1U;
/* clear stall */
data.b.stall =(uint8_t) 0U;
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32; /* configure endpoint */
daintmsk.ep.out |=(uint16_t) ((uint16_t)1U << (uint8_t)ep->address_u.address_st.number); /* enable interrupts */
}
xmc_device.device_register->daintmsk = daintmsk.d32;
return XMC_USBD_STATUS_OK;
}
/**
* Unconfigure the selected endpoint.
**/
XMC_USBD_STATUS_t XMC_USBD_EndpointUnconfigure(const uint8_t ep_addr)
{
XMC_USBD_EP_t *ep = &xmc_device.ep[ep_addr & (uint8_t)XMC_USBD_ENDPOINT_NUMBER_MASK];
depctl_data_t data;
daint_data_t daintmsk;
XMC_USBD_STATUS_t result;
uint32_t number_temp;
data.d32 = 0U;
daintmsk.d32 = xmc_device.device_register->daintmsk;
number_temp = (uint32_t)((uint32_t)1U << (uint8_t)ep->address_u.address_st.number);
/* if not configured return an error */
if (!ep->isConfigured)
{
result = XMC_USBD_STATUS_ERROR;
}
else
{
/* disable the endpoint, deactivate it and only send naks */
data.b.usbactep = 0U;
data.b.epdis = 1U;
data.b.snak = 1U;
data.b.stall = 0U;
ep->isConfigured = 0U;
ep->isStalled = 0U;
ep->outInUse = 0U;
ep->inInUse = 0U;
/* chose register based on the direction. Control Endpoint need both */
if ((ep->address_u.address_st.direction == 1U) || (ep->type == (uint8_t)XMC_USBD_ENDPOINT_TYPE_CONTROL))
{
/* disable endpoint configuration */
xmc_device.endpoint_in_register[ep->address_u.address_st.number]->diepctl = data.d32;
/* disable interrupts */
daintmsk.ep.in = (uint16_t)((uint32_t)daintmsk.ep.in & (~(uint32_t)number_temp));
}
if ((ep->address_u.address_st.direction == 0U) || (ep->type == (uint8_t)XMC_USBD_ENDPOINT_TYPE_CONTROL))
{
xmc_device.endpoint_out_register[ep->address_u.address_st.number]->doepctl = data.d32;
daintmsk.ep.out = (uint16_t)((uint32_t)daintmsk.ep.out & (~(uint32_t)number_temp));
if(usbd_init->usbd_transfer_mode == XMC_USBD_USE_FIFO)
{
xmc_device.device_register->dtknqr4_fifoemptymsk &= ~number_temp;
}
}
xmc_device.device_register->daintmsk = daintmsk.d32;
XMC_USBD_lUnassignFifo(ep->txFifoNum); /* free fifo */
result = XMC_USBD_STATUS_OK;
}
return result;
}
/**
* Gets the current USB frame number
**/
uint16_t XMC_USBD_GetFrameNumber(void)
{
uint16_t result;
dsts_data_t dsts;
dsts.d32 = xmc_device.device_register->dsts;
result = (uint16_t)dsts.b.soffn;
return result;
}
/**
* Gets the USB speed enumeration completion status.
* This should not be used for the actual USB enumeration completion status. For the actual USB enumeration status,
* the application layer should check for the completion of USB standard request Set configuration.
**/
uint32_t XMC_USBD_IsEnumDone(void)
{
return (uint32_t)((uint8_t)xmc_device.IsConnected && (uint8_t)xmc_device.IsPowered);
}
/***
* MISRA C 2004 Deviations
*
* 1. cast from pointer to pointer [MISRA 2004 Rule 11.4]
* 2. cast from pointer to unsigned int [Encompasses MISRA 2004 Rule 11.1], [MISRA 2004 Rule 11.3]
* 3. call to function 'memset()' not made in the presence of a prototype [MISRA 2004 Rule 8.1]
* 4. No explicit type for symbol '_Bool', int assumed
*/
#endif /* defined(USB0) */