Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

source/hic_hal/atmel/sam3u2c/usbd_ATSAM3U2C.c

Committer:
Pawel Zarembski
Date:
2020-04-07
Revision:
0:01f31e923fe2

File content as of revision 0:01f31e923fe2:

/**
 * @file    usbd_ATSAM3U2C.c
 * @brief   
 *
 * DAPLink Interface Firmware
 * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rl_usb.h"
#include "sam3u.h"
#include "util.h"

#define __NO_USB_LIB_C
#include "usb_config.c"

#define UDPHS_EPTFIFO_BASE (0x20180000) /* (UDPHS_EPTFIFO) Base Address       */
uint32_t eptsta_copy[USBD_EP_NUM + 1];

/*
 *  Calculate EP size code Function
 *   Called during EndPoint configuration
 *    Return Value:    EP size code for given EP size
 */

static int USBD_CalcSizeEP(uint32_t size)
{
    if (size <=    8) {
        return (0);
    } else if (size <=   16) {
        return (1);
    } else if (size <=   32) {
        return (2);
    } else if (size <=   64) {
        return (3);
    } else if (size <=  128) {
        return (4);
    } else if (size <=  256) {
        return (5);
    } else if (size <=  512)  {
        return (6);
    } else if (size <= 1024) {
        return (7);
    }

    return (0);
}


/*
 *  Retrieve maximum EP size Function
 *   Called during EndPoint configuration
 *    Return Value:    maximum size for given EP
 */

static int USBD_GetSizeEP(uint32_t EPNum)
{
    switch (EPNum & 0x0F) {
        case 0:
            return (64);                      /* Maximum size is 64 bytes           */

        case 1:
        case 2:
            return (512);                     /* Maximum size is 512 bytes          */

        case 3:
        case 4:
            return (64);                      /* Maximum size is 64 bytes           */

        case 5:
        case 6:
            return (1024);                    /* Maximum size is 1024 bytes         */

        default:
            return (0);                       /* Non existant endpoint              */
    }
}


/*
 *  USB Device Interrupt enable
 *   Called by USBD_Init to enable the USB Interrupt
 *    Return Value:    None
 */

void USBD_IntrEna(void)
{
    NVIC_EnableIRQ(UDPHS_IRQn);           /* Enable USB interrupt               */
}


/*
 *  USB Device Initialize Function
 *   Called by the User to initialize USB Device
 *    Return Value:    None
 */

void USBD_Init(void)
{
    uint32_t n;
    /* Enables the 48MHz USB Clock UDPCK and System Peripheral USB Clock        */
    PMC->PMC_WPMR = 0x504D4300;                              /* Disable write protect  */
    PMC->PMC_PCER0  = (1 << ID_UDPHS);                       /* enable clock for UPDHS */
    PMC->CKGR_UCKR  = (CKGR_UCKR_UPLLCOUNT(15) | CKGR_UCKR_UPLLEN);

    while (!(PMC->PMC_SR & PMC_SR_LOCKU));                   /* wait until PLL is locked */

    PMC->PMC_WPMR = 0x504D4301;                              /* Enable write protect */
    /* Configure the pull-up on D+ and disconnect it                            */
    UDPHS->UDPHS_CTRL |= UDPHS_CTRL_DETACH;         /* Detach                   */
    UDPHS->UDPHS_CTRL |= UDPHS_CTRL_PULLD_DIS;      /* Disable Pull Down        */
    /* Reset IP UDPHS                                                           */
    UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_EN_UDPHS;
    UDPHS->UDPHS_CTRL |=  UDPHS_CTRL_EN_UDPHS;
#if (!USBD_HS_ENABLE)                             /* If HS disabled           */
    UDPHS->UDPHS_TST  |= (3 & UDPHS_TST_SPEED_CFG_Msk);
#endif

    /* Disable DMA for UDPHS                                                    */
    for (n = 1; n < (UDPHSDMA_NUMBER); n++) {
        /* RESET endpoint canal DMA:                                              */
        UDPHS->UDPHS_DMA[n].UDPHS_DMACONTROL = 0;     /* STOP command             */
        /* Disable endpoint                                                       */
        UDPHS->UDPHS_EPT[n].UDPHS_EPTCTLDIS  = 0xFFFFFFFF;
        /* Clear status endpoint                                                  */
        UDPHS->UDPHS_EPT[n].UDPHS_EPTCLRSTA  = 0xFFFFFFFF;
        /* Reset endpoint config                                                  */
        UDPHS->UDPHS_EPT[n].UDPHS_EPTCTLENB  = 0;
        /* Reset DMA channel (Buff count and Control field)                       */
        UDPHS->UDPHS_DMA[n].UDPHS_DMACONTROL = (0x1 << 1);    /* NON STOP command */
        /* Reset DMA channel 0 (STOP)                                             */
        UDPHS->UDPHS_DMA[n].UDPHS_DMACONTROL = 0;             /* STOP command     */
        /* Clear DMA channel status (read the register for clear it)              */
        UDPHS->UDPHS_DMA[n].UDPHS_DMASTATUS =  UDPHS->UDPHS_DMA[n].UDPHS_DMASTATUS;
    }

    UDPHS->UDPHS_IEN     = 0;
    UDPHS->UDPHS_CLRINT  = UDPHS_CLRINT_UPSTR_RES |
                           UDPHS_CLRINT_ENDOFRSM  |
                           UDPHS_CLRINT_WAKE_UP   |
                           UDPHS_CLRINT_ENDRESET  |
                           UDPHS_CLRINT_INT_SOF   |
                           UDPHS_CLRINT_MICRO_SOF |
                           UDPHS_CLRINT_DET_SUSPD;
    USBD_IntrEna();                       /* Enable USB interrupt               */
}


