GD32450i-EVAL学习笔记 18 - USB FS

目录

1. 定义USB FS的结构

2. IO初始化

3. 初始化频率

3.1 IRC48M

3.2 PLL48M

3.3 使能USB FS

4. USB中断初始化

4.1 设置中断优先级

4.2 设置优先级

5. 初始化USB

5.1 选择内部PHY

5.2 复位

5.3 配置USB内核

5.4 软断开USB连接

5.5 设置USB模式

5.6 Device模式初始化

5.6.1 清除时钟停止使能

5.6.2 配置周期性帧尾时间

 5.6.3 设置USB速度

5.6.4 设置接收FIFO的长度

5.6.5 设置发送FIFO的长度

5.6.6 刷新所有TX FIFO

5.6.7 刷新RX FIFO

5.6.8 清除所有的中断标志

6. 初始化端点

6.1 清零所有IN端点

6.2 清零所有OUT端点

6.3 初始化EP

7. USB中断使能

7.1 端点Tx FIFO下溢中断使能

7.2 清除所有的中断

7.3 使能中断

7.4 使能USB中断总开关

8. 连接USB

9. USBFS_IRQHandler中断处理

9.1 判断是否为设备中断

9.2 判断该中断是否使能

9.3 端点OUT中断

9.4 端点IN中断

9.5 Suspend中断

9.6 唤醒中断

9.7 SOF中断

9.8 接收缓冲非空中断

9.9 复位中断

9.10 枚举完成中断

9.11 同步IN传输未完成中断

9.12 同步OUT端点未完成传输

9.13 会话中断


USBFS包含了一个内部的全速USB PHY,不需要外部PHY芯片。

注:GD32F450的USB FS寄存器地址分布和含义与STM32F407一样,只是各自的命名方式不同。另外,在使用中代码也可能会有少许不同,即GD32F450的USB代码不一定可以在STM32F407上跑,反之以然。

1. 定义USB FS的结构

#define USBFS_REG_BASE                  0x50000000L   /*!< base address of USBFS registers */

typedef struct
{
    uint32_t GOTGCS;                    //0x00
    uint32_t GOTGINTF;                  //0x04
    uint32_t GAHBCS;                    //0x08
    uint32_t GUSBCS;                    //0x0C
    uint32_t GRSTCTL;                   //0x10
    uint32_t GINTF;                     //0x14
    uint32_t GINTEN;                    //0x18
    uint32_t GRSTATR;                   //0x1C
    uint32_t GRSTATP;                   //0x20
    uint32_t GRFLEN;                    //0x24
    uint32_t HNPTFLEN_DIEP0TFLEN;       //0x28
    uint32_t HNPTFQSTAT;                //0x2C
    uint32_t recv1[2];                  //0x30, 0x34
    uint32_t GCCFG;                     //0x38
    uint32_t CID;                       //0x3C
    uint32_t recv2[48];                 //0x40 - 0xFF
    uint32_t HPTFLEN;                   //0x100
    uint32_t DIEPxTFLEN[3];             //0x104
}USBFSGlobal_t;

typedef struct
{
    uint32_t HCTL;                      //0x00
    uint32_t HFT;                       //0x04
    uint32_t HFINFR;                    //0x08
    uint32_t resv1;                     //0x0C
    uint32_t HPTFQSTAT;                 //0x10
    uint32_t HACHINT;                   //0x14
    uint32_t HACHINTEN;                 //0x18
    uint32_t resv2[9];                  //0x1C - 0x3F
    uint32_t HPCS;                      //0x40
    uint32_t resv3[47];                 //0x44 - 0xFF
    struct                              //0x100
    {
        uint32_t CTL;           //0x00
        uint32_t resv1;         //0x04 - 0x07
        uint32_t INTF;          //0x08
        uint32_t INTEN;         //0x0C
        uint32_t LEN;           
    }Channel[8];
}USBFSHost_t;

