Files
hc32f460_boot/mcu/lib/src/hc32_ll_usb.c
T
2026-04-23 13:49:53 +08:00

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)
*****************************************************************************/