/*
 *  USB Device Connect Function
 *   Called by the User to Connect/Disconnect USB Device
 *    Parameters:      con:   Connect/Disconnect
 *    Return Value:    None
 */

void USBD_Connect(BOOL con)
{
    if (con) {
        UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_DETACH;          /* Pull Up on DP        */
        UDPHS->UDPHS_CTRL |=  UDPHS_CTRL_PULLD_DIS;       /* Disable Pull Down    */
    } else {
        UDPHS->UDPHS_CTRL |=  UDPHS_CTRL_DETACH;          /* Detach               */
        UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_PULLD_DIS;       /* Enable Pull Down     */
    }
}

/*
 *  USB Device Reset Function
 *   Called automatically on USB Device Reset
 *    Return Value:    None
 */
extern U8 USBD_ConfigDescriptor_HS[];
extern U8 USBD_ConfigDescriptor[];
void USBD_Reset(void)
{
    uint32_t ep, EPMask;
    EPMask = ((1 << (USBD_EP_NUM + 1)) - 1);

    /* Reset & Disable USB Endpoints                                            */
    for (ep = 0; ep <= USBD_EP_NUM; ep++) {
        UDPHS->UDPHS_EPT[ep].UDPHS_EPTCFG    =  0;
        UDPHS->UDPHS_EPT[ep].UDPHS_EPTCTLDIS = (0x1 <<  0);     /* Disable EP     */
        eptsta_copy[ep] = 0;
    }

    UDPHS->UDPHS_EPTRST = EPMask;                             /* Reset   EPs    */
    UDPHS->UDPHS_EPTRST = 0;
    /* Setup USB Interrupts */               /* note: Micro_SOF not yet handled */
#ifdef __RTX
    UDPHS->UDPHS_IEN = ((USBD_RTX_DevTask     != 0) ? UDPHS_IEN_DET_SUSPD : 0) |
                       ((USBD_RTX_DevTask     != 0) ? UDPHS_IEN_MICRO_SOF : 0) |
                       ((USBD_RTX_DevTask     != 0) ? UDPHS_IEN_INT_SOF   : 0) |
                       ((USBD_RTX_DevTask     != 0) ? UDPHS_IEN_ENDRESET  : 0) |
//                   ((USBD_RTX_DevTask     != 0) ? UDPHS_IEN_WAKE_UP   : 0) |
//                   ((USBD_RTX_DevTask     != 0) ? UDPHS_IEN_UPSTR_RES : 0) |
#else
    UDPHS->UDPHS_IEN = ((USBD_P_Suspend_Event != 0) ? UDPHS_IEN_DET_SUSPD : 0) |
                       ((USBD_P_SOF_Event     != 0) ? UDPHS_IEN_MICRO_SOF : 0) |
                       ((USBD_P_SOF_Event     != 0) ? UDPHS_IEN_INT_SOF   : 0) |
                       ((USBD_P_Reset_Event   != 0) ? UDPHS_IEN_ENDRESET  : 0) |
//                   ((USBD_P_WakeUp_Event  != 0) ? UDPHS_IEN_WAKE_UP   : 0) |
//                   ((USBD_P_Resume_Event  != 0) ? UDPHS_IEN_UPSTR_RES : 0) |
#endif
                       (EPMask << 8);
    /* Setup Control Endpoint 0                                                 */
    UDPHS->UDPHS_EPT[0].UDPHS_EPTCFG     = UDPHS_EPTCFG_BK_NUMBER_1            |
                                           UDPHS_EPTCFG_EPT_TYPE_CTRL8         |
                                           USBD_CalcSizeEP(USBD_MAX_PACKET0)   ;
    UDPHS->UDPHS_EPT[0].UDPHS_EPTCTLENB  = UDPHS_EPTCTLENB_RXRDY_TXKL          |
                                           UDPHS_EPTCTLENB_TX_COMPLT           |
                                           UDPHS_EPTCTLENB_RX_SETUP            |
                                           UDPHS_EPTCTLENB_STALL_SNT           |
                                           UDPHS_EPTCTLENB_NYET_DIS            |
                                           UDPHS_EPTCTLENB_EPT_ENABL;
                                           
    
#if (USBD_HS_ENABLE == 1)
    U8 * config_desc = USBD_ConfigDescriptor_HS;
#else
    U8 * config_desc = USBD_ConfigDescriptor;
#endif

    while (((USB_ENDPOINT_DESCRIPTOR *)config_desc)->bLength > 0) {
        if (((USB_ENDPOINT_DESCRIPTOR *)config_desc)->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) {
            uint32_t num, type, dir, size, banks, interval;
            USB_ENDPOINT_DESCRIPTOR *pEPD =  (USB_ENDPOINT_DESCRIPTOR *)config_desc;
            num      = pEPD->bEndpointAddress & 0x0F;
            type     = pEPD->bmAttributes & USB_ENDPOINT_TYPE_MASK;
            dir      = pEPD->bEndpointAddress >> 7;
            interval = pEPD->bInterval;
            size     = USBD_CalcSizeEP(pEPD->wMaxPacketSize);
            banks    = 1;
            UDPHS->UDPHS_EPT[num].UDPHS_EPTCFG    = (interval << 8) |
                                                    (banks    << 6) |
                                                    (type     << 4) |
                                                    (dir      << 3) |
                                                    (size     << 0) ;
        }
        config_desc += ((USB_ENDPOINT_DESCRIPTOR *)config_desc)->bLength;
    }
}