typedef struct
{
    uint32_t DCFG;                      //0x00
    uint32_t DCTL;                      //0x04
    uint32_t DSTAT;                     //0x08
    uint32_t recv1;                     //0x0C
    uint32_t DIEPINTEN;                 //0x10
    uint32_t DOEPINTEN;                 //0x14
    uint32_t DAEPINT;                   //0x18
    uint32_t DAEPINTEN;                 //0x1C
    uint32_t recv2[2];                  //0x20 - 0x27
    uint32_t DVBUSDT;                   //0x28
    uint32_t DVBUSPT;                   //0x2C
    uint32_t recv3;                     //0x30
    uint32_t DIEPFEINTEN;               //0x34
    uint32_t recv4[50];                 //0x38 - 0xFF
    struct                              //0x100
    {
        uint32_t CTL;           //0x00
        uint32_t recv1;         //0x04
        uint32_t INTF;          //0x08
        uint32_t recv2;         //0x0C
        uint32_t LEN;           //0x10
        uint32_t recv3;         //0x14
        uint32_t TFSTAT;        //0x18
        uint32_t recv4;         //0x1C, offset = 0x20
    }DIEPx[4];
    uint32_t recv5[96];                 //0x180 - 0x2FF  
    struct                              //0x300
    {
        uint32_t CTL;           //0x00
        uint32_t recv1;         //0x04
        uint32_t INTF;          //0x08
        uint32_t recv2;         //0x0C
        uint32_t LEN;           //0x10
        uint32_t recv3[3];       //0x14 - 0x1F
    }DOEPx[4];
}USBFSDev_t;

//#define USBFSCore                       ((USBFSGlobal_t *)USBFS_REG_BASE)
//#define USBFSDev                        ((USBFSDev_t *)(USBFS_REG_BASE + 0x800))
//#define USBFSPwrClk                     ((uint32_t *)(USBFS_REG_BASE + 0xE00))

typedef struct
{
    volatile USBFSGlobal_t *Global;
    volatile USBFSHost_t *Host;
    volatile USBFSDev_t *Dev;
    uint32_t *PwrClk;
    uint8_t maxEPNum;
    uint32_t *FIFO[4];
}USBFS_t;

volatile USBFS_t USBFS =
{
    ((USBFSGlobal_t *)USBFS_REG_BASE),
    ((USBFSHost_t *)(USBFS_REG_BASE + 0x400)),
    ((USBFSDev_t *)(USBFS_REG_BASE + 0x800)),
    ((uint32_t *)(USBFS_REG_BASE + 0xE00)),
    4,
    {
        ((uint32_t *)(USBFS_REG_BASE + 0x1000)), 
        ((uint32_t *)(USBFS_REG_BASE + 0x2000)), 
        ((uint32_t *)(USBFS_REG_BASE + 0x3000)), 
        ((uint32_t *)(USBFS_REG_BASE + 0x4000))
    },
};

2. IO初始化

DP、DM对应GPIOA11和GPIOA12.

//DM: GPIOA11, DP: GPIOA12
GPIO_AFSEL1(GPIOA) &= ~(uint32_t)((uint32_t)0xFF << (11 % 8) * 4);
GPIO_AFSEL1(GPIOA) |= (((uint32_t)0xAA << (11 % 8) * 4)); 
GPIO_CTL(GPIOA) &= ~(uint32_t)(((uint32_t)0xF << 11 * 2));
GPIO_CTL(GPIOA) |= (uint32_t)(((uint32_t)0xA << 11 * 2)); //GPIO_MODE_AF
GPIO_PUD(GPIOA) &= ~(uint32_t)(((uint32_t)0xF << 11 * 2));
//GPIO_PUD(GPIOA) |= (uint32_t)(((uint32_t)0x5 << 11 * 2)); //GPIO_PUPD_PULLUP
GPIO_OMODE(GPIOA) &= ~(uint32_t)((uint32_t)0x3 << 11);    //GPIO_OTYPE_PP
GPIO_OSPD(GPIOA) &= ~(uint32_t)((uint32_t)0xF << 11 * 2);
GPIO_OSPD(GPIOA) |= (uint32_t)(((uint32_t)0xF << 11 * 2)); //GPIO_OSPEED_200MHZ

3. 初始化频率

 USB的频率源有2种方式:IRC48M(内部48MHz RC 振荡器时钟)和PLL48M。

3.1 IRC48M

IRC48M晶振对应USB应用精度不够高,所以还需要CK_CTC校准精度。

通过设置RCU_ADDCTL的位16为1使能IRC48M,然后通过判断RCU_ADDCTL的位17为1表示IRC48M已经稳定。

{
    uint32_t timeout;
    RCU_ADDCTL |= ((uint32_t)1 << 16);  //Enable IRC48M
    timeout = 30000;
    do
    {
        if((RCU_ADDCTL & ((uint32_t)1 << 17)) > 1)
            break;
        timeout--;
        delayms(1);
    }while(timeout > 0);
    RCU_ADDCTL |= ((uint32_t)1 << 0);  //Select IRC48M      
}

 USB初始化完成后再设置CTC校准

