1318 lines
46 KiB
C
1318 lines
46 KiB
C
/**
|
|
*******************************************************************************
|
|
* @file hc32_ll_usb.c
|
|
* @brief USB core driver.
|
|
@verbatim
|
|
Change Logs:
|
|
Date Author Notes
|
|
2022-03-31 CDT First version
|
|
2022-06-30 CDT Add USB core ID select function
|
|
2022-10-31 CDT Add USB DMA function
|
|
2023-09-30 CDT Fix bug for function usb_clearepstall()
|
|
Modify typo
|
|
@endverbatim
|
|
*******************************************************************************
|
|
* Copyright (C) 2022-2023, Xiaohua Semiconductor Co., Ltd. All rights reserved.
|
|
*
|
|
* This software component is licensed by XHSC under BSD 3-Clause license
|
|
* (the "License"); You may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at:
|
|
* opensource.org/licenses/BSD-3-Clause
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* Include files
|
|
******************************************************************************/
|
|
#include "hc32_ll_usb.h"
|
|
#include "hdl_clk.h"
|
|
|
|
/**
|
|
* @addtogroup LL_Driver
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @defgroup LL_USB USB
|
|
* @brief USB Driver Library
|
|
* @{
|
|
*/
|
|
|
|
#if (LL_USB_ENABLE == DDL_ON)
|
|
|
|
/*******************************************************************************
|
|
* Local type definitions ('typedef')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Local pre-processor symbols/macros ('#define')
|
|
******************************************************************************/
|
|
/* Parameters check */
|
|
#define IS_USB_CORE_ID(x) \
|
|
( ((x) == USBFS_CORE_ID))
|
|
|
|
#define IS_USB_PHY_TYPE(x) \
|
|
( ((x) == USBHS_PHY_EMBED))
|
|
|
|
/*******************************************************************************
|
|
* Global variable definitions (declared in header file with 'extern')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Local function prototypes ('static')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Local variable definitions ('static')
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Function implementation - global ('extern') and local ('static')
|
|
******************************************************************************/
|
|
/**
|
|
* @defgroup USB_Global_Functions USB Global Functions
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief core software reset
|
|
* @param [in] USBx usb instance
|
|
* @retval None
|
|
*/
|
|
void usb_coresoftrst(LL_USB_TypeDef *USBx)
|
|
{
|
|
__IO uint8_t u8Status = USB_OK;;
|
|
__IO uint32_t u32grstctl = 0UL;
|
|
__IO uint32_t u32Count = 0UL;
|
|
|
|
/* Wait for AHB master to be idle. */
|
|
do {
|
|
hdl_delay_us(1UL);
|
|
u32grstctl = READ_REG32(USBx->GREGS->GRSTCTL);
|
|
if (++u32Count > 100000UL) {
|
|
u8Status = USB_ERROR;
|
|
}
|
|
} while (0UL == (u32grstctl & USBFS_GRSTCTL_AHBIDL));
|
|
|
|
if (USB_OK == u8Status) {
|
|
/* Write the Core Soft Reset bit to reset the USB core */
|
|
u32Count = 0UL;
|
|
u32grstctl |= USBFS_GRSTCTL_CSRST;
|
|
WRITE_REG32(USBx->GREGS->GRSTCTL, u32grstctl);
|
|
|
|
/* Wait for the reset finishing */
|
|
do {
|
|
u32grstctl = READ_REG32(USBx->GREGS->GRSTCTL);
|
|
if (u32Count > 100000UL) {
|
|
break;
|
|
}
|
|
u32Count++;
|
|
hdl_delay_us(1UL);
|
|
} while (0UL != (u32grstctl & USBFS_GRSTCTL_CSRST));
|
|
/* Wait for at least 3 PHY clocks after the core resets */
|
|
hdl_delay_us(3UL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Writes a packet whose byte number is len into the Tx FIFO associated
|
|
* with the EP
|
|
* @param [in] USBx usb instance
|
|
* @param [in] src source pointer used to hold the transmitted data
|
|
* @param [in] ch_ep_num end point index
|
|
* @param [in] len length in bytes
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval None
|
|
*/
|
|
void usb_wrpkt(LL_USB_TypeDef *USBx, uint8_t *src, uint8_t ch_ep_num, uint16_t len, uint8_t u8DmaEn)
|
|
{
|
|
__IO uint32_t u32pAddr;
|
|
__IO uint32_t *fifo;
|
|
uint32_t u32Count32b;
|
|
uint32_t u32Tmp;
|
|
if (u8DmaEn == 0U) {
|
|
u32Count32b = (len + 3UL);
|
|
u32Count32b = u32Count32b >> 2U;
|
|
fifo = USBx->DFIFO[ch_ep_num];
|
|
u32Tmp = 0UL;
|
|
while (u32Tmp < u32Count32b) {
|
|
WRITE_REG32(*fifo, *((uint32_t *)src));
|
|
u32pAddr = (uint32_t)src;
|
|
src = (uint8_t *)(u32pAddr + 4U);
|
|
u32Tmp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Reads a packet whose byte number is len from the Rx FIFO
|
|
* @param [in] USBx usb instance
|
|
* @param [in] dest destination pointer that point to the received data
|
|
* @param [in] len number of bytes
|
|
* @retval None
|
|
*/
|
|
void usb_rdpkt(LL_USB_TypeDef *USBx, uint8_t *dest, uint16_t len)
|
|
{
|
|
uint32_t u32Tmp;
|
|
__IO uint32_t u32Count32b;
|
|
__IO uint32_t u32pAddr;
|
|
|
|
__IO uint32_t *fifo = USBx->DFIFO[0];
|
|
u32Count32b = (len + 3UL);
|
|
u32Count32b = u32Count32b >> 2U;
|
|
u32pAddr = 0UL;
|
|
u32Tmp = 0UL;
|
|
while (u32Tmp < u32Count32b) {
|
|
*(uint32_t *)dest = READ_REG32(*fifo);
|
|
u32pAddr = (uint32_t)dest;
|
|
dest = (uint8_t *)(u32pAddr + 4U);
|
|
u32Tmp++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize the addresses of the core registers.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] pstcPortIdentify usb core and phy select
|
|
* @param [in] basic_cfgs usb core basic cfgs
|
|
* @retval None
|
|
*/
|
|
void usb_setregaddr(LL_USB_TypeDef *USBx, stc_usb_port_identify *pstcPortIdentify, USB_CORE_BASIC_CFGS *basic_cfgs)
|
|
{
|
|
uint32_t u32Tmp = 0UL;
|
|
uint32_t u32baseAddr = CM_USBFS_BASE;
|
|
DDL_ASSERT(IS_USB_CORE_ID(pstcPortIdentify->u8CoreID));
|
|
#if defined (USB_INTERNAL_DMA_ENABLED)
|
|
basic_cfgs->dmaen = 1U;
|
|
#else
|
|
basic_cfgs->dmaen = 0U;
|
|
#endif
|
|
/* initialize device cfg following its address */
|
|
basic_cfgs->host_chnum = USB_MAX_CH_NUM;
|
|
basic_cfgs->dev_epnum = USB_MAX_EP_NUM;
|
|
basic_cfgs->core_type = pstcPortIdentify->u8CoreID;
|
|
basic_cfgs->phy_type = USBHS_PHY_EMBED;
|
|
if (USBFS_CORE_ID == pstcPortIdentify->u8CoreID) {
|
|
#ifdef USB_FS_MODE
|
|
u32baseAddr = CM_USBFS_BASE;
|
|
#endif
|
|
} else {
|
|
#ifdef USB_HS_MODE
|
|
u32baseAddr = CM_USBHS_BASE;
|
|
#endif
|
|
}
|
|
|
|
USBx->GREGS = (USB_CORE_GREGS *)(u32baseAddr + 0UL);
|
|
USBx->DREGS = (USB_CORE_DREGS *)(u32baseAddr + 0x800UL);
|
|
|
|
while (u32Tmp < basic_cfgs->dev_epnum) {
|
|
USBx->INEP_REGS[u32Tmp] = (USB_CORE_INEPREGS *)(u32baseAddr + 0x900UL + (u32Tmp * 0x20UL));
|
|
USBx->OUTEP_REGS[u32Tmp] = (USB_CORE_OUTEPREGS *)(u32baseAddr + 0xb00UL + (u32Tmp * 0x20UL));
|
|
u32Tmp++;
|
|
}
|
|
u32Tmp = 0UL;
|
|
while (u32Tmp < basic_cfgs->dev_epnum) {
|
|
USBx->DFIFO[u32Tmp] = (uint32_t *)(u32baseAddr + 0x1000UL + (u32Tmp * 0x1000UL));
|
|
u32Tmp++;
|
|
}
|
|
USBx->GCCTL = (uint32_t *)(u32baseAddr + 0xe00UL);
|
|
#ifdef USE_HOST_MODE /* if the application mode is host */
|
|
USBx->HREGS = (USB_CORE_HREGS *)(u32baseAddr + 0x400UL);
|
|
USBx->HPRT = (uint32_t *)(u32baseAddr + 0x440UL);
|
|
u32Tmp = 0UL;
|
|
while (u32Tmp < basic_cfgs->host_chnum) {
|
|
USBx->HC_REGS[u32Tmp] = (USB_CORE_HC_REGS *)(u32baseAddr + 0x500UL + (u32Tmp * 0x20UL));
|
|
u32Tmp++;
|
|
}
|
|
#endif /* USE_HOST_MODE */
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes the USB controller registers and prepares the core
|
|
* device mode or host mode operation.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] basic_cfgs usb core basic cfgs
|
|
* @retval None
|
|
*/
|
|
void usb_initusbcore(LL_USB_TypeDef *USBx, USB_CORE_BASIC_CFGS *basic_cfgs)
|
|
{
|
|
/* reset the core through core soft reset */
|
|
usb_coresoftrst(USBx);
|
|
|
|
/* Select PHY for USB core*/
|
|
usb_PhySelect(USBx, basic_cfgs->phy_type);
|
|
/* reset the core through core soft reset */
|
|
usb_coresoftrst(USBx);
|
|
hdl_delay_ms(20UL);
|
|
if (basic_cfgs->dmaen == 1U) {
|
|
/* burst length/type(HBstLen) 64-words x32-bit, core operates in a DMA mode*/
|
|
usb_BurstLenConfig(USBx, 5U);
|
|
usb_DmaCmd(USBx, 1U);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Flush a Tx FIFO whose index is num
|
|
* @param [in] USBx usb instance
|
|
* @param [in] num txFIFO index
|
|
* @retval None
|
|
*/
|
|
void usb_txfifoflush(LL_USB_TypeDef *USBx, uint32_t num)
|
|
{
|
|
__IO uint32_t u32grstctl;
|
|
__IO uint32_t u32Tmp = 0UL;
|
|
|
|
u32grstctl = USBFS_GRSTCTL_TXFFLSH | ((num & 0x1FUL) << USBFS_GRSTCTL_TXFNUM_POS);
|
|
/* set the TxFIFO Flush bit, set TxFIFO Number */
|
|
WRITE_REG32(USBx->GREGS->GRSTCTL, u32grstctl);
|
|
|
|
/* wait for the finishing of txFIFO flushing */
|
|
do {
|
|
u32grstctl = READ_REG32(USBx->GREGS->GRSTCTL);
|
|
if (u32Tmp <= 200000UL) {
|
|
u32Tmp++;
|
|
} else {
|
|
break;
|
|
}
|
|
hdl_delay_us(1UL);
|
|
} while (0UL != (u32grstctl & USBFS_GRSTCTL_TXFFLSH));
|
|
/* Wait for at least 3 PHY clocks after the txfifo has been flushed */
|
|
hdl_delay_us(3UL);
|
|
}
|
|
|
|
/**
|
|
* @brief Flush the whole rxFIFO
|
|
* @param [in] USBx usb instance
|
|
* @retval None
|
|
*/
|
|
void usb_rxfifoflush(LL_USB_TypeDef *USBx)
|
|
{
|
|
__IO uint32_t u32grstctl;
|
|
__IO uint32_t u32Tmp = 0UL;
|
|
|
|
u32grstctl = USBFS_GRSTCTL_RXFFLSH; /* set the RxFIFO Flush bit */
|
|
WRITE_REG32(USBx->GREGS->GRSTCTL, u32grstctl);
|
|
/* wait for the finishing of rxFIFO flushing */
|
|
do {
|
|
u32grstctl = READ_REG32(USBx->GREGS->GRSTCTL);
|
|
if (u32Tmp <= 200000UL) {
|
|
u32Tmp++;
|
|
} else {
|
|
break;
|
|
}
|
|
hdl_delay_us(1UL);
|
|
} while (0UL != (u32grstctl & USBFS_GRSTCTL_RXFFLSH));
|
|
/* Wait for at least 3 PHY clocks after the rxfifo has been flushed */
|
|
hdl_delay_us(3UL);
|
|
}
|
|
|
|
/**
|
|
* @brief set the core to be host mode or device mode through the second
|
|
* input parameter.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] mode mode of HOST_MODE or DEVICE_MODE that the core would be
|
|
* @retval None
|
|
*/
|
|
void usb_modeset(LL_USB_TypeDef *USBx, uint8_t mode)
|
|
{
|
|
if (mode == HOST_MODE) {
|
|
MODIFY_REG32(USBx->GREGS->GUSBCFG, USBFS_GUSBCFG_FHMOD | USBFS_GUSBCFG_FDMOD, USBFS_GUSBCFG_FHMOD);
|
|
} else {
|
|
MODIFY_REG32(USBx->GREGS->GUSBCFG, USBFS_GUSBCFG_FHMOD | USBFS_GUSBCFG_FDMOD, USBFS_GUSBCFG_FDMOD);
|
|
}
|
|
/* wate for the change to take effect */
|
|
hdl_delay_ms(50UL);
|
|
}
|
|
|
|
#ifdef USE_DEVICE_MODE
|
|
|
|
/**
|
|
* @brief initializes the initial status of all endpoints of the device to be
|
|
* disable.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] u8EpNum EP number
|
|
* @retval None
|
|
*/
|
|
void usb_devepdis(LL_USB_TypeDef *USBx, uint8_t u8EpNum)
|
|
{
|
|
uint8_t u8Tmp = 0U;
|
|
|
|
while (u8Tmp < u8EpNum) {
|
|
if (0UL != READ_REG32_BIT(USBx->INEP_REGS[u8Tmp]->DIEPCTL, USBFS_DIEPCTL_EPENA)) {
|
|
WRITE_REG32(USBx->INEP_REGS[u8Tmp]->DIEPCTL, USBFS_DIEPCTL_EPDIS | USBFS_DIEPCTL_SNAK);
|
|
} else {
|
|
WRITE_REG32(USBx->INEP_REGS[u8Tmp]->DIEPCTL, 0UL);
|
|
}
|
|
WRITE_REG32(USBx->INEP_REGS[u8Tmp]->DIEPTSIZ, 0UL);
|
|
WRITE_REG32(USBx->INEP_REGS[u8Tmp]->DIEPINT, 0xFFUL);
|
|
u8Tmp++;
|
|
}
|
|
|
|
u8Tmp = 0U;
|
|
while (u8Tmp < u8EpNum) {
|
|
if (0UL != READ_REG32_BIT(USBx->OUTEP_REGS[u8Tmp]->DOEPCTL, USBFS_DOEPCTL_EPENA)) {
|
|
WRITE_REG32(USBx->OUTEP_REGS[u8Tmp]->DOEPCTL, USBFS_DOEPCTL_EPDIS | USBFS_DOEPCTL_SNAK);
|
|
} else {
|
|
WRITE_REG32(USBx->OUTEP_REGS[u8Tmp]->DOEPCTL, 0UL);
|
|
}
|
|
WRITE_REG32(USBx->OUTEP_REGS[u8Tmp]->DOEPTSIZ, 0UL);
|
|
WRITE_REG32(USBx->OUTEP_REGS[u8Tmp]->DOEPINT, 0xFFUL);
|
|
u8Tmp++;
|
|
}
|
|
}
|
|
|
|
#ifdef USB_FS_MODE
|
|
static void usb_DevFSFifoConfig(LL_USB_TypeDef *USBx)
|
|
{
|
|
uint32_t u32StardAddr;
|
|
|
|
WRITE_REG32(USBx->GREGS->GRXFSIZ, RX_FIFO_FS_SIZE);
|
|
/* set txFIFO and rxFIFO size of EP0 */
|
|
u32StardAddr = RX_FIFO_FS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->HNPTXFSIZ,
|
|
(RX_FIFO_FS_SIZE << USBFS_HNPTXFSIZ_NPTXFSA_POS) | (TX0_FIFO_FS_SIZE << USBFS_HNPTXFSIZ_NPTXFD_POS));
|
|
/* set txFIFO size of EP1 */
|
|
u32StardAddr += TX0_FIFO_FS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[0],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX1_FIFO_FS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP2 */
|
|
u32StardAddr += TX1_FIFO_FS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[1],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX2_FIFO_FS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP3 */
|
|
u32StardAddr += TX2_FIFO_FS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[2],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX3_FIFO_FS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP4 */
|
|
u32StardAddr += TX3_FIFO_FS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[3],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX4_FIFO_FS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP5 */
|
|
u32StardAddr += TX4_FIFO_FS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[4],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX5_FIFO_FS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
}
|
|
#endif
|
|
|
|
#ifdef USB_HS_MODE
|
|
static void usb_DevHSFifoConfig(LL_USB_TypeDef *USBx)
|
|
{
|
|
uint32_t u32StardAddr;
|
|
|
|
WRITE_REG32(USBx->GREGS->GRXFSIZ, RX_FIFO_HS_SIZE);
|
|
/* set txFIFO and rxFIFO size of EP0 */
|
|
u32StardAddr = RX_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->HNPTXFSIZ,
|
|
(RX_FIFO_HS_SIZE << USBFS_HNPTXFSIZ_NPTXFSA_POS) | (TX0_FIFO_HS_SIZE << USBFS_HNPTXFSIZ_NPTXFD_POS));
|
|
/* set txFIFO size of EP1 */
|
|
u32StardAddr += TX0_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[0],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX1_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP2 */
|
|
u32StardAddr += TX1_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[1],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX2_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP3 */
|
|
u32StardAddr += TX2_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[2],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX3_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP4 */
|
|
u32StardAddr += TX3_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[3],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX4_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP5 */
|
|
u32StardAddr += TX4_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[4],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX5_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP6 */
|
|
u32StardAddr += TX5_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[5],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX6_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP7 */
|
|
u32StardAddr += TX6_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[6],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX7_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP8 */
|
|
u32StardAddr += TX7_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[7],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX8_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP9 */
|
|
u32StardAddr += TX8_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[8],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX9_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP10 */
|
|
u32StardAddr += TX9_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[9],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX10_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP11 */
|
|
u32StardAddr += TX10_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[10],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX11_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP12 */
|
|
u32StardAddr += TX11_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[11],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX12_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP13 */
|
|
u32StardAddr += TX12_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[12],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX13_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP14 */
|
|
u32StardAddr += TX13_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[13],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX14_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
/* set txFIFO size of EP15 */
|
|
u32StardAddr += TX14_FIFO_HS_SIZE;
|
|
WRITE_REG32(USBx->GREGS->DIEPTXF[14],
|
|
(u32StardAddr << USBFS_DIEPTXF_INEPTXSA_POS) | (TX15_FIFO_HS_SIZE << USBFS_DIEPTXF_INEPTXFD_POS));
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief initializes the USB controller, include the size of txFIFO, rxFIFO
|
|
* status of endpoints, interrupt register etc. Details are shown as
|
|
* follows.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] basic_cfgs usb core basic cfgs
|
|
* @retval None
|
|
*/
|
|
void usb_devmodeinit(LL_USB_TypeDef *USBx, USB_CORE_BASIC_CFGS *basic_cfgs)
|
|
{
|
|
usb_FrameIntervalConfig(USBx, USB_FRAME_INTERVAL_80);
|
|
usb_DevPhySelect(USBx, basic_cfgs->phy_type);
|
|
|
|
if (basic_cfgs->core_type == 0U) {
|
|
#ifdef USB_FS_MODE
|
|
usb_DevFSFifoConfig(USBx);
|
|
#endif
|
|
} else {
|
|
#ifdef USB_HS_MODE
|
|
usb_DevHSFifoConfig(USBx);
|
|
#endif
|
|
}
|
|
|
|
usb_clrandmskepint(USBx);
|
|
usb_devepdis(USBx, basic_cfgs->dev_epnum);
|
|
usb_coreconn(USBx);
|
|
usb_devinten(USBx, basic_cfgs->dmaen);
|
|
}
|
|
|
|
/**
|
|
* @brief Enable the interrupt setting when in device mode.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval None
|
|
*/
|
|
void usb_devinten(LL_USB_TypeDef *USBx, uint8_t u8DmaEn)
|
|
{
|
|
uint32_t u32gintmskTmp = 0UL;
|
|
|
|
WRITE_REG32(USBx->GREGS->GINTMSK, 0UL);
|
|
WRITE_REG32(USBx->GREGS->GINTSTS, 0xBFFFFFFFUL);
|
|
/* Enable the normal interrupt setting */
|
|
usb_normalinten(USBx);
|
|
if (u8DmaEn == 0U) {
|
|
u32gintmskTmp |= USBFS_GINTMSK_RXFNEM;
|
|
}
|
|
/* Enable interrupts bits corresponding to the Device mode */
|
|
u32gintmskTmp |= (USBFS_GINTMSK_USBSUSPM | USBFS_GINTMSK_USBRSTM | USBFS_GINTMSK_ENUMDNEM
|
|
| USBFS_GINTMSK_IEPIM | USBFS_GINTMSK_OEPIM | USBFS_GINTMSK_SOFM
|
|
| USBFS_GINTMSK_IISOIXFRM | USBFS_GINTMSK_IPXFRM_INCOMPISOOUTM);
|
|
#ifdef VBUS_SENSING_ENABLED
|
|
u32gintmskTmp |= USBFS_GINTMSK_VBUSVIM;
|
|
#endif
|
|
SET_REG32_BIT(USBx->GREGS->GINTMSK, u32gintmskTmp);
|
|
}
|
|
|
|
/**
|
|
* @brief get the working status of endpoint.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @retval current status of the endpoint
|
|
*/
|
|
uint32_t usb_epstatusget(LL_USB_TypeDef *USBx, USB_DEV_EP *ep)
|
|
{
|
|
__IO uint32_t u32Status = 0UL;
|
|
uint32_t u32dxepctl;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
u32dxepctl = READ_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL);
|
|
|
|
if (0UL != (u32dxepctl & USBFS_DIEPCTL_STALL)) {
|
|
u32Status = USB_EP_TX_STALL;
|
|
} else if (0UL != (u32dxepctl & USBFS_DIEPCTL_NAKSTS)) {
|
|
u32Status = USB_EP_TX_NAK;
|
|
} else {
|
|
u32Status = USB_EP_TX_VALID;
|
|
}
|
|
} else {
|
|
u32dxepctl = READ_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL);
|
|
if (0UL != (u32dxepctl & USBFS_DOEPCTL_STALL)) {
|
|
u32Status = USB_EP_RX_STALL;
|
|
} else if (0UL != (u32dxepctl & USBFS_DOEPCTL_NAKSTS)) {
|
|
u32Status = USB_EP_RX_NAK;
|
|
} else {
|
|
u32Status = USB_EP_RX_VALID;
|
|
}
|
|
}
|
|
|
|
return u32Status;
|
|
}
|
|
|
|
/**
|
|
* @brief set the working status of endpoint.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @param [in] Status new Status that the endpoint would be
|
|
* @retval None
|
|
*/
|
|
void usb_epstatusset(LL_USB_TypeDef *USBx, USB_DEV_EP *ep, uint32_t Status)
|
|
{
|
|
uint32_t u32dxepctl;
|
|
uint8_t u8RetFlag = 0U;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
u32dxepctl = READ_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL);
|
|
|
|
switch (Status) {
|
|
case USB_EP_TX_STALL:
|
|
usb_setepstall(USBx, ep);
|
|
u8RetFlag = 1U;
|
|
break;
|
|
case USB_EP_TX_NAK:
|
|
u32dxepctl |= USBFS_DIEPCTL_SNAK;
|
|
break;
|
|
case USB_EP_TX_VALID:
|
|
if (0UL != (u32dxepctl & USBFS_DIEPCTL_STALL)) {
|
|
ep->datax_pid = 0U;
|
|
usb_clearepstall(USBx, ep);
|
|
u8RetFlag = 1U;
|
|
}
|
|
u32dxepctl |= (USBFS_DIEPCTL_CNAK | USBFS_DIEPCTL_USBAEP | USBFS_DIEPCTL_EPENA);
|
|
break;
|
|
case USB_EP_TX_DIS:
|
|
u32dxepctl &= (~USBFS_DIEPCTL_USBAEP);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* Write register */
|
|
if (1U != u8RetFlag) {
|
|
WRITE_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL, u32dxepctl);
|
|
}
|
|
} else {
|
|
u32dxepctl = READ_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL);
|
|
|
|
switch (Status) {
|
|
case USB_EP_RX_STALL:
|
|
u32dxepctl |= USBFS_DOEPCTL_STALL;
|
|
break;
|
|
case USB_EP_RX_NAK:
|
|
u32dxepctl |= USBFS_DOEPCTL_SNAK;
|
|
break;
|
|
case USB_EP_RX_VALID:
|
|
if (0UL != (u32dxepctl & USBFS_DOEPCTL_STALL)) {
|
|
ep->datax_pid = 0U;
|
|
usb_clearepstall(USBx, ep);
|
|
u8RetFlag = 1U;
|
|
}
|
|
u32dxepctl |= (USBFS_DOEPCTL_CNAK | USBFS_DOEPCTL_USBAEP | USBFS_DOEPCTL_EPENA);
|
|
break;
|
|
case USB_EP_RX_DIS:
|
|
u32dxepctl &= (~USBFS_DOEPCTL_USBAEP);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/* Write register */
|
|
if (1U != u8RetFlag) {
|
|
WRITE_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL, u32dxepctl);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief enable the EP0 to be actiove
|
|
* @param [in] USBx usb instance
|
|
* @retval None
|
|
*/
|
|
void usb_ep0activate(LL_USB_TypeDef *USBx)
|
|
{
|
|
uint32_t u32EnumSpeed;
|
|
uint32_t u32DiepctlTmp;
|
|
|
|
u32EnumSpeed = READ_REG32(USBx->DREGS->DSTS) & USBFS_DSTS_ENUMSPD;
|
|
u32DiepctlTmp = READ_REG32(USBx->INEP_REGS[0]->DIEPCTL);
|
|
/* Set the MPS of the DIEPCTL0 based on the enumeration speed */
|
|
if ((DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ == u32EnumSpeed)
|
|
|| (DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ == u32EnumSpeed)
|
|
|| (DSTS_ENUMSPD_FS_PHY_48MHZ == u32EnumSpeed)) {
|
|
u32DiepctlTmp &= (~USBFS_DIEPCTL_MPSIZ);
|
|
} else if (DSTS_ENUMSPD_LS_PHY_6MHZ == u32EnumSpeed) {
|
|
u32DiepctlTmp &= (~USBFS_DIEPCTL_MPSIZ);
|
|
u32DiepctlTmp |= (3UL << USBFS_DIEPCTL_MPSIZ_POS);
|
|
} else {
|
|
;
|
|
}
|
|
WRITE_REG32(USBx->INEP_REGS[0]->DIEPCTL, u32DiepctlTmp);
|
|
SET_REG32_BIT(USBx->DREGS->DCTL, USBFS_DCTL_CGINAK);
|
|
}
|
|
|
|
/**
|
|
* @brief enable an EP to be active
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @retval None
|
|
*/
|
|
void usb_epactive(LL_USB_TypeDef *USBx, USB_DEV_EP *ep)
|
|
{
|
|
uint32_t u32Addr;
|
|
uint32_t u32dxepctl;
|
|
uint32_t u32Daintmsk;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
u32Addr = (uint32_t)(&(USBx->INEP_REGS[ep->epidx]->DIEPCTL));
|
|
u32Daintmsk = 1UL << ep->epidx;
|
|
} else {
|
|
u32Addr = (uint32_t)(&(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL));
|
|
u32Daintmsk = 1UL << (USBFS_DAINTMSK_OEPINTM_POS + ep->epidx);
|
|
}
|
|
u32dxepctl = READ_REG32(*(__IO uint32_t *)u32Addr);
|
|
if (0UL == (u32dxepctl & USBFS_DIEPCTL_USBAEP)) {
|
|
u32dxepctl = ((ep->maxpacket << USBFS_DIEPCTL_MPSIZ_POS)
|
|
| (((uint32_t)ep->trans_type) << USBFS_DIEPCTL_EPTYP_POS)
|
|
| (((uint32_t)ep->tx_fifo_num) << USBFS_DIEPCTL_TXFNUM_POS)
|
|
| USBFS_DIEPCTL_SD0PID_SEVNFRM
|
|
| USBFS_DIEPCTL_USBAEP);
|
|
|
|
WRITE_REG32(*(__IO uint32_t *)u32Addr, u32dxepctl);
|
|
}
|
|
SET_REG32_BIT(USBx->DREGS->DAINTMSK, u32Daintmsk);
|
|
}
|
|
|
|
/**
|
|
* @brief enable an EP to be deactive state if it is active
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @retval None
|
|
*/
|
|
void usb_epdeactive(LL_USB_TypeDef *USBx, USB_DEV_EP *ep)
|
|
{
|
|
uint32_t u32Daintmsk;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
CLR_REG32_BIT(USBx->INEP_REGS[ep->epidx]->DIEPCTL, USBFS_DIEPCTL_USBAEP);
|
|
u32Daintmsk = 1UL << ep->epidx;
|
|
} else {
|
|
CLR_REG32_BIT(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL, USBFS_DOEPCTL_USBAEP);
|
|
u32Daintmsk = 1UL << (USBFS_DAINTMSK_OEPINTM_POS + ep->epidx);
|
|
}
|
|
CLR_REG32_BIT(USBx->DREGS->DAINTMSK, u32Daintmsk);
|
|
}
|
|
|
|
/**
|
|
* @brief Setup the data into the EP and begin to transmit data.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval None
|
|
*/
|
|
void usb_epntransbegin(LL_USB_TypeDef *USBx, USB_DEV_EP *ep, uint8_t u8DmaEn)
|
|
{
|
|
uint32_t u32depctl;
|
|
uint32_t u32DeptsizTmp;
|
|
uint32_t u32Pktcnt;
|
|
uint32_t u32Xfersize;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
u32depctl = READ_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL);
|
|
/* Zero Length Packet? */
|
|
if (ep->xfer_len == 0UL) {
|
|
u32Xfersize = 0UL;
|
|
u32Pktcnt = 1UL;
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DIEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DIEPTSIZ_PKTCNT_POS);
|
|
} else {
|
|
/* Program the transfer size and packet count
|
|
* as follows: xfersize = N * maxpacket +
|
|
* short_packet pktcnt = N + (short_packet
|
|
* exist ? 1 : 0)
|
|
*/
|
|
u32Xfersize = ep->xfer_len;
|
|
u32Pktcnt = (ep->xfer_len - 1U + ep->maxpacket) / ep->maxpacket;
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DIEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DIEPTSIZ_PKTCNT_POS);
|
|
}
|
|
MODIFY_REG32(USBx->INEP_REGS[ep->epidx]->DIEPTSIZ, USBFS_DIEPTSIZ_XFRSIZ | USBFS_DIEPTSIZ_PKTCNT, u32DeptsizTmp);
|
|
|
|
if (u8DmaEn == 1U) {
|
|
WRITE_REG32(USBx->INEP_REGS[ep->epidx]->DIEPDMA, ep->dma_addr);
|
|
} else {
|
|
if (ep->trans_type != EP_TYPE_ISOC) {
|
|
/* Enable the Tx FIFO Empty Interrupt for this EP */
|
|
if (ep->xfer_len > 0U) {
|
|
SET_REG32_BIT(USBx->DREGS->DIEPEMPMSK, 1UL << ep->epidx);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ep->trans_type == EP_TYPE_ISOC) {
|
|
if (((READ_REG32(USBx->DREGS->DSTS) >> USBFS_DSTS_FNSOF_POS) & 0x1U) == 0U) {
|
|
u32depctl |= USBFS_DIEPCTL_SODDFRM;
|
|
} else {
|
|
u32depctl |= USBFS_DIEPCTL_SD0PID_SEVNFRM;
|
|
}
|
|
}
|
|
|
|
u32depctl |= (USBFS_DIEPCTL_CNAK | USBFS_DIEPCTL_EPENA);
|
|
WRITE_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL, u32depctl);
|
|
|
|
if (ep->trans_type == EP_TYPE_ISOC) {
|
|
usb_wrpkt(USBx, ep->xfer_buff, ep->epidx, (uint16_t)ep->xfer_len, u8DmaEn);
|
|
}
|
|
} else {
|
|
u32depctl = READ_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL);
|
|
/* Program the transfer size and packet count as follows:
|
|
* pktcnt = N
|
|
* xfersize = N * maxpacket
|
|
*/
|
|
if (ep->xfer_len == 0U) {
|
|
u32Xfersize = ep->maxpacket;
|
|
u32Pktcnt = 1UL;
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DOEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DOEPTSIZ_PKTCNT_POS);
|
|
} else {
|
|
u32Pktcnt = (ep->xfer_len + (ep->maxpacket - 1U)) / ep->maxpacket;
|
|
u32Xfersize = u32Pktcnt * ep->maxpacket;
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DOEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DOEPTSIZ_PKTCNT_POS);
|
|
ep->xfer_len = u32Xfersize;
|
|
}
|
|
MODIFY_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPTSIZ, USBFS_DOEPTSIZ_XFRSIZ | USBFS_DOEPTSIZ_PKTCNT, u32DeptsizTmp);
|
|
|
|
if (u8DmaEn == 1U) {
|
|
WRITE_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPDMA, ep->dma_addr);
|
|
}
|
|
|
|
if (ep->trans_type == EP_TYPE_ISOC) {
|
|
if (0U != ep->datax_pid) {
|
|
u32depctl |= USBFS_DOEPCTL_SD1PID;
|
|
} else {
|
|
u32depctl |= USBFS_DOEPCTL_SD0PID;
|
|
}
|
|
}
|
|
u32depctl |= (USBFS_DOEPCTL_CNAK | USBFS_DOEPCTL_EPENA);
|
|
WRITE_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL, u32depctl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Setup the data into the EP0 and begin to transmit data.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval None
|
|
*/
|
|
void usb_ep0transbegin(LL_USB_TypeDef *USBx, USB_DEV_EP *ep, uint8_t u8DmaEn)
|
|
{
|
|
uint32_t u32depctl;
|
|
uint32_t u32DeptsizTmp;
|
|
uint32_t u32Pktcnt;
|
|
uint32_t u32Xfersize;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
u32depctl = READ_REG32(USBx->INEP_REGS[0]->DIEPCTL);
|
|
/* Zero Length Packet? */
|
|
if (ep->xfer_len == 0U) {
|
|
u32Xfersize = 0UL;
|
|
u32Pktcnt = 1UL;
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DIEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DIEPTSIZ_PKTCNT_POS);
|
|
} else {
|
|
if (ep->xfer_len > ep->maxpacket) {
|
|
ep->xfer_len = ep->maxpacket;
|
|
u32Xfersize = ep->maxpacket;
|
|
} else {
|
|
u32Xfersize = ep->xfer_len;
|
|
}
|
|
u32Pktcnt = 1UL;
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DIEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DIEPTSIZ_PKTCNT_POS);
|
|
}
|
|
MODIFY_REG32(USBx->INEP_REGS[0]->DIEPTSIZ, USBFS_DIEPTSIZ_XFRSIZ | USBFS_DIEPTSIZ_PKTCNT, u32DeptsizTmp);
|
|
|
|
if (u8DmaEn == 1U) {
|
|
WRITE_REG32(USBx->INEP_REGS[ep->epidx]->DIEPDMA, ep->dma_addr);
|
|
}
|
|
|
|
u32depctl |= (USBFS_DIEPCTL_CNAK | USBFS_DIEPCTL_EPENA);
|
|
WRITE_REG32(USBx->INEP_REGS[0]->DIEPCTL, u32depctl);
|
|
|
|
if (u8DmaEn == 0U) {
|
|
/* Enable the Tx FIFO Empty Interrupt for this EP */
|
|
if (ep->xfer_len > 0U) {
|
|
SET_REG32_BIT(USBx->DREGS->DIEPEMPMSK, 1UL << ep->epidx);
|
|
}
|
|
}
|
|
} else {
|
|
u32depctl = READ_REG32(USBx->OUTEP_REGS[0]->DOEPCTL);
|
|
/* Program the transfer size and packet count as follows:
|
|
* xfersize = N * (maxpacket + 4 - (maxpacket % 4))
|
|
* pktcnt = N */
|
|
if (ep->xfer_len == 0U) {
|
|
u32Xfersize = 0UL;
|
|
u32Pktcnt = 1UL;
|
|
} else {
|
|
ep->xfer_len = LL_MIN(ep->rem_data_len, ep->maxpacket);
|
|
u32Xfersize = ep->xfer_len;
|
|
u32Pktcnt = 1UL;
|
|
}
|
|
u32DeptsizTmp = (u32Xfersize << USBFS_DOEPTSIZ_XFRSIZ_POS) | (u32Pktcnt << USBFS_DOEPTSIZ_PKTCNT_POS);
|
|
MODIFY_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPTSIZ, USBFS_DOEPTSIZ_XFRSIZ | USBFS_DOEPTSIZ_PKTCNT, u32DeptsizTmp);
|
|
|
|
if (u8DmaEn == 1U) {
|
|
WRITE_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPDMA, ep->dma_addr);
|
|
}
|
|
u32depctl |= (USBFS_DOEPCTL_CNAK | USBFS_DOEPCTL_EPENA);
|
|
WRITE_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL, u32depctl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Set the EP to be stall status
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @retval None
|
|
*/
|
|
void usb_setepstall(LL_USB_TypeDef *USBx, USB_DEV_EP *ep)
|
|
{
|
|
uint32_t u32depctl;
|
|
|
|
if (ep->ep_dir == 1U) {
|
|
u32depctl = READ_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL);
|
|
if (0UL != (u32depctl & USBFS_DIEPCTL_EPENA)) {
|
|
u32depctl |= USBFS_DIEPCTL_EPDIS;
|
|
}
|
|
u32depctl |= USBFS_DIEPCTL_STALL;
|
|
WRITE_REG32(USBx->INEP_REGS[ep->epidx]->DIEPCTL, u32depctl);
|
|
} else {
|
|
u32depctl = READ_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL);
|
|
u32depctl |= USBFS_DOEPCTL_STALL;
|
|
WRITE_REG32(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL, u32depctl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief clear the stall status of a EP
|
|
* @param [in] USBx usb instance
|
|
* @param [in] ep endpoint instance
|
|
* @retval None
|
|
*/
|
|
void usb_clearepstall(LL_USB_TypeDef *USBx, USB_DEV_EP *ep)
|
|
{
|
|
uint32_t tmp_depctl_addr;
|
|
uint32_t u32depctl;
|
|
if (ep->ep_dir == 1U) {
|
|
tmp_depctl_addr = (uint32_t)(&(USBx->INEP_REGS[ep->epidx]->DIEPCTL));
|
|
} else {
|
|
tmp_depctl_addr = (uint32_t)(&(USBx->OUTEP_REGS[ep->epidx]->DOEPCTL));
|
|
}
|
|
u32depctl = READ_REG32(*(__IO uint32_t *)tmp_depctl_addr);
|
|
|
|
u32depctl &= (~USBFS_DIEPCTL_STALL);
|
|
if ((ep->trans_type == EP_TYPE_INTR) || (ep->trans_type == EP_TYPE_BULK)) {
|
|
u32depctl |= USBFS_DIEPCTL_SD0PID_SEVNFRM;
|
|
}
|
|
|
|
WRITE_REG32(*(__IO uint32_t *)tmp_depctl_addr, u32depctl);
|
|
}
|
|
|
|
/**
|
|
* @brief configure the EPO to receive data packets
|
|
* @param [in] USBx usb instance
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval None
|
|
*/
|
|
void usb_ep0revcfg(LL_USB_TypeDef *USBx, uint8_t u8DmaEn, uint8_t *u8RevBuf)
|
|
{
|
|
uint32_t u32deptsize;
|
|
uint32_t u32doepctl;
|
|
|
|
u32deptsize = (3UL << USBFS_DOEPTSIZ0_STUPCNT_POS)
|
|
| (1UL << USBFS_DOEPTSIZ0_PKTCNT_POS)
|
|
| (64UL << USBFS_DOEPTSIZ0_XFRSIZ_POS);
|
|
|
|
WRITE_REG32(USBx->OUTEP_REGS[0]->DOEPTSIZ, u32deptsize);
|
|
|
|
if (u8DmaEn == 1U) {
|
|
WRITE_REG32(USBx->OUTEP_REGS[0]->DOEPDMA, (uint32_t)&u8RevBuf[0]);
|
|
u32doepctl = READ_REG32(USBx->OUTEP_REGS[0]->DOEPCTL);
|
|
u32doepctl |= (USBFS_DOEPCTL_EPENA | USBFS_DOEPCTL_USBAEP);
|
|
WRITE_REG32(USBx->OUTEP_REGS[0]->DOEPCTL, u32doepctl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief enable remote wakeup active
|
|
* @param [in] USBx usb instance
|
|
* @retval None
|
|
*/
|
|
void usb_remotewakeupen(LL_USB_TypeDef *USBx)
|
|
{
|
|
uint32_t u32dsts;
|
|
|
|
u32dsts = READ_REG32(USBx->DREGS->DSTS);
|
|
if (0UL != (u32dsts & USBFS_DSTS_SUSPSTS)) {
|
|
/* un-gate USB Core clock */
|
|
CLR_REG32_BIT(*USBx->GCCTL, USBFS_GCCTL_GATEHCLK | USBFS_GCCTL_STPPCLK);
|
|
}
|
|
|
|
SET_REG32_BIT(USBx->DREGS->DCTL, USBFS_DCTL_RWUSIG);
|
|
hdl_delay_ms(5UL);
|
|
CLR_REG32_BIT(USBx->DREGS->DCTL, USBFS_DCTL_RWUSIG);
|
|
}
|
|
|
|
/**
|
|
* @brief control the device to connect or disconnect
|
|
* @param [in] USBx usb instance
|
|
* @param [in] link 0(conn) or 1(disconn)
|
|
* @retval None
|
|
*/
|
|
void usb_ctrldevconnect(LL_USB_TypeDef *USBx, uint8_t link)
|
|
{
|
|
if (0U == link) {
|
|
CLR_REG32_BIT(USBx->DREGS->DCTL, USBFS_DCTL_SDIS);
|
|
} else {
|
|
SET_REG32_BIT(USBx->DREGS->DCTL, USBFS_DCTL_SDIS);
|
|
}
|
|
hdl_delay_ms(3UL);
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_HOST_MODE
|
|
/**
|
|
* @brief Initializes the USB controller when it is host mode
|
|
* @param [in] USBx usb instance
|
|
* @param [in] basic_cfgs usb core basic cfgs
|
|
* @retval None
|
|
*/
|
|
void usb_hostmodeinit(LL_USB_TypeDef *USBx, USB_CORE_BASIC_CFGS *basic_cfgs)
|
|
{
|
|
__IO uint8_t u8Tmp = 0U;
|
|
WRITE_REG32(*USBx->GCCTL, 0UL); /* reset the register-GCCTL */
|
|
if (USBHS_PHY_EMBED == basic_cfgs->phy_type) {
|
|
usb_fslspclkselset(USBx, HCFG_6_MHZ); /* PHY clock is running at 6MHz */
|
|
} else {
|
|
usb_fslspclkselset(USBx, HCFG_30_60_MHZ); /* PHY clock is running at 6MHz */
|
|
}
|
|
usb_hprtrst(USBx); /* reset the port */
|
|
usb_enumspeed(USBx); /* FS or LS bases on the maximum speed supported by the connected device */
|
|
usb_sethostfifo(USBx, basic_cfgs->core_type);
|
|
/* Flush all the txFIFO and the whole rxFIFO */
|
|
usb_txfifoflush(USBx, 0x10UL);
|
|
usb_rxfifoflush(USBx);
|
|
/* Clear all HC Interrupt bits that are pending */
|
|
while (u8Tmp < basic_cfgs->host_chnum) {
|
|
WRITE_REG32(USBx->HC_REGS[u8Tmp]->HCINT, 0xFFFFFFFFUL);
|
|
WRITE_REG32(USBx->HC_REGS[u8Tmp]->HCINTMSK, 0UL);
|
|
u8Tmp++;
|
|
}
|
|
usb_hostinten(USBx, basic_cfgs->dmaen);
|
|
}
|
|
|
|
/**
|
|
* @brief set the vbus if state is 1 or reset the vbus if state is 0.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] u8State the vbus state it would be.
|
|
* @retval None
|
|
*/
|
|
void usb_vbusctrl(LL_USB_TypeDef *USBx, uint8_t u8State)
|
|
{
|
|
uint32_t u32hprt;
|
|
|
|
u32hprt = usb_rdhprt(USBx);
|
|
if ((0UL == (u32hprt & USBFS_HPRT_PWPR)) && (1U == u8State)) {
|
|
u32hprt |= USBFS_HPRT_PWPR;
|
|
WRITE_REG32(*USBx->HPRT, u32hprt);
|
|
}
|
|
if ((0UL != (u32hprt & USBFS_HPRT_PWPR)) && (0U == u8State)) {
|
|
u32hprt &= (~USBFS_HPRT_PWPR);
|
|
WRITE_REG32(*USBx->HPRT, u32hprt);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enables the related interrupts when the core is host mode
|
|
* @param [in] USBx usb instance
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval None
|
|
*/
|
|
void usb_hostinten(LL_USB_TypeDef *USBx, uint8_t u8DmaEn)
|
|
{
|
|
uint32_t u32gIntmsk = 0UL;
|
|
WRITE_REG32(USBx->GREGS->GINTMSK, 0UL);
|
|
/* Clear the pending interrupt bits */
|
|
WRITE_REG32(USBx->GREGS->GINTSTS, 0xFFFFFFFFUL);
|
|
|
|
/* Enable the normal interrupt bits */
|
|
usb_normalinten(USBx);
|
|
|
|
if (u8DmaEn == 0U) {
|
|
u32gIntmsk |= USBFS_GINTMSK_RXFNEM;
|
|
}
|
|
u32gIntmsk |= (USBFS_GINTMSK_HPRTIM
|
|
| USBFS_GINTMSK_HCIM
|
|
| USBFS_GINTMSK_DISCIM
|
|
| USBFS_GINTMSK_SOFM
|
|
| USBFS_GINTMSK_IPXFRM_INCOMPISOOUTM);
|
|
SET_REG32_BIT(USBx->GREGS->GINTMSK, u32gIntmsk);
|
|
}
|
|
|
|
/**
|
|
* @brief Reset the port, the 1'b0 state must last at lease 10ms.
|
|
* @param [in] USBx usb instance
|
|
* @retval None
|
|
*/
|
|
void usb_hprtrst(LL_USB_TypeDef *USBx)
|
|
{
|
|
uint32_t u32hprt;
|
|
u32hprt = usb_rdhprt(USBx);
|
|
u32hprt |= USBFS_HPRT_PRST;
|
|
WRITE_REG32(*USBx->HPRT, u32hprt);
|
|
hdl_delay_ms(10UL);
|
|
u32hprt &= ~USBFS_HPRT_PRST;
|
|
WRITE_REG32(*USBx->HPRT, u32hprt);
|
|
hdl_delay_ms(20UL);
|
|
}
|
|
|
|
/**
|
|
* @brief Prepares transferring packets on a host channel
|
|
* @param [in] USBx usb instance
|
|
* @param [in] hc_num channel index
|
|
* @param [in] pCh channel structure
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval status in byte
|
|
*/
|
|
uint8_t usb_inithch(LL_USB_TypeDef *USBx, uint8_t hc_num, USB_HOST_CH *pCh, uint8_t u8DmaEn)
|
|
{
|
|
uint32_t u32hcintmsk = 0UL;
|
|
uint32_t u32hcchar = 0UL;
|
|
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCINT, 0xFFFFFFFFUL);
|
|
switch (pCh->ep_type) {
|
|
case EP_TYPE_CTRL:
|
|
case EP_TYPE_BULK:
|
|
u32hcintmsk |= (USBFS_HCINTMSK_XFRCM
|
|
| USBFS_HCINTMSK_STALLM
|
|
| USBFS_HCINTMSK_TXERRM
|
|
| USBFS_HCINTMSK_DTERRM
|
|
| USBFS_HCINTMSK_NAKM);
|
|
if (0U != pCh->is_epin) {
|
|
u32hcintmsk |= USBFS_HCINTMSK_BBERRM;
|
|
} else {
|
|
if (0U != pCh->do_ping) {
|
|
u32hcintmsk |= USBFS_HCINTMSK_ACKM;
|
|
}
|
|
}
|
|
break;
|
|
case EP_TYPE_INTR:
|
|
u32hcintmsk |= (USBFS_HCINTMSK_XFRCM
|
|
| USBFS_HCINTMSK_NAKM
|
|
| USBFS_HCINTMSK_STALLM
|
|
| USBFS_HCINTMSK_TXERRM
|
|
| USBFS_HCINTMSK_DTERRM
|
|
| USBFS_HCINTMSK_FRMORM);
|
|
if (0U != pCh->is_epin) {
|
|
u32hcintmsk |= USBFS_HCINTMSK_BBERRM;
|
|
}
|
|
break;
|
|
case EP_TYPE_ISOC:
|
|
u32hcintmsk |= (USBFS_HCINTMSK_XFRCM
|
|
| USBFS_HCINTMSK_FRMORM
|
|
| USBFS_HCINTMSK_ACKM);
|
|
|
|
if (0U != pCh->is_epin) {
|
|
u32hcintmsk |= (USBFS_HCINTMSK_TXERRM | USBFS_HCINTMSK_BBERRM);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCINTMSK, u32hcintmsk);
|
|
SET_REG32_BIT(USBx->HREGS->HAINTMSK, 1UL << hc_num);
|
|
|
|
/* enable the host channel interrupts */
|
|
SET_REG32_BIT(USBx->GREGS->GINTMSK, USBFS_GINTMSK_HCIM);
|
|
|
|
/* modify HCCHAR */
|
|
u32hcchar |= (((uint32_t)pCh->dev_addr) << USBFS_HCCHAR_DAD_POS);
|
|
u32hcchar |= (((uint32_t)pCh->ep_idx) << USBFS_HCCHAR_EPNUM_POS);
|
|
u32hcchar |= (((uint32_t)pCh->is_epin) << USBFS_HCCHAR_EPDIR_POS);
|
|
u32hcchar |= (((uint32_t)pCh->ep_type) << USBFS_HCCHAR_EPTYP_POS);
|
|
u32hcchar |= (((uint32_t)pCh->max_packet) << USBFS_HCCHAR_MPSIZ_POS);
|
|
if (PRTSPD_LOW_SPEED == pCh->ch_speed) {
|
|
u32hcchar |= USBFS_HCCHAR_LSDEV;
|
|
} else {
|
|
u32hcchar &= ~USBFS_HCCHAR_LSDEV;
|
|
}
|
|
|
|
if (pCh->ep_type == EP_TYPE_INTR) {
|
|
u32hcchar |= USBFS_HCCHAR_ODDFRM;
|
|
}
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCCHAR, u32hcchar);
|
|
return USB_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Start transfer on the channel whose index is hc_num.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] hc_num channel index
|
|
* @param [in] pCh channel structure
|
|
* @param [in] u8DmaEn USB DMA status
|
|
* @retval status in 8 bits
|
|
*/
|
|
uint8_t usb_hchtransbegin(LL_USB_TypeDef *USBx, uint8_t hc_num, USB_HOST_CH *pCh, uint8_t u8DmaEn)
|
|
{
|
|
uint32_t u32hcchar;
|
|
uint32_t u32hctsiz = 0UL;
|
|
uint32_t u32hnptxsts;
|
|
uint32_t u32hptxsts;
|
|
uint16_t u16LenWords;
|
|
uint16_t u16NumPacket;
|
|
uint16_t u16MaxHcPktCount = 256U;
|
|
|
|
/* Compute the expected number of packets associated to the transfer */
|
|
if (pCh->xfer_len > 0U) {
|
|
u16NumPacket = (uint16_t)((pCh->xfer_len +
|
|
(uint32_t)pCh->max_packet - 1UL) / (uint32_t)pCh->max_packet);
|
|
|
|
if (u16NumPacket > u16MaxHcPktCount) {
|
|
u16NumPacket = u16MaxHcPktCount;
|
|
pCh->xfer_len = (uint32_t)u16NumPacket * (uint32_t)pCh->max_packet;
|
|
}
|
|
} else {
|
|
u16NumPacket = 1U;
|
|
}
|
|
if (0U != pCh->is_epin) {
|
|
pCh->xfer_len = (uint32_t)u16NumPacket * (uint32_t)pCh->max_packet;
|
|
}
|
|
|
|
u32hctsiz |= (((uint32_t)pCh->xfer_len) << USBFS_HCTSIZ_XFRSIZ_POS);
|
|
u32hctsiz |= (((uint32_t)u16NumPacket) << USBFS_HCTSIZ_PKTCNT_POS);
|
|
u32hctsiz |= (((uint32_t)pCh->pid_type) << USBFS_HCTSIZ_DPID_POS);
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCTSIZ, u32hctsiz);
|
|
|
|
if (u8DmaEn == 1U) {
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCDMA, pCh->xfer_buff);
|
|
}
|
|
|
|
u32hcchar = READ_REG32(USBx->HC_REGS[hc_num]->HCCHAR);
|
|
u32hcchar &= ~USBFS_HCCHAR_ODDFRM;
|
|
u32hcchar |= (usb_ifevenframe(USBx) << USBFS_HCCHAR_ODDFRM_POS);
|
|
|
|
/* enable this host channel whose number is hc_num */
|
|
u32hcchar |= USBFS_HCCHAR_CHENA;
|
|
u32hcchar &= ~USBFS_HCCHAR_CHDIS;
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCCHAR, u32hcchar);
|
|
|
|
if (u8DmaEn == 0U) {
|
|
if ((pCh->is_epin == 0U) && (pCh->xfer_len > 0U)) {
|
|
switch (pCh->ep_type) {
|
|
/* Non-periodic transmit */
|
|
case EP_TYPE_CTRL:
|
|
case EP_TYPE_BULK:
|
|
u32hnptxsts = READ_REG32(USBx->GREGS->HNPTXSTS);
|
|
u16LenWords = (uint16_t)((pCh->xfer_len + 3UL) / 4UL);
|
|
/* check if the amount of free space available in the non-periodic txFIFO is enough */
|
|
if (u16LenWords > ((u32hnptxsts & USBFS_HNPTXSTS_NPTXFSAV) >> USBFS_HNPTXSTS_NPTXFSAV_POS)) {
|
|
/* enable interrrupt of nptxfempty of GINTMSK*/
|
|
SET_REG32_BIT(USBx->GREGS->GINTMSK, USBFS_GINTMSK_NPTXFEM);
|
|
}
|
|
break;
|
|
/* Periodic trnsmit */
|
|
case EP_TYPE_INTR:
|
|
case EP_TYPE_ISOC:
|
|
u32hptxsts = READ_REG32(USBx->HREGS->HPTXSTS);
|
|
u16LenWords = (uint16_t)((pCh->xfer_len + 3UL) / 4UL);
|
|
/* check if the space of periodic TxFIFO is enough */
|
|
if (u16LenWords > ((u32hptxsts & USBFS_HPTXSTS_PTXFSAVL) >> USBFS_HPTXSTS_PTXFSAVL_POS)) {
|
|
/* enable interrrupt of ptxfempty of GINTMSK */
|
|
SET_REG32_BIT(USBx->GREGS->GINTMSK, USBFS_GINTMSK_PTXFEM);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
usb_wrpkt(USBx, pCh->xfer_buff, hc_num, (uint16_t)pCh->xfer_len, u8DmaEn);
|
|
}
|
|
}
|
|
return USB_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Stop the host and flush all the txFIFOs and the whole rxFIFO.
|
|
* @param [in] USBx usb instance
|
|
* @param [in] u8ChNum Host channel number
|
|
* @retval None
|
|
*/
|
|
void usb_hoststop(LL_USB_TypeDef *USBx, uint8_t u8ChNum)
|
|
{
|
|
__IO uint32_t u32Tmp = 0UL;
|
|
|
|
WRITE_REG32(USBx->HREGS->HAINTMSK, 0UL);
|
|
WRITE_REG32(USBx->HREGS->HAINT, 0xFFFFFFFFUL);
|
|
|
|
do {
|
|
usb_chrst(USBx, (uint8_t)u32Tmp);
|
|
u32Tmp++;
|
|
} while (u32Tmp < u8ChNum);
|
|
/* flush all the txFIFOs and the whole rxFIFO */
|
|
usb_rxfifoflush(USBx);
|
|
usb_txfifoflush(USBx, 0x10UL);
|
|
}
|
|
|
|
/**
|
|
* @brief make the channel to halt
|
|
* @param [in] USBx usb instance
|
|
* @param [in] hc_num channel index
|
|
* @retval None
|
|
*/
|
|
void usb_hchstop(LL_USB_TypeDef *USBx, uint8_t hc_num)
|
|
{
|
|
uint32_t u32hcchar;
|
|
|
|
u32hcchar = READ_REG32(USBx->HC_REGS[hc_num]->HCCHAR);
|
|
u32hcchar |= USBFS_HCCHAR_CHDIS;
|
|
/* Check for space in the request queue to issue the halt. */
|
|
if ((EP_TYPE_CTRL == ((u32hcchar & USBFS_HCCHAR_EPTYP) >> USBFS_HCCHAR_EPTYP_POS))
|
|
|| (EP_TYPE_BULK == ((u32hcchar & USBFS_HCCHAR_EPTYP) >> USBFS_HCCHAR_EPTYP_POS))) {
|
|
if (0UL == (READ_REG32(USBx->GREGS->HNPTXSTS) & USBFS_HNPTXSTS_NPTQXSAV)) {
|
|
u32hcchar &= (~USBFS_HCCHAR_CHENA);
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCCHAR, u32hcchar);
|
|
}
|
|
} else {
|
|
if (0UL == (READ_REG32(USBx->HREGS->HPTXSTS) & USBFS_HPTXSTS_PTXQSAV)) {
|
|
u32hcchar &= (~USBFS_HCCHAR_CHENA);
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCCHAR, u32hcchar);
|
|
}
|
|
}
|
|
u32hcchar |= USBFS_HCCHAR_CHENA;
|
|
WRITE_REG32(USBx->HC_REGS[hc_num]->HCCHAR, u32hcchar);
|
|
}
|
|
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#endif /* LL_USB_ENABLE */
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/******************************************************************************
|
|
* EOF (not truncated)
|
|
*****************************************************************************/
|