/*
 *  USB Device Suspend Function
 *   Called automatically on USB Device Suspend
 *    Return Value:    None
 */

void USBD_Suspend(void)
{
    UDPHS->UDPHS_IEN  &= ~UDPHS_IEN_DET_SUSPD;
    UDPHS->UDPHS_IEN  |=  UDPHS_IEN_WAKE_UP;
}


/*
 *  USB Device Resume Function
 *   Called automatically on USB Device Resume
 *    Return Value:    None
 */

void USBD_Resume(void)
{
    UDPHS->UDPHS_IEN  &= ~UDPHS_IEN_WAKE_UP;
    UDPHS->UDPHS_IEN  |=  UDPHS_IEN_DET_SUSPD;
}


/*
 *  USB Device Remote Wakeup Function
 *   Called automatically on USB Device Remote Wakeup
 *    Return Value:    None
 */

void USBD_WakeUp(void)
{
    UDPHS->UDPHS_IEN  |=  UDPHS_IEN_UPSTR_RES;
    UDPHS->UDPHS_CTRL |=  UDPHS_CTRL_REWAKEUP;
}


/*
 *  USB Device Remote Wakeup Configuration Function
 *    Parameters:      cfg:   Device Enable/Disable
 *    Return Value:    None
 */

void USBD_WakeUpCfg(BOOL cfg)
{
    if (cfg) {
        /* Enable wakeup mechanism */
    } else {
        UDPHS->UDPHS_CTRL &= ~UDPHS_CTRL_REWAKEUP;
        UDPHS->UDPHS_IEN  &= ~UDPHS_IEN_UPSTR_RES;
    }
}