RCU_ADDAPB1EN |= ((uint32_t)1 << 27);  //Enable CTC
ctcConfig();
while ((CTC_STAT & ((uint32_t)1 << 0)) == 0)  //1 means CK OK
{
}

其中CTC校准函数ctcConfig参考例程拷贝

void ctcConfig(void)
{
    /* configure CTC reference signal source prescaler */
    ctc_refsource_prescaler_config(CTC_REFSOURCE_PSC_OFF);
    /* select reference signal source */
    ctc_refsource_signal_select(CTC_REFSOURCE_USBSOF);
    /* select reference signal source polarity */
    ctc_refsource_polarity_config(CTC_REFSOURCE_POLARITY_RISING);
    /* configure hardware automatically trim mode */
    ctc_hardware_trim_mode_config(CTC_HARDWARE_TRIM_MODE_ENABLE);

    /* configure CTC counter reload value, Fclock/Fref-1 */
    ctc_counter_reload_value_config(0xBB7F);
    /* configure clock trim base limit value, Fclock/Fref*0.0012/2 */
    ctc_clock_limit_value_config(0x1D);

    /* CTC counter enable */
    ctc_counter_enable();
}

3.2 PLL48M

PLL48M有2个源:CK_PLLQ时钟或CK_PLLSAIP时钟。建议使用CK_PLLQ时钟。

RCU_ADDCTL &= ~((uint32_t)1 << 1);  //Select PLLQ
RCU_ADDCTL &= ~((uint32_t)1 << 0);  //Select PLL48M

 对于GD32F450 200M时钟时,现在的例程中CK_PLLQ时钟不准,会导致USB工作不稳定。可以选择120M或168M。

附PLL的计算公式,对于USB应用要是PLLQ为48M:
CK_PLLVCOSRC = CK_PLLSRC /  PLLPSC
CK_PLLVCO =  CK_PLLVCOSRC × PLLN
CK_PLLP =  CK_PLLVCO / PLLP
CK_PLLQ =  CK_PLLVCO / PLLQ

CK_PLLSRC即外部晶体的频率,这里是25M。

/* Configure the main PLL, PSC = 25, PLL_N = 400, PLL_P = 2, PLL_Q = 9 */ 
RCU_PLL = (25U | (400U << 6U) | (((2U >> 1U) - 1U) << 16U) |
                   (RCU_PLLSRC_HXTAL) | (9U << 24U));

即 CK_PLLVCOSRC = 1M,CK_PLLVCO = 400M,CK_PLLP = 200M,PLLQ = 400 / 9 = 44.4444M, 和48M有误差。要想200M的PLLP和48M的PLLQ同时成立,则PLLVCO最小要设置到1200M,而PLLVCO的范围是100MHz 到 500MHz 之间,所以当200M频率需求时,无法使用PLL48M模式,可以采用第一种IRC48M的设置。

3.3 使能USB FS

RCU_AHB2EN |= ((uint32_t)1 << 7); //Enable

4. USB中断初始化

USB FS有2个中断:USBFS_WKUP_IRQHandler(只有在使用USB睡眠功能时才需要)和USBFS_IRQHandler。

4.1 设置中断优先级

SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | ((uint32_t)0x500);

设置中断优先级的组,即中断用2个位作为组优先级,用2个位作为子优先级。

4.2 设置优先级

USBFS_WKUP_IRQHandler设置为组0,组内编号0,即Wakeup的中断有限级最高,而USBFS_IRQn设置为组3,组内编号0,即中断优先级是组3中最高,但是比Wakeup低2级。

nvic_irq_enable((uint8_t)USBFS_IRQn, 3U, 0U);
#ifdef USB_LOW_POWER
RCU_APB1EN |= ((uint32_t)1 << 28);    //Enable PMU
/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_18);
exti_init(EXTI_18, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_18);

nvic_irq_enable((uint8_t)USBFS_WKUP_IRQn, 0U, 0U);
#endif

5. 初始化USB

5.1 选择内部PHY

USBFS.Global->GUSBCS |= ((uint32_t)1 << 6); //Select embedded PHY

这里有个问题,datasheet中没有这个位的说明,代码里面设置这个位为1.

5.2 复位

USB内核软件复位, 复位AHB和USB时钟域电路,以及大多数的寄存器。

//Reset Core
USBFS.Global->GRSTCTL |= ((uint32_t)1 << 0);
while ((USBFS.Global->GRSTCTL & ((uint32_t)1 << 0))  > 0)     // wait for the core to be soft reset
{
}
delayus(3);