/*
 *  USB Device Set Address Function
 *    Parameters:      adr:   USB Device Address
 *                     setup: Called in setup stage (!=0), else after status stage
 *    Return Value:    None
 */

void USBD_SetAddress(uint32_t adr, uint32_t setup)
{
    if (setup) {
        return;
    }

    if (adr) {
        UDPHS->UDPHS_CTRL |= (UDPHS_CTRL_FADDR_EN | adr);
    } else {
        UDPHS->UDPHS_CTRL &= ~(UDPHS_CTRL_FADDR_EN | UDPHS_CTRL_DEV_ADDR_Msk);
    }
}


/*
 *  USB Device Configure Function
 *    Parameters:      cfg:   Device Configure/Deconfigure
 *    Return Value:    None
 */

void USBD_Configure(BOOL cfg)
{
    /* Performed by Hardware */
}


/*
 *  Configure USB Device Endpoint according to Descriptor
 *    Parameters:      pEPD:  Pointer to Device Endpoint Descriptor
 *    Return Value:    None
 */

void USBD_ConfigEP(USB_ENDPOINT_DESCRIPTOR *pEPD)
{
    uint32_t num;//, type, dir, size, banks, interval;
    num      = pEPD->bEndpointAddress & 0x0F;
    /*type     = pEPD->bmAttributes & USB_ENDPOINT_TYPE_MASK;
    dir      = pEPD->bEndpointAddress >> 7;
    interval = pEPD->bInterval;
    size     = USBD_CalcSizeEP(pEPD->wMaxPacketSize);
    banks    = 1;
    */
    /* Check if MaxPacketSize fits for EndPoint                                 */
    if (pEPD->wMaxPacketSize <= USBD_GetSizeEP(num)) {
        /*UDPHS->UDPHS_EPT[num].UDPHS_EPTCFG    = (interval << 8) |
                                                (banks    << 6) |
                                                (type     << 4) |
                                                (dir      << 3) |
                                                //(size     << 0) ;
                                                 6;*/
        UDPHS->UDPHS_EPT[num].UDPHS_EPTCTLENB =
            (0x1 <<  9) |  /* Received OUT Data Interrupt Enable                    */
            (0x1 << 10) |  /* Transmitted IN Data Complete Interrupt Enable         */
            (0x0 <<  4) |  /* NYET Disable (Only for High Speed Bulk OUT endpoints) */
            (0x1 << 13) ;  /* Stall Sent /ISO CRC Error/Number of Transaction Error */
    }
}


/*
 *  Set Direction for USB Device Control Endpoint
 *    Parameters:      dir:   Out (dir == 0), In (dir <> 0)
 *    Return Value:    None
 */

void USBD_DirCtrlEP(uint32_t dir)
{
    /* Performed by Hardware */
}


/*
 *  Enable USB Device Endpoint
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *    Return Value:    None
 */

void USBD_EnableEP(uint32_t EPNum)
{
    UDPHS->UDPHS_EPT[EPNum & 0x0F].UDPHS_EPTCTLENB = (0x1 << 0);  /* EP Enable  */
    eptsta_copy[EPNum & 0x0F] = UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTSETSTA;
}


/*
 *  Disable USB Device Endpoint
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *    Return Value:    None
 */

void USBD_DisableEP(uint32_t EPNum)
{
    UDPHS->UDPHS_EPT[EPNum & 0x0F].UDPHS_EPTCTLDIS = (0x1 << 0);  /* EP Disable */
    eptsta_copy[EPNum & 0x0F] = UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTSETSTA;
}


/*
 *  Reset USB Device Endpoint
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *    Return Value:    None
 */

void USBD_ResetEP(uint32_t EPNum)
{
    EPNum &= 0x0F;
    UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTCLRSTA = (0x1 << 6) |  /* Data Toggle Clear*/
            (0x1 << 5);   /* Stall Req Set    */
    UDPHS->UDPHS_EPTRST |= (1 << EPNum);                    /* Reset endpoint   */
    UDPHS->UDPHS_EPTRST &= ~(1 << EPNum);
    eptsta_copy[EPNum] = UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTSETSTA;
}


/*
 *  Set Stall for USB Device Endpoint
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *    Return Value:    None
 */

void USBD_SetStallEP(uint32_t EPNum)
{
    UDPHS->UDPHS_EPT[EPNum & 0x0F].UDPHS_EPTSETSTA = (0x1 << 5);  /* Stall Set  */
    eptsta_copy[EPNum & 0x0F] |= 0x1 << 5;
}


/*
 *  Clear Stall for USB Device Endpoint
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *    Return Value:    None
 */

void USBD_ClrStallEP(uint32_t EPNum)
{
    UDPHS->UDPHS_EPT[EPNum & 0x0F].UDPHS_EPTCLRSTA = (0x1 << 6) | /* Clr Toggle */
            (0x1 << 5);  /* Stall Clear*/
    eptsta_copy[EPNum & 0x0F] &= ~(0x1 << 5);
}


/*
 *  Read USB Device Endpoint Data
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *                     pData: Pointer to Data Buffer
 *    Return Value:    Number of bytes read
 */

uint32_t USBD_ReadEP(uint32_t EPNum, uint8_t *pData, uint32_t size)
{
    uint32_t cnt, n, copy_sz;
    uint8_t *pEPFIFO;                                /* Pointer to EP FIFO           */
    uint32_t eptsta;
    EPNum  &= 0x0F;
    eptsta = eptsta_copy[EPNum];
    pEPFIFO = (uint8_t *)((uint32_t *)UDPHS_EPTFIFO_BASE + (16384 * EPNum));
    cnt     = (eptsta >> 20) & 0x07FF;  /* Get by */
    copy_sz = cnt > size ? size : cnt;

    for (n = 0; n < copy_sz; n++) {
        *pData++ = *pEPFIFO++;
    }

    util_assert(cnt == copy_sz);

    if ((cnt == copy_sz) && (eptsta & (0x1 << 9))) {
        UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTCLRSTA = (0x1 << 9);   /* Rece OUT Clear   */
    }

    /* RX_Setup must be cleared after Setup packet is read                      */
    if (eptsta & (0x1 << 12)) {
        UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTCLRSTA = (0x1 << 12);  /* Rece SETUP Clear */
    }
    UDPHS->UDPHS_IEN |= (1 << (EPNum + 8));     /* Enable EP int after data read*/
    return (cnt);
}


/*
 *  Write USB Device Endpoint Data
 *    Parameters:      EPNum: Device Endpoint Number
 *                       EPNum.0..3: Address
 *                       EPNum.7:    Dir
 *                     pData: Pointer to Data Buffer
 *                     cnt:   Number of bytes to write
 *    Return Value:    Number of bytes written
 */

uint32_t USBD_WriteEP(uint32_t EPNum, uint8_t *pData, uint32_t cnt)
{
    uint32_t n;
    uint8_t *pEPFIFO;                          /* Pointer to the endpoint FIFO       */
    uint32_t eptsta;
    EPNum &= 0x0F;
    eptsta = eptsta_copy[EPNum];

    // Cached value should match the real value
    util_assert((UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTSTA & (0x1 << 5)) == (eptsta & (0x1 << 5)));
    if (eptsta & (0x1 << 5)) {  /* If EP is stall */
        return (cnt);
    }

    // Both register and cached value should indicate that the bank is ready (bit 11 clear)
    util_assert(!(UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTSTA & (0x1 << 11)));
    util_assert(!(eptsta & (0x1 << 11)));

    pEPFIFO = (uint8_t *)((uint32_t *)UDPHS_EPTFIFO_BASE + (16384 * EPNum));

    for (n = 0; n < cnt; n++) {
        *pEPFIFO++ = *pData++;              /* Write data to FIFO                 */
    }

    UDPHS->UDPHS_EPT[EPNum].UDPHS_EPTSETSTA = (0x1 << 11);  /* Set packet ready */
    return (cnt);
}