5.3 配置USB内核

//Active the transceiver and enable VBUS sensing
//bit16: Power On
//bit18: VBUS A-device comparer enable
//bit19: VBUS B-device comparer enable
USBFS.Global->GCCFG |= ((uint32_t)1 << 16) | ((uint32_t)1 << 18) | ((uint32_t)1 << 19);
#ifndef USB_IGNORE_VBUS
USBFS.Global->GCCFG |= ((uint32_t)1 << 21);
#endif
USBFS.Global->GCCFG |= ((uint32_t)1 << 20); //Enable SOF
delayms(20);

位16表示USB内核上电,位18和位19是用于OTG识别设备类型。

位21表示是否忽略VBUS检测,为1时则表示忽略VBUS引脚电压,这时可以将该Pin作为其他使用。

位20表示SOF输出使能。

5.4 软断开USB连接

#ifdef USB_DEVICE_MODE
USBFS.Dev->DCTL |= ((uint32_t)1 << 1);  //Soft Disconnect
#endif

5.5 设置USB模式

USBFS.Global->GUSBCS &= ~(((uint32_t)1 << 29) | ((uint32_t)1 << 30));
#if (defined(USB_DEVICE_MODE))
USBFS.Global->GUSBCS |= ((uint32_t)1 << 30);
#elif (defined(USB_HOST_MODE))
USBFS.Global->GUSBCS |= ((uint32_t)1 << 29);
#endif

OTG不需要设置,而Device和Host模式下需要将USB强制设置为对应的模式。

5.6 Device模式初始化

5.6.1 清除时钟停止使能

USBFS.PwrClk = 0;

5.6.2 配置周期性帧尾时间

定义周期性帧时间的帧尾标志触发的时间点,默认80%

USBFS.Dev->DCFG &= ~((uint32_t)0x03 << 11);

 5.6.3 设置USB速度

USB FS只能设置全速

USBFS.Dev->DCFG |= ((uint32_t)0x03 << 0);

5.6.4 设置接收FIFO的长度

所有的OUT端点通过共享 Rx FIFO接收包数据。

USBFS.Global->GRFLEN = USB_FS_FIFO_RX_LEN;

接收FIFO总是在USB FIFO中起始位置开始的,所以不需要设置RX FIFO的起始地址。 注意这个长度是32位计数,比如如果设置RX FIFO的长度为64字节,这个寄存器的值为64/4 = 16。STM32F407的文档建议这个长度为40个字,即160字节。

5.6.5 设置发送FIFO的长度

发送FIFO有4个(设备模式下),即每个IN端点使用一个FIFO。同样的,这些长度都是32位计数的。

※端点0的TX FIFO设置

端点0的TX FIFO在Global的设置中,紧接着RX FIFO。

USBFS.Global->HNPTFLEN_DIEP0TFLEN = ((uint32_t)USB_FS_FIFO_TX0_LEN << 16) | USB_FS_FIFO_RX_LEN;

※其他3个端点的TX FIFO设置

USBFS.Global->DIEPxTFLEN[0] = ((uint32_t)USB_FS_FIFO_TX1_LEN << 16) 
    | (USB_FS_FIFO_RX_LEN + USB_FS_FIFO_TX0_LEN);
USBFS.Global->DIEPxTFLEN[1] = ((uint32_t)USB_FS_FIFO_TX2_LEN << 16) 
    | (USB_FS_FIFO_RX_LEN + USB_FS_FIFO_TX0_LEN + USB_FS_FIFO_TX1_LEN);
USBFS.Global->DIEPxTFLEN[2] = ((uint32_t)USB_FS_FIFO_TX3_LEN << 16) 
    | (USB_FS_FIFO_RX_LEN + USB_FS_FIFO_TX0_LEN + USB_FS_FIFO_TX1_LEN + USB_FS_FIFO_TX2_LEN);

仔细说明一下FIFO的结构:

USBFS的FIFO总大小为1.25K字节。上面的初始化就是通过USBFS_GRFLEN USBFS_DIEPxTFLEN (x=0…3)配置 FIFO 的大小和起始偏移地址。FIFO的地址和大小如下图:

整个FIFO大小为1.25K字节 = 1280字节 = 0x500,上图中End是0x13F,是因为这里是以字(4字节)计算的,所以0x500 / 4 = 0x140。