/*
 *  Get USB Device Last Frame Number
 *    Parameters:      None
 *    Return Value:    Frame Number
 */

uint32_t USBD_GetFrame(void)
{
    uint32_t val;

    if ((UDPHS->UDPHS_FNUM & (1UL << 31)) == 0) {
        if (USBD_HighSpeed) {
            val = UDPHS->UDPHS_FNUM & 0x7FFFFFFF;
        } else {
            val = (UDPHS->UDPHS_FNUM & UDPHS_FNUM_FRAME_NUMBER_Msk) >> 3;
        }
    } else {
        val = 0xFFFFFFFF;
    }

    return (val);
}


#ifdef __RTX
uint32_t LastError;                          /* Last Error                         */

/*
 *  Get USB Device Last Error Code
 *    Parameters:      None
 *    Return Value:    Error Code
 */

uint32_t USBD_GetError(void)
{
    return (LastError);
}
#endif


/*
 *  USB Device Interrupt Service Routine
 */

void UDPHS_IRQHandler(void)
{
    NVIC_DisableIRQ(UDPHS_IRQn);
    USBD_SignalHandler();
}

/*
 *  USB Device Service Routine
 */

void USBD_Handler(void)
{
    uint32_t intsta, eptsta, n;
    intsta = UDPHS->UDPHS_INTSTA & UDPHS->UDPHS_IEN;

    /* End of Bus Reset Interrupt                                               */
    if (intsta & UDPHS_INTSTA_ENDRESET) {
        /* Get used speed (HighSpeed or FullSpeed)                                */
        USBD_HighSpeed = (UDPHS->UDPHS_INTSTA & UDPHS_INTSTA_SPEED) ? 1 : 0;
        USBD_Reset();
        usbd_reset_core();
#ifdef __RTX
        UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_ENDRESET;

        if (USBD_RTX_DevTask) {
            isr_evt_set(USBD_EVT_RESET, USBD_RTX_DevTask);
        }

#else

        if (USBD_P_Reset_Event) {
            USBD_P_Reset_Event();
        }

        UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_ENDRESET;
#endif
    }

    /* USB Suspend Interrupt                                                    */
    if (intsta & UDPHS_INTSTA_DET_SUSPD) {
        USBD_Suspend();
#ifdef __RTX
        UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_DET_SUSPD;

        if (USBD_RTX_DevTask) {
            isr_evt_set(USBD_EVT_SUSPEND, USBD_RTX_DevTask);
        }

#else

        if (USBD_P_Suspend_Event) {
            USBD_P_Suspend_Event();
        }

        UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_DET_SUSPD;
#endif
    }

    /* USB Resume Interrupt                                                     */
    if (intsta & UDPHS_INTSTA_WAKE_UP) {
        USBD_Resume();
#ifdef __RTX
        UDPHS->UDPHS_CLRINT = UDPHS_INTSTA_WAKE_UP;

        if (USBD_RTX_DevTask) {
            isr_evt_set(USBD_EVT_RESUME,  USBD_RTX_DevTask);
        }

#else

        if (USBD_P_Resume_Event) {
            USBD_P_Resume_Event();
        }

        UDPHS->UDPHS_CLRINT = UDPHS_INTSTA_WAKE_UP;
#endif
    }

    /* USB Remote Wakeup Interrupt                                              */
    if (intsta & UDPHS_INTSTA_UPSTR_RES) {
        UDPHS->UDPHS_CLRINT = UDPHS_INTSTA_UPSTR_RES;
    }

    /* Start of Frame Interrupt                                                 */
    if (intsta & UDPHS_INTSTA_INT_SOF) {
        /* Process the SOF interrupt even in high speed mode.
        The SOF and MICRO_SOF interrupt are never generated at the same
        time. Instead, when in high speed mode there is 1 SOF
        interrupt and 7 MICRO_SOF interrupts every 1ms. */

#ifdef __RTX
        UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_INT_SOF;

        if (USBD_RTX_DevTask) {
            isr_evt_set(USBD_EVT_SOF, USBD_RTX_DevTask);
        }

#else

        if (USBD_P_SOF_Event) {
            USBD_P_SOF_Event();
        }

        UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_INT_SOF;
#endif
    }

    /* Micro Frame Interrupt                                                    */
    if (intsta & UDPHS_INTSTA_MICRO_SOF) {
        if (USBD_HighSpeed == 1) {
#ifdef __RTX
            UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_MICRO_SOF;

            if (USBD_RTX_DevTask) {
                isr_evt_set(USBD_EVT_SOF, USBD_RTX_DevTask);
            }

#else

            if (USBD_P_SOF_Event) {
                USBD_P_SOF_Event();
            }

            UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_MICRO_SOF;
#endif

        } else {
            UDPHS->UDPHS_CLRINT = UDPHS_CLRINT_MICRO_SOF;
        }
    }

    /* Endpoint Interrupts                                                      */
    for (n = 0; n <= USBD_EP_NUM; n++) {
        if (intsta & (1 << (n + 8))) {
            eptsta = UDPHS->UDPHS_EPT[n].UDPHS_EPTSTA;  /* Read EP status           */
            eptsta_copy[n] = eptsta;

            /* Data Packet Sent Interrupt                                           */
            if (eptsta & (1 << 10)) {         /* Transmitted IN Data Complete Int   */
                UDPHS->UDPHS_EPT[n].UDPHS_EPTCLRSTA = (1 << 10);    /* Tx IN Clear    */
#ifdef __RTX

                if (USBD_RTX_EPTask[n]) {       /* IN Packet                          */
                    isr_evt_set(USBD_EVT_IN,  USBD_RTX_EPTask[n]);
                }

#else

                if (USBD_P_EP[n]) {
                    USBD_P_EP[n](USBD_EVT_IN);
                }

#endif
            }

            /* Data Packet Received Interrupt                                       */
            if (eptsta & (1 << 9)) {          /* Received OUT Data Interrupt        */
                UDPHS->UDPHS_IEN &= ~(1 << (n + 8));      /* Disable EP int until read*/
#ifdef __RTX

                if (USBD_RTX_EPTask[n]) {       /* OUT Packet                         */
                    isr_evt_set(USBD_EVT_OUT, USBD_RTX_EPTask[n]);
                }

#else

                if (USBD_P_EP[n]) {
                    USBD_P_EP[n](USBD_EVT_OUT);
                }

#endif
            }

            /* STALL Packet Sent Interrupt                                          */
            if (eptsta & (0x1 << 13)) {       /* Stall Sent                         */
                if ((UDPHS->UDPHS_EPT[n].UDPHS_EPTCFG & UDPHS_EPTCFG_EPT_TYPE_Msk) == UDPHS_EPTCFG_EPT_TYPE_CTRL8) {
#ifdef __RTX

                    if (USBD_RTX_EPTask[n]) {
                        isr_evt_set(USBD_EVT_IN_STALL, USBD_RTX_EPTask[n]);
                    }

#else

                    if (USBD_P_EP[n]) {
                        USBD_P_EP[n](USBD_EVT_IN_STALL);
                    }

#endif
                }

                UDPHS->UDPHS_EPT[n].UDPHS_EPTCLRSTA = UDPHS_EPTCLRSTA_STALL_SNT;
            }

            /* Setup Packet Received Interrupt                                      */
            if (eptsta & (0x1 << 12)) {       /* Received SETUP Interrupt           */
                UDPHS->UDPHS_IEN &= ~(1 << (n + 8));      /* Disable EP int until read*/
#ifdef __RTX

                if (USBD_RTX_EPTask[n]) {       /* SETUP Packet                       */
                    isr_evt_set(USBD_EVT_SETUP, USBD_RTX_EPTask[n]);
                }

#else

                if (USBD_P_EP[n]) {
                    USBD_P_EP[n](USBD_EVT_SETUP);
                }

#endif
            }
        }
    }

    NVIC_EnableIRQ(UDPHS_IRQn);
}