整个FIFO可以分为5个空间,即1个Rx FIFO空间和4个Tx FIFO空间,所有的端点公用Rx FIFO空间,4个端点各自有对应的Tx FIFO空间。

Rx FIFO空间的起始地址固定为0x000,它的大小由USBFS_GRFLEN设定,注意这里设置的是字节数,而且长度必须是4的倍数。

USBFS_DIEPxTFLEN中设定的是4个Tx FIFO的起始地址和长度,高16位是起始地址,而低16位为FIFO长度,注意也是字节且长度必须是4个倍数。

上面是配置FIFO的空间分布,而实际读写FIFO时FIFO的范围地址是映射为固定的,并不是上面设置长度时的位置,如下图,比如端点0的地址0x1000-0x1FFF。写端点0时数据写入0x1000这个地址即可。

而且在读写FIFO时必须是4字节的倍数读写。

5.6.6 刷新所有TX FIFO

void usbFlushTXFIFO(uint8_t fifoNum)
{
    USBFS.Global->GRSTCTL = ((uint32_t)fifoNum << 6U) | ((uint32_t)1 << 5);
    while((USBFS.Global->GRSTCTL & ((uint32_t)1 << 5)) > 0)
    {
    }
    delayus(3);
}

刷新所有的FIFO参数为0x10即可。

5.6.7 刷新RX FIFO

void usbFlushRXFIFO(void)
{
    USBFS.Global->GRSTCTL = ((uint32_t)1 << 4);
    while((USBFS.Global->GRSTCTL & ((uint32_t)1 << 4)) > 0)
    {
    }
    delayus(3);
}

5.6.8 清除所有的中断标志

//Clear all pending device interrupts
USBFS.Dev->DIEPINTEN = 0U;
USBFS.Dev->DOEPINTEN = 0U;
USBFS.Dev->DAEPINT = 0xFFFFFFFFU;
USBFS.Dev->DAEPINTEN = 0U;

6. 初始化端点

6.1 清零所有IN端点

for(i = 0; i < USBFS.maxEPNum; i++)
{
    if((USBFS.Dev->DIEPx[i].CTL & ((uint32_t)1 << 31)) > 0)  //bit31: DP Enable
    {
        USBFS.Dev->DIEPx[i].CTL |= ((uint32_t)1 << 30 | (uint32_t)1 << 27); //bit30: DP Disable, bit27: Set NAK
    }
    else
    {
        USBFS.Dev->DIEPx[i].CTL = 0;
    }
    USBFS.Dev->DIEPx[i].LEN = 0;       //set IN endpoint transfer length to 0
    USBFS.Dev->DIEPx[i].INTF = 0xFF;   //clear all pending IN endpoint interrupts
}

6.2 清零所有OUT端点

if((USBFS.Dev->DOEPx[i].CTL & ((uint32_t)1 << 31)) > 0)  //bit31: DP Enable
{
    USBFS.Dev->DOEPx[i].CTL |= ((uint32_t)1 << 30 | (uint32_t)1 << 27); //bit30: DP Disable, bit27: Set NAK
}
else
{
    USBFS.Dev->DOEPx[i].CTL = 0;
}
USBFS.Dev->DOEPx[i].LEN = 0;       //set OUT endpoint transfer length to 0
USBFS.Dev->DOEPx[i].INTF = 0xFF;   //clear all pending OUT endpoint interrupts

6.3 初始化EP

每个端点设置方向、包最大大小和端点编号(这个可以通过配置描述符约束依次定义),其中端点0是默认64字节大小,双向。

if(i < sizeof(epDir))
{
    //bit0-10: maximum packet length
    //bit18-19: endpoint type
    //bit22-25: FIFO number
    if(epDir[i] == USB_EP_DIR_IN || epDir[i] == USB_EP_DIR_BOTH)
    {
        USBFS.Dev->DIEPx[i].CTL &= ~(((uint32_t)0x7FF << 0) | ((uint32_t)0x3 << 18) | ((uint32_t)0xF << 22));
        USBFS.Dev->DIEPx[i].CTL |= ((uint32_t)epInSize[i] << 0) | ((uint32_t)epType[i] << 18) | ((uint32_t)i << 22);
        value |= (uint32_t)1 << i;
    }
    if (epDir[i] == USB_EP_DIR_OUT || epDir[i] == USB_EP_DIR_BOTH)
    {
        USBFS.Dev->DOEPx[i].CTL &= ~(((uint32_t)0x7FF << 0) | ((uint32_t)0x3 << 18) | ((uint32_t)0xF << 22));
        USBFS.Dev->DOEPx[i].CTL |= ((uint32_t)epInSize[i] << 0) | ((uint32_t)epType[i] << 18) | ((uint32_t)i << 22);
        value |= (uint32_t)1 << (i + 16);
    }
}

 最后将对应的USB端点中断使能

USBFS.Dev->DAEPINTEN |= value;

7. USB中断使能

7.1 端点Tx FIFO下溢中断使能

USBFS.Dev->DIEPINTEN |= ((uint32_t)1 << 4); //endpoint Tx FIFO underrun interrupt enable bit

7.2 清除所有的中断

USBFS.Global->GOTGINTF = 0xFFFFFFFF;
USBFS.Global->GINTF = 0xBFFFFFFF;

7.3 使能中断

//bit31: wakeup interrupt enable
//bit11: USB suspend interrupt enable
USBFS.Global->GINTEN = ((uint32_t)1 << 31) | ((uint32_t)1 << 11);
#ifdef USB_USB_FIFO
USBFS.Global->GINTEN |= (uint32_t)1 << 4;   //bit4: receive FIFO non-empty interrupt enable
#endif
USBFS.Global->GINTEN |= 
        ((uint32_t)1 << 12) |       //bit12: USB reset interrupt enable
        ((uint32_t)1 << 13) |       //bit13: enumeration finish enable
        ((uint32_t)1 << 18) |       //bit18: IN endpoints interrupt enable
        ((uint32_t)1 << 19) |       //bit19: OUT endpoints interrupt enable
        ((uint32_t)1 << 3) |        //bit3: start of frame interrupt enable
        ((uint32_t)1 << 21) |       //bit21: isochronous OUT transfer not complete interrupt enable
        ((uint32_t)1 << 20);        //bit20: isochronous IN transfer not complete interrupt enable
#ifdef USB_IGNORE_VBUS
//bit30: session interrupt enable
//bit2: OTG interrupt enable
USBFS.Global->GINTEN |= ((uint32_t)1 << 30) | ((uint32_t)1 << 2);
#endif

 

7.4 使能USB中断总开关

USBFS.Global->GAHBCS |= ((uint32_t)1 << 0);     //bit0: global interrupt enable

8. 连接USB

#ifndef USB_OTG_MODE
USBFS.Dev->DCTL &= ~((uint32_t)1 << 1);
delayms(3);
#endif

到了这一步USB的USBFS_IRQHandler中断应该可以进入了。

9. USBFS_IRQHandler中断处理

9.1 判断是否为设备中断

if((USBFS.Global->GINTF & ((uint32_t)1 << 0)) > 0)
        return;

如果是主机模式中断,则直接返回

9.2 判断该中断是否使能

intr = USBFS.Global->GINTF & USBFS.Global->GINTEN;
if(intr == 0)
    return;

9.3 端点OUT中断

if ((intr & ((uint32_t)1 << 19)) > 0) //bit19: OUT endpoint interrupt flag
{
        
}

9.4 端点IN中断

if ((intr & ((uint32_t)1 << 18)) > 0) //bit18: IN endpoint interrupt flag
{
        
}

9.5 Suspend中断

if ((intr & ((uint32_t)1 << 11)) > 0) //bit11: USB suspend
{
        
}

9.6 唤醒中断

if ((intr & ((uint32_t)1 << 31)) > 0) //bit31: wakeup interrupt flag
{
        
}

9.7 SOF中断

if ((intr & ((uint32_t)1 << 3)) > 0) //bit3: start of frame flag
{
        
}

9.8 接收缓冲非空中断

if ((intr & ((uint32_t)1 << 4)) > 0) //bit4: rx FIFO non-empty interrupt flag 
{
        
}

9.9 复位中断

if ((intr & ((uint32_t)1 << 12)) > 0) //bit12: USB reset
{
        
}

9.10 枚举完成中断

if ((intr & ((uint32_t)1 << 13)) > 0) //bit13: enumeration finished
{
        
}

9.11 同步IN传输未完成中断

if ((intr & ((uint32_t)1 << 20)) > 0) //bit20: isochronous IN transfer not complete interrupt flag
{
        
}

9.12 同步OUT端点未完成传输

if ((intr & ((uint32_t)1 << 21)) > 0) //bit21: isochronous OUT transfer not complete interrupt flag
{
        
}

9.13 会话中断

if ((intr & ((uint32_t)1 << 2)) > 0) //bit2: OTG interrupt flag
{
        
}

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值