打印
[应用方案]

NUC970 裸机USBD驱动

[复制链接]
1448|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
晓伍|  楼主 | 2021-8-1 16:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
NUC970的USB接收缓冲区非常方便,比如实际上bluk只有64字节,但是设置缓冲区大小512字节,也可以非常容易的接收512字节及以上的数据包,只要主机OUT,设备会自动接收,但是也有个问题,就是CBW数据包会跟bluk数据包混在一起,这个时候就不好处理了,貌似NUC970是自动流控,就是只要缓冲区有数据,就会自动接收来自主机的OUT数据。

先上USBD.c代码,主要是底层硬件操作,跟USB协议无关部分,将所有中断函数使用回调方式暴露出来,无需着重的去处理某个中断,实际内部已经做好了处理。

/*************************************************************************************************************
* 文件名:                        usbd.c
* 功能:                        NUC970 USB设备相关驱动
* 作者:                        cp1300@139.com
* 创建时间:                2020-10-12
* 最后修改时间:        2020-10-12
* 详细:                       
*************************************************************************************************************/
#include "nuc970_system.h"
#include "usbd.h"
#include "typedef.h"
#include "irq_aic.h"
#include "usbd_req.h"

#define USBD_MAX_DMA_LEN                    0x1000                                                                //DMA最大传输数据长度
               
//USBD所需全局变量定义==必须4字节对齐
#pragma pack(4)
typedef struct
{
        const USBD_DESCRIPTOR *pDescData;                                                                        //全局的描述符信息
        USBD_IRQHandlerType pUSBD_BusIRQHandlerCallBack;                                        //总线中断服务程序回调处理
        USBD_IRQHandlerType pUSBD_cEpIRQHandlerCallBack;                                        //控制端点中断服务程序回调处理
        USBD_CLASS_REQ pClassReqCallBack;                                                                        //类别请求回调处理
        USBD_VENDOR_REQ pVendorReqCallBack;                                                                        //厂商请求回调处理
        volatile u8         DeviceAddr;                                                                                        //USB设备地址
        volatile bool isTestMode;                                                                                        //是否为测试模式
        volatile u8        TestSelector;                                                                                        //选择的测试通道
        volatile bool isConfig;                                                                                                //主机配置设备
        volatile u8         ConfigValue;                                                                                        //主机发送的配置参数
        volatile u8         UsbAltInterface;                                                                                //主机指定的接口描述符
        volatile u8 CtrSendDataLen;                                                                                        //控制待发送命令数据长度,待控制端口IN令牌有效后将会发送数据
        volatile u8 CtrReadDataLen;                                                                                        //读取的控制端点数据长度
        volatile u8         CtrSendDataBuff[128];                                                                        //控制待发送命令缓冲区
        volatile u8 *pCtrlInPointer;                                                                                //指向 CtrDataBuff 缓冲区的指针
        volatile u8         CtrReadDataBuff[64];                                                                        //读取的控制端点数据缓冲区
}USBD_GLOBAL_DTAT;
#pragma pack()

static void USBD_IRQHandler(void);                                                                                //中断服务程序
static USBD_EP_CONFIG sg_EpConfig[USBD_MAX_EP];                                                        //全局EP配置信息
static USBD_GLOBAL_DTAT sg_USBD_Data;                                                                        //USBD所需全局变量结构体
USBD_SETUP_TYPE g_USBD_Setup;                                                                                        //全局USB SETUP信息结构体

#define USBD_EP_INIT_ID                        0x13542557                                                                                                        //端点是否初始化
#define USBD_SET_MAX_PAYLOAD(ep, size)          (USBD->EPx[ep].MPS = (size))                                        //设置端点x的最大数据包长度
#define USBD_WriteCEP_DataByte(data)                 (*((vu8*)(&(USBD->CEPDAT))) = (data))                        //写入BYTE数据到控制端点数据发送寄存器
#define USBD_ReadCEP_DataByte()                         (*((vu8*)(&(USBD->CEPDAT))))                                        //从控制端点数据接收寄存器读取BYTE数据


static void USBD_SetEpConfig(USBD_EP_CONFIG *pConfig);                                                        //设置一个端点(会配置到硬件中)
static void USBD_SetEpBuffAddr(USBD_EPx EPx, u32 EpBuffOffset, u32 EpBuffSzie);        //设置端点缓冲区地址(会配置到硬件中)
static void USBD_StandardRequest(void);                                                                                        //标准请求处理
static void USBD_SetupHandle(void);                                                                                                //USB Setup处理
static bool USBD_DMA_TransferData(USBD_EPx EPx, u32 BuffAddr, u16 Len, bool isShortPacket);        //DAM传输数据(不会设置传输方向)



/*************************************************************************************************************************
* 函数                        :        void USBD_Init(void)
* 功能                        :        初始化USBD
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :
*************************************************************************************************************************/
void USBD_Init(void)
{
        outpw(REG_SYS_GPH_MFPL, (inpw(REG_SYS_GPH_MFPL) & ~0xf) | 0x7);
        SYS_DeviceClockEnable(DEV_USBD, TRUE);                                        //使能USBD时钟
        USBD_DISABLE_USB();
        USBD_DISABLE_PHY();
        SYS_DeviceReset(DEV_RESET_USBD);                                                //USBD复位
        SYS_DelayMS(10);
       
    USBD_ENABLE_PHY() ;                                                                                //使能USBD PHY
        SYS_DelayMS(1);
        memset(sg_EpConfig, 0, sizeof(sg_EpConfig));                        //复位ep配置信息
        memset(&sg_USBD_Data, 0, sizeof(USBD_GLOBAL_DTAT));                //全局数据清除
        while(USBD->EPx[USBD_EPA].MPS != 0x08)
        {
                USBD->EPx[USBD_EPA].MPS = 0x08;                                                //写入并读取,看看是否一致,等待PHY时钟稳定
        }
       
        USBD_SET_ADDR(0);                                                                                //复位地址为0
        USBD_SetEpBuffAddr(USBD_CEP, CEP_BUFF_OFFSET, CEP_BUFF_SIZE);//设置控制端点缓冲区
        USBD_ENABLE_USB_INT(0x1FFF);                                                        //开启所有USB中断
        //控制端口相关中断开启
        USBD_ENABLE_CEP_INT(USBD_CEPINTSTS_SETUPPKIF_Msk|                //控制端点SETUP数据包中断
                                                //USBD_CEPINTSTS_OUTTKIF_Msk|                //控制端点OUT令牌中断
                                                //USBD_CEPINTSTS_INTKIF_Msk|                //控制端点IN令牌中断-无需提前开启,在USBD_PrepareCtrlIn中开启,有数据发送才提前开启
                                                //USBD_CEPINTSTS_TXPKIF_Msk|                //控制端点数据发送中断-无需提前开启,收到IN令牌后有数据要发送就会自动开启
                                                USBD_CEPINTSTS_RXPKIF_Msk|                        //控制端点数据接收中断
                                                USBD_CEPINTSTS_ERRIF_Msk                        //控制端点错误中断
                                                //USBD_CEPINTSTS_STSDONEIF_Msk                //控制端点状态完成中断       
                                                );
        //BUS相关中断开启
        USBD_ENABLE_BUS_INT(USBD_BUSINTSTS_RSTIF_Msk|                        //端口重置中断
                                                USBD_BUSINTSTS_RESUMEIF_Msk|                //设备恢复
                                                USBD_BUSINTSTS_SUSPENDIF_Msk|                //暂停
                                                USBD_BUSINTSTS_HISPDIF_Msk|                        //设备已设置为高速
                                                USBD_BUSINTSTS_VBUSDETIF_Msk                //VBUS已插入
                                                );

        USBD_SET_OPER(USBD_OPER_HISPDEN_Msk);                                         //设置为高速
        USBD_SET_SE0();
        USBD_SET_ADDR(0);                                                                                //复位地址为0
       
        AIC_SetIrqTriggered(AIC_USBD_INT, AIC_HIGHT_LEVEL);                //设置中断高电平触发
        AIC_SetIrqPriority(AIC_USBD_INT, SYS_INT_USBD_PRO);                //设置一个中断优先级
        AIC_RegisterIRQHandler(AIC_USBD_INT, USBD_IRQHandler);        //注册中断服务程序
        AIC_IrqEnable(AIC_USBD_INT, TRUE);                                                //开启AIC中断
}



使用特权

评论回复
沙发
晓伍|  楼主 | 2021-8-1 16:30 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        void USBD_InterfaceConfig(USBD_IRQHandlerType pBusIRQCallBack, USBD_IRQHandlerType pCEpIRQCallBack, USBD_CLASS_REQ pClassReqCallBack,
                                                USBD_VENDOR_REQ pVendorReqCallBack,const USBD_DESCRIPTOR *pDescData)
* 功能                        :        USBD所需接口配置
* 参数                        :        pBusIRQCallBack:BUS中断回调处理;pCEpIRQCallBack:控制端点中断回调处理;pClassReqCallBack:类别请求回调处理
                                        pVendorReqCallBack:厂商请求回调处理;pDescData:全局描述符数据信息
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :
*************************************************************************************************************************/
void USBD_InterfaceConfig(USBD_IRQHandlerType pBusIRQCallBack, USBD_IRQHandlerType pCEpIRQCallBack, USBD_CLASS_REQ pClassReqCallBack,
        USBD_VENDOR_REQ pVendorReqCallBack,const USBD_DESCRIPTOR *pDescData)
{
        sg_USBD_Data.pUSBD_BusIRQHandlerCallBack = pBusIRQCallBack;        //总线中断服务程序回调处理               
        sg_USBD_Data.pUSBD_cEpIRQHandlerCallBack = pCEpIRQCallBack;        //控制端点中断服务程序回调处理       
        sg_USBD_Data.pClassReqCallBack = pClassReqCallBack;                        //类别请求回调处理
        sg_USBD_Data.pVendorReqCallBack = pVendorReqCallBack;                //厂商请求回调处理
        sg_USBD_Data.pDescData = pDescData;                                                        //描述符数据信息
}


/*************************************************************************************************************************
* 函数                        :        void USBD_Start(void)
* 功能                        :        USB启动(清除SE0)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        当初始化USB硬件后,监测到VBUS有效后调用,清除SE0状态
*************************************************************************************************************************/
void USBD_Start(void)
{
    USBD_CLR_SE0();
}

/*************************************************************************************************************************
* 函数                        :        u16 USBD_ReadEPxOutData(USBD_EPx EPx, u8 *pData)
* 功能                        :        从EPx的OUT缓冲区中读取数据
* 参数                        :        EPx:EP端点选择,见USBD_EPx;pData:数据缓冲区(缓冲区长度必须大于一个包长度)
* 返回                        :        数据长度
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-15
* 最后修改时间         :         2020-10-15
* 说明                        :        在端点收到数据后调用
*************************************************************************************************************************/
u16 USBD_ReadEPxOutData(USBD_EPx EPx, u8 *pData)
{
        u16 len,i;
       
        if(EPx > USBD_EPL) return 0;
        len = USBD->EPx[EPx].DATCNT & 0xffff;        //获取收到的数据长度
        for(i = 0;i < len;i ++)
        {
                pData = USBD_ReadEPx_DataByte(EPx);//读取数据
        }
       
        return len;
}



使用特权

评论回复
板凳
晓伍|  楼主 | 2021-8-1 16:31 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        USBD_EP_CONFIG *USBD_GetEpConfigPointer(USBD_EPx EPx)
* 功能                        :        获取一个端点的配置指针,可以对端点进行配置(配置到缓存中)
* 参数                        :        EPx:EP端点选择,见USBD_EPx
* 返回                        :        配置指针,见USBD_EP_CONFIG
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        并未配置到设备
*************************************************************************************************************************/
USBD_EP_CONFIG *USBD_GetEpConfigPointer(USBD_EPx EPx)
{
        if(EPx > USBD_EPL) return NULL;
       
        return &sg_EpConfig[EPx];
}


/*************************************************************************************************************************
* 函数                        :        void USBD_SetEpConfigData(USBD_EPx EPx,USBD_EP_TYPE EpType, USBD_EP_DIR EpDir, u32 EnableIntBit, u16 EpBuffOffset, u16 EpBuffSzie, u16 EpMaxPackSzie,
                                                USBD_EPxIRQHandlerType pCallBack)
* 功能                        :        对一个端点进行配置(配置到缓存中)
* 参数                        :        EPx:EP端点选择,见USBD_EPx;EpType:EP类型,见USBD_EP_TYPE;EpDir:EP方向,见USBD_EP_DIR;EnableIntBit:需要使能的中断;
                                        EpBuffOffset:EP缓冲区偏移;EpBuffSzie:EP缓冲区大小;EpMaxPackSzie:当前EP最大数据包大小;pCallBack:当前EP中断回调函数
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        要在USB启动前进行初始化,并且并未配置到USB硬件中;先调用USBD_GetIdleEp()获取一个空闲端点,之后调用本函数进行初始化
*************************************************************************************************************************/
void USBD_SetEpConfigData(USBD_EPx EPx,USBD_EP_TYPE EpType, USBD_EP_DIR EpDir, u32 EnableIntBit, u16 EpBuffOffset, u16 EpBuffSzie, u16 EpMaxPackSzie,
        USBD_EPxIRQHandlerType pCallBack)
{
        if(EPx > USBD_EPL) return;

        sg_EpConfig[EPx].EPx = EPx;                                                                //EP端点
        sg_EpConfig[EPx].EnableIntBit = EnableIntBit;                        //使能的中断
        sg_EpConfig[EPx].EpNum = EPx + 1;                                                //EP端点编号
        sg_EpConfig[EPx].EpBuffOffset = EpBuffOffset;                        //EP端点缓冲区位置(USBD缓冲区)
        sg_EpConfig[EPx].EpBuffSzie = EpBuffSzie;                                //EP端点缓冲区大小(USBD缓冲区)
        sg_EpConfig[EPx].EpUSB20_MaxPackSize = EpMaxPackSzie;        //EP端点最大数据包大小
        sg_EpConfig[EPx].EpType = EpType;                                                //EP端点类型
        sg_EpConfig[EPx].EpDir = EpDir;                                                        //EP端点方向
        sg_EpConfig[EPx].EpIRQHandlerCallBack = pCallBack;                //EP端点中断回调函数
       
        sg_EpConfig[EPx].InitId = USBD_EP_INIT_ID;                                //端点是否初始化了
}


/*************************************************************************************************************************
* 函数                        :        bool USBD_GetIdleEp(USBD_EPx *pEPx)
* 功能                        :        获取一个空闲的EP通道
* 参数                        :        pEPx:返回EP端点选择,见USBD_EPx
* 返回                        :        TRUE:空闲;FALSE:没有空闲
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        获取后需要立即调用 USBD_SetEpConfigData() ,将端点进行配置,并占用,否则会一直返回同一个空闲端点
*************************************************************************************************************************/
bool USBD_GetIdleEp(USBD_EPx *pEPx)
{
        u8 i;
       
        for(i = 0;i < USBD_MAX_EP;i ++)
        {
                if(sg_EpConfig.InitId != USBD_EP_INIT_ID)                //找到空闲的EP了
                {
                        *pEPx = (USBD_EPx)i;
                        return TRUE;
                }
        }
       
        return FALSE;
}



使用特权

评论回复
地板
晓伍|  楼主 | 2021-8-1 16:32 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        static void USBD_SetEpConfig(USBD_EP_CONFIG *pConfig)
* 功能                        :        设置一个端点(会配置到硬件中)
* 参数                        :        pConfig:需要配置的EP配置数据
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        会配置到设备
*************************************************************************************************************************/
static void USBD_SetEpConfig(USBD_EP_CONFIG *pConfig)
{
        if(pConfig->EPx > USBD_EPL) return;
       
        switch(pConfig->EpType)
        {
                case USBD_EP_TYPE_BULK        :        //块传输
                {
                        USBD->EPx[pConfig->EPx].RSPCTL = (USB_EP_RSPCTL_FLUSH|USB_EP_RSPCTL_MODE_AUTO);
                }break;
                case USBD_EP_TYPE_INT        :        //中断
                {
                        USBD->EPx[pConfig->EPx].RSPCTL = (USB_EP_RSPCTL_FLUSH|USB_EP_RSPCTL_MODE_MANUAL);
                }break;
                case USBD_EP_TYPE_ISO        :        //同步
                {
                        USBD->EPx[pConfig->EPx].RSPCTL = (USB_EP_RSPCTL_FLUSH|USB_EP_RSPCTL_MODE_FLY);
                }break;
                default:break;
        }
        if (USBD->OPER & 0x04)  //high speed USB2.0
        {
                pConfig->EpMaxPackSzie = pConfig->EpUSB20_MaxPackSize;                                                                                //USB2.0数据包大小,通常是超过64字节的
        }
        else //USB1.1
        {
                pConfig->EpMaxPackSzie = 64;                                                                                                                                //USB 1.1 固定为64字节
        }
        USBD_SET_MAX_PAYLOAD(pConfig->EPx, pConfig->EpMaxPackSzie);                                                                                //设置最大数据包大小

    USBD->EPx[pConfig->EPx].CFG = ((pConfig->EpNum&0xF) << 4) | (pConfig->EpDir << 3) | (pConfig->EpType<<1) | (1<<0);
        USBD_SetEpBuffAddr(pConfig->EPx, pConfig->EpBuffOffset, pConfig->EpBuffSzie);
        USBD_ENABLE_EP_INT(pConfig->EPx, pConfig->EnableIntBit);                //开启对应中断
       
        sg_EpConfig[pConfig->EPx].InitId = USBD_EP_INIT_ID;                                //端点是否初始化了
}


/*************************************************************************************************************************
* 函数                        :        void USBD_ResetDMA(void)
* 功能                        :        复位DMA
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
void USBD_ResetDMA(void)
{
    USBD->DMACNT = 0;
    USBD->DMACTL = 0x80;
    USBD->DMACTL = 0x00;
}



使用特权

评论回复
5
晓伍|  楼主 | 2021-8-1 16:33 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        void USBD_SetEpBuffAddr(USBD_EPx EPx, u32 EpBuffOffset, u32 EpBuffSzie)
* 功能                        :        设置端点缓冲区地址(会配置到硬件中)
* 参数                        :        EPx:端点号,见USBD_EPx;EpBuffOffset:端点缓冲区偏移;EpBuffSzie:端点缓冲区大小
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
static void USBD_SetEpBuffAddr(USBD_EPx EPx, u32 EpBuffOffset, u32 EpBuffSzie)
{
        if(EPx > USBD_CEP) return;
       
    if (EPx == USBD_CEP)         //控制端点
        {
        USBD->CEPBUFSTART = EpBuffOffset;
        USBD->CEPBUFEND   = EpBuffOffset + EpBuffSzie - 1;
    }
        else
        {
        USBD->EPx[EPx].BUFSTART = EpBuffOffset;
        USBD->EPx[EPx].BUFEND         = EpBuffOffset + EpBuffSzie - 1;
               
                sg_EpConfig[EPx].EPx = EPx;                                                                //EP端点
                sg_EpConfig[EPx].EpBuffOffset = EpBuffOffset;                        //EP端点缓冲区位置(USBD缓冲区)
                sg_EpConfig[EPx].EpBuffSzie = EpBuffSzie;                                //EP端点缓冲区大小(USBD缓冲区)
    }
}

/*************************************************************************************************************************
* 函数                        :        u16 USBD_GetEpBuffSize(USBD_EPx EPx)
* 功能                        :        获取端点缓冲区大小(从硬件配置中获取)
* 参数                        :        EPx:端点号,见USBD_EPx
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-17
* 最后修改时间         :         2020-10-17
* 说明                        :       
*************************************************************************************************************************/
u16 USBD_GetEpBuffSize(USBD_EPx EPx)
{
        if(EPx > USBD_CEP) return 0;
       
        if (EPx == USBD_CEP)         //控制端点
        {
                if(USBD->CEPBUFEND == 0) return 0;
        return USBD->CEPBUFEND - USBD->CEPBUFSTART + 1;
    }
        else
        {
                if(USBD->EPx[EPx].BUFEND == 0) return 0;
        return USBD->EPx[EPx].BUFEND - USBD->EPx[EPx].BUFSTART + 1;
    }
}


使用特权

评论回复
6
晓伍|  楼主 | 2021-8-1 16:34 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        void USBD_SetEpStall(USBD_EPx EPx)
* 功能                        :        将USB端点停止状态设置为指定的端点ID。 端点将自动响应STALL令牌
* 参数                        :        EPx:端点号,见USBD_EPx;
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
void USBD_SetEpStall(USBD_EPx EPx)
{
    if (EPx == USBD_CEP)         //控制端点
        {
        USBD_SET_CEP_STATE(USB_CEPCTL_STALL);
        }
    else
        {
        USBD->EPx[EPx].RSPCTL = (USBD->EPx[EPx].RSPCTL & 0xf7) | USB_EP_RSPCTL_HALT;
    }
}

/*************************************************************************************************************************
* 函数                        :        static void USBD_SetStall(u8 EpNum)
* 功能                        :        设置指定编号端点为停止状态, 端点将自动响应STALL令牌
* 参数                        :        EpNum:端点编号
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
static void USBD_SetStall(u8 EpNum)
{
    int i;

    if (EpNum == 0)
        {
                USBD_SET_CEP_STATE(USB_CEPCTL_STALL);
        }   
    else
        {
        for (i=0; i<USBD_MAX_EP; i++)
                {
            if (((USBD->EPx.CFG & 0xf0) >> 4) == EpNum)
                        {
                USBD->EPx.RSPCTL = (USBD->EPx.RSPCTL & 0xf7) | USB_EP_RSPCTL_HALT;
            }
        }
    }
}


使用特权

评论回复
7
晓伍|  楼主 | 2021-8-1 16:34 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        void  USBD_ClearEpStall(USBD_EPx EPx)
* 功能                        :        清除USB端点停止状态
* 参数                        :        EPx:端点号,见USBD_EPx;
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
void  USBD_ClearEpStall(USBD_EPx EPx)
{
        if(EPx > USBD_EPL) return;
    USBD->EPx[EPx].RSPCTL = USB_EP_RSPCTL_TOGGLE;
}


/*************************************************************************************************************************
* 函数                        :        void USBD_ClearStall(u8 EpNum)
* 功能                        :        清除指定编号端点的停止状态,端点将返回ACK / NAK令牌
* 参数                        :        EpNum:端点编号
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
void USBD_ClearStall(u8 EpNum)
{
    int i;

    for (i = 0; i < USBD_MAX_EP; i ++)
        {
        if (((USBD->EPx.CFG & 0xf0) >> 4) == EpNum)
                {
            USBD->EPx.RSPCTL = USB_EP_RSPCTL_TOGGLE;
                        break;
        }
    }
}

/*************************************************************************************************************************
* 函数                        :        void USBD_PrepareCtrlIn(u8 *pDataBuff, u8 DataLen)
* 功能                        :        控制端点准备响应控制命令(将数据写入缓冲区,准备等待控制端口IN令牌到来后发送到主机)
* 参数                        :        pDataBuff:控制命令缓冲区;DataLen:控制命令长度
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        数据别缓存到全局缓冲区sg_USBD_Data.CtrDataBuff sg_USBD_Data.CtrDataLen
*************************************************************************************************************************/
void USBD_PrepareCtrlIn(u8 *pDataBuff, u8 DataLen)
{
        if(DataLen > 0)
        {
                if(sg_USBD_Data.CtrSendDataLen == 0)                                                                //数据发送完了
                {
                        USBD->CEPCTL |= USB_CEPCTL_FLUSH;                                                                //清除控制端口待发送数据区-该位是自清除
                }
                USBD_MemCopy((u8*)sg_USBD_Data.CtrSendDataBuff, pDataBuff, DataLen);//拷贝命令到缓冲区中
                sg_USBD_Data.CtrSendDataLen = DataLen;
                sg_USBD_Data.pCtrlInPointer = sg_USBD_Data.CtrSendDataBuff;                        //指针复位
               
                USBD_SET_CEP_INT_BIT(USBD_CEPINTSTS_INTKIF_Msk);                                        //控制端点IN令牌中断使能,等待发送数据
        }       
}



使用特权

评论回复
8
晓伍|  楼主 | 2021-8-1 16:35 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        bool USBD_CtrlIn(void)
* 功能                        :        控制端点发送数据给主机(必须在控制端点IN令牌有效时调用)
* 参数                        :        无
* 返回                        :        TRUE:有数据要发送;FALSE:无数据要发送
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :        数据别缓存到全局缓冲区sg_USBD_Data.CtrDataBuff sg_USBD_Data.CtrDataLen
                                        当要发送的数据大于64字节,会分多次发送,需要等待多个IN令牌
*************************************************************************************************************************/
bool USBD_CtrlIn(void)
{
    int volatile i;
    uint32_t volatile count;

        if(sg_USBD_Data.CtrSendDataLen == 0) return FALSE;                //没有数据要发送
    if(sg_USBD_Data.CtrSendDataLen >= CEP_BUFF_SIZE)                //数据大小超过了控制端点的缓冲区大小
        {
        for (i=0; i<(CEP_BUFF_SIZE >> 2); i++)
                {
                        USBD->CEPDAT = *(uint32_t *)sg_USBD_Data.pCtrlInPointer;
                        sg_USBD_Data.pCtrlInPointer += 4;
                }
        USBD_START_CEP_IN(CEP_BUFF_SIZE);
        sg_USBD_Data.CtrSendDataLen -= CEP_BUFF_SIZE;
    }
        else  //不足64字节的数据
        {
        for (i=0; i<(sg_USBD_Data.CtrSendDataLen >> 2); i++)//4字节整数倍
                {
                        USBD->CEPDAT = *(uint32_t *)sg_USBD_Data.pCtrlInPointer;
                        //uart_printf("%02X ", *(uint32_t *)sg_USBD_Data.pCtrlInPointer);
                        sg_USBD_Data.pCtrlInPointer += 4;
                }
        count = sg_USBD_Data.CtrSendDataLen % 4;
        for (i=0; i<count; i++)
                {
                        USBD_WriteCEP_DataByte(sg_USBD_Data.pCtrlInPointer);
                }

        USBD_START_CEP_IN(sg_USBD_Data.CtrSendDataLen);
        sg_USBD_Data.pCtrlInPointer = sg_USBD_Data.CtrSendDataBuff;        //发送数据指针复位
        sg_USBD_Data.CtrSendDataLen = 0;                                                        //待发送数据长度清零
    }
       
        return TRUE;
}

/*************************************************************************************************************************
* 函数                        :        static bool USBD_DMA_TransferData(USBD_EPx EPx, u32 BuffAddr, u16 Len, bool isShortPacket)
* 功能                        :        DAM传输数据(不会设置传输方向)
* 参数                        :        EPx:端点号,见USBD_EPx;BuffAddr:数据缓冲区地址;Len:要传输的数据长度;isShortPacket:是否为短数据包
* 返回                        :        TRUE:完成;FALSE:失败
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-16
* 最后修改时间         :         2020-10-16
* 说明                        :        需要提前设置DMA传输的端口,不要开启DMA传输完成中断,并且调用之前需要清除DMA完成中断状态
*************************************************************************************************************************/
static bool USBD_DMA_TransferData(USBD_EPx EPx, u32 BuffAddr, u16 Len, bool isShortPacket)
{
        u32 TimeOut = 0;
       
    USBD->BUSINTSTS |= USBD_BUSINTSTS_DMADONEIF_Msk;        //清除DMA完成中断
       
        USBD_SET_DMA_ADDR(BuffAddr);                                                //设置传输地址
    USBD_SET_DMA_LEN(Len);                                                                //设置传输长度
    USBD_ENABLE_DMA();                                                                        //启动DMA
        while(1)                                                                                        //等待传输完成或超时
        {
                if(USBD->BUSINTSTS & (USBD_BUSINTSTS_DMADONEIF_Msk | USBD_BUSINTSTS_RSTIF_Msk)) break;        //传输完成了,或端口重置了
                if (!USBD_IS_ATTACHED()) break;                                                                //总线未就绪
                TimeOut ++;
        }       
        if(USBD->BUSINTSTS & USBD_BUSINTSTS_DMADONEIF_Msk)
        {
                if(isShortPacket)        //短数据包,需要发送结束
                {
                        //短数据包,手动发送结束
                        USBD->EPx[EPx].RSPCTL = (USBD->EPx[EPx].RSPCTL & 0x10) | USB_EP_RSPCTL_SHORTTXEN;    // packet end
                }
                return TRUE;
        }
        else return FALSE;
}



使用特权

评论回复
9
晓伍|  楼主 | 2021-8-1 16:36 | 只看该作者

/*************************************************************************************************************************
* 函数                        :        bool USBD_ReadBulkOutPackData(USBD_EPx EPx, u8 *pData, u16 EpBuffSize)
* 功能                        :        读取一整包来自OUT的数据(需要等待缓冲区满)
* 参数                        :        EPx:EP端点选择,见USBD_EPx;pData:数据缓冲区;EpBuffSize:端点缓冲区大小
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-17
* 最后修改时间         :         2020-10-17
* 说明                        :        注意:不会判断端点缓冲区大小,等待数据包缓冲区满的过程可能出现假死,后面需要根据错误状态进行优化
                                        如果数据不够一整包也会假死,所以使用前一定要注意
*************************************************************************************************************************/
bool USBD_ReadBulkOutPackData(USBD_EPx EPx, u8 *pData, u16 EpBuffSize)
{
        if(EPx > USBD_EPL) return FALSE;
        while((USBD->EPx[EPx].INTSTS & USBD_EPINTSTS_BUFFULLIF_Msk) == 0)        //等待端点数据包缓冲区满
        {
                if (!USBD_IS_ATTACHED()) return FALSE;                                                        //总线未就绪
                if (USBD->EPx[EPx].INTSTS & USBD_EPINTSTS_STALLIF_Msk) return FALSE;        //端点失速了
        }
        USBD->EPx[EPx].INTSTS |= USBD_EPINTSTS_BUFFULLIF_Msk;                                //清除状态
        return USBD_BulkOut(EPx, pData, EpBuffSize);                                                //接收来自Bulk OUT的数据
}

/*************************************************************************************************************************
* 函数                        :        static bool USBD_BulkOut(USBD_EPx EPx, u8 *pDataBuff, u32 Len)
* 功能                        :        接收来自Bulk OUT的数据
* 参数                        :        EPx:端点号,见USBD_EPx;BuffAddr:数据缓冲区地址;Len:要传输的数据长度;
* 返回                        :        TRUE:完成;FALSE:失败
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-16
* 最后修改时间         :         2020-10-16
* 说明                        :        使用的DMA阻塞传输,地址必须4字节对齐,需要提前等待端口缓冲区有数据,再调用此函数
*************************************************************************************************************************/
bool USBD_BulkOut(USBD_EPx EPx, u8 *pDataBuff, u32 Len)
{
        u32 Loop;
    u32 i;
        u32 Addr;

        if(EPx > USBD_EPL) return FALSE;

        Addr = (u32)pDataBuff;                        //获取地址
        if(Addr % 4)
        {
                DEBUG("缓冲区地址没有4字节对齐\r\n");
                SYS_DelayMS(5000);
                return FALSE;
        }
         Loop = Len / USBD_MAX_DMA_LEN;
       
        USBD_SET_DMA_WRITE(EPx+1);                //端点地址使用端点号+1
    for (i=0; i < Loop; i++)
        {
        if(USBD_DMA_TransferData(EPx, Addr, USBD_MAX_DMA_LEN, FALSE) == FALSE) return FALSE;
                Addr += USBD_MAX_DMA_LEN;        //地址增加
    }

    Loop = Len % USBD_MAX_DMA_LEN;        //余下的
    if (Loop)
        {
        if(USBD_DMA_TransferData(EPx, Addr, Loop, FALSE) == FALSE) return FALSE;
    }
       
        return TRUE;
}


使用特权

评论回复
10
晓伍|  楼主 | 2021-8-1 16:37 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        static bool USBD_BulkIn(USBD_EPx EPx, u8 *pDataBuff, u32 Len)
* 功能                        :        写入数据到Bulk IN
* 参数                        :        EPx:端点号,见USBD_EPx;BuffAddr:数据缓冲区地址;Len:要传输的数据长度;
* 返回                        :        TRUE:完成;FALSE:失败
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-16
* 最后修改时间         :         2020-10-16
* 说明                        :        使用的DMA阻塞传输,地址必须4字节对齐
*************************************************************************************************************************/
bool USBD_BulkIn(USBD_EPx EPx, u8 *pDataBuff, u32 Len)
{
        u32 Loop;
    u32 i;
        u32 Addr;
        u32 EpMaxPackSzie = USBD_GetEpMaxPacketSize(EPx);

        if(EPx > USBD_EPL) return FALSE;

        Addr = (u32)pDataBuff;                        //获取地址
        if(Addr % 4)
        {
                DEBUG("缓冲区地址没有4字节对齐\r\n");
                SYS_DelayMS(5000);
                return FALSE;
        }

        Loop = Len / EpMaxPackSzie;
        USBD_SET_DMA_READ(EPx+1);                                                                                        //端点地址使用端点号+1
    for (i=0; i < Loop; i++)
        {
                while(1)
                {
                        if(USBD->EPx[EPx].INTSTS & USBD_EPINTSTS_BUFEMPTYIF_Msk)        //端点缓冲区为空,可以写入数据了
                        {
                                if(USBD_DMA_TransferData(EPx, Addr, EpMaxPackSzie, FALSE) == FALSE) return FALSE;
                                else
                                {
                                        break;
                                }
                        }
                }
        Addr += EpMaxPackSzie;                                                                                        //地址增加
    }

    Loop = Len % EpMaxPackSzie;                                                                                        //余下的
    if (Loop)
        {
                while(1)
                {
                        if(USBD->EPx[EPx].INTSTS & USBD_EPINTSTS_BUFEMPTYIF_Msk)        //端点缓冲区为空,可以写入数据了
                        {
                                if(USBD_DMA_TransferData(EPx, Addr, Loop, TRUE) == FALSE)
                                {
                                        return FALSE;
                                }
                                else break;
                        }
                }
               
    }
       
        return TRUE;
}



使用特权

评论回复
11
晓伍|  楼主 | 2021-8-1 16:39 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        u32 USBD_GetEpStall(USBD_EPx EPx)
* 功能                        :        获取指定端点ID的USB端点停止状态
* 参数                        :        EPx:端点号,见USBD_EPx;
* 返回                        :        停止状态
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
u32 USBD_GetEpStall(USBD_EPx EPx)
{
        if(EPx > USBD_EPL) return 0;
       
    return (USBD->EPx[EPx].RSPCTL & USB_EP_RSPCTL_HALT);
}

/*************************************************************************************************************************
* 函数                        :        u32 USBD_GetStall(u8 EpNum)
* 功能                        :        获取指定端点号的停止状态
* 参数                        :        EpNum:端点编号
* 返回                        :        停止状态
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
u32 USBD_GetStall(u8 EpNum)
{
    int i;

    for (i=0; i<USBD_MAX_EP; i++)
        {
        if (((USBD->EPx.CFG & 0xf0) >> 4) == EpNum)
                {
            return (USBD->EPx.RSPCTL & USB_EP_RSPCTL_HALT);
        }
    }
    return 0;
}

/*************************************************************************************************************************
* 函数                        :        static void USBD_SwReset(void)
* 功能                        :        USBD软复位
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        无
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-15
* 最后修改时间         :         2020-10-15
* 说明                        :        主要用于清除一些状态以及USB地址
*************************************************************************************************************************/
static void USBD_SwReset(void)
{
        sg_USBD_Data.ConfigValue = 0;
        sg_USBD_Data.DeviceAddr = 0;
        sg_USBD_Data.CtrSendDataLen = 0;
        USBD_SET_ADDR(0);
}



使用特权

评论回复
12
晓伍|  楼主 | 2021-8-1 16:40 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        void USBD_StandardRequest(void)
* 功能                        :        标准请求处理
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
static void USBD_StandardRequest(void)
{
    if (g_USBD_Setup.RequestType & 0x80)                                                                         //USBD发送数据到主机
        {
        // Device to host
        switch (g_USBD_Setup.Request)
                {
                        case USBD_GET_CONFIGURATION: //获取设备配置描述符-主机枚举设备
                        {
                                uart_printf("GET_CONFIGURATION\r\n");
                                // Return current configuration setting
                                USBD_PrepareCtrlIn((u8 *)&sg_USBD_Data.ConfigValue, 1);
                        }break;
                        case USBD_GET_DESCRIPTOR:         //用于主机获取设备的特定描述符
                        {
                                uart_printf("GET_DESCRIPTOR\r\n");
                                USBD_GetDescriptor(sg_USBD_Data.pDescData);//获取设备描述符处理
                        }break;
                        case USBD_GET_INTERFACE:         //用于获取当前某个接口描述符编号
                        {
                                uart_printf("GET_INTERFACE\r\n");
                                USBD_PrepareCtrlIn((u8 *)&sg_USBD_Data.UsbAltInterface, 1);                               
                        }break;
                        case USBD_GET_STATUS:                 //用来返回特定接收者的状态
                        {
                                u8 usbd_buff[2] = {0,0};
                               
                                uart_printf("GET_STATUS\r\n");
                                // Device
                                if (g_USBD_Setup.RequestType == 0x80)
                                {
                                        //usbd_buff[0] = 1; // 自供电
                                        usbd_buff[0] = 0; // 总线供电
                                }
                                else if (g_USBD_Setup.RequestType == 0x81)// Interface
                                {
                                        usbd_buff[0] = 0;
                                }
                               
                                else if (g_USBD_Setup.RequestType == 0x82) // Endpoint
                                {
                                        usbd_buff[0] = USBD_GetStall((g_USBD_Setup.Index & 0xF))? 1 : 0;
                                }
                                usbd_buff[1] = 0;
                                USBD_PrepareCtrlIn(usbd_buff, 2);
                        }break;
                        default: //未知请求
                        {
                                uart_printf("未知01\r\n");
                                /* Setup error, stall the device */
                                USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk);
                        }break;
        }
    } else //来自主机的请求
        {
        // Host to device
        switch (g_USBD_Setup.Request)
                {
                        case USBD_CLEAR_FEATURE: //用来清除或禁止接收者的某些特性
                        {
                                uart_printf("CLEAR_FEATURE\r\n");
                                /* Status stage */
                        }break;
                        case USBD_SET_ADDRESS: //用来给设备分配地址
                        {
                                uart_printf("SET_ADDRESS\r\n");
                                sg_USBD_Data.DeviceAddr = (u8)g_USBD_Setup.Value;

                                // DATA IN for end of setup
                                /* Status Stage */
                        }break;
                        case USBD_SET_CONFIGURATION: //用于主机指示设备采用的要求的配置
                        {
                                uart_printf("SET_CONFIGURATION\r\n");
                                sg_USBD_Data.ConfigValue = (u8)g_USBD_Setup.Value;
                                // DATA IN for end of setup
                                /* Status stage */

                        }break;
                        case USBD_SET_FEATURE:
                        {
                                uart_printf("SET_FEATURE\r\n");
                                if ((g_USBD_Setup.Value & 0x3) == USBD_FEATURE_TEST_MODE)
                                {  /* TEST_MODE*/
                                        sg_USBD_Data.TestSelector = g_USBD_Setup.Index >> 8;
                                        sg_USBD_Data.isTestMode = TRUE;
                                }
                                /* Status stage */
                        }break;
                        case USBD_SET_INTERFACE: //用于主机要求设备用某个描述符来描述接口
                        {
                                uart_printf("SET_INTERFACE\r\n");
                                sg_USBD_Data.UsbAltInterface = (u8)g_USBD_Setup.Value;
                                /* Status stage */                       
                        }break;
                        default: //其它命令,不支持
                        {
                                uart_printf("未知02\r\n");
                                /* Setup error, stall the device */
                                USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk);
                        }break;
        }
    }
}


使用特权

评论回复
13
晓伍|  楼主 | 2021-8-1 16:41 | 只看该作者

/*************************************************************************************************************************
* 函数                        :        void USBD_SetupHandle(void)
* 功能                        :        USB Setup处理
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-14
* 最后修改时间         :         2020-10-14
* 说明                        :       
*************************************************************************************************************************/
static void USBD_SetupHandle(void)
{
        //首先获取全局SETUP数据,存储到g_USBD_Setup中
        g_USBD_Setup.RequestType = USBD->SETUP1_0 & 0xFF;                        //请求类型
        g_USBD_Setup.Request = USBD->SETUP1_0>>8;                                        //本描述符的请求类型
        g_USBD_Setup.Value = USBD->SETUP3_2;                                                //参数
        g_USBD_Setup.Index = USBD->SETUP5_4;                                                //标示
        g_USBD_Setup.Length = USBD->SETUP7_6;                                                //下一阶段发送数据的长度

        uart_printf("RequestType:0x%X\t", g_USBD_Setup.RequestType);
        uart_printf("Request:0x%X\t", g_USBD_Setup.Request);
        uart_printf("Value:0x%X\t", g_USBD_Setup.Value);
        uart_printf("Index:0x%X\t", g_USBD_Setup.Index);
        uart_printf("Length:0x%X\r\n", g_USBD_Setup.Length);
       
    //处理SETUP请求
    switch (g_USBD_Setup.RequestType & 0x60)                                         //D6-D5位是请求主分类型
        {
                case USBD_REQ_STANDARD: //标准请求
                {
                        uart_printf("USBD_REQ_STANDARD\r\n");
                        USBD_StandardRequest();
        }break;
                case USBD_REQ_CLASS:         //类别请求
                {
                        uart_printf("USBD_REQ_CLASS\r\n");
                        if (sg_USBD_Data.pClassReqCallBack != NULL) sg_USBD_Data.pClassReqCallBack();
                }break;
                case USBD_REQ_VENDOR:         //厂商请求
                {
                        uart_printf("USBD_REQ_VENDOR\r\n");
                        if (sg_USBD_Data.pVendorReqCallBack != NULL) sg_USBD_Data.pVendorReqCallBack();
                }break;
                default:                                 //保留的其它请求
                {
                        /* Setup error, stall the device */
                        USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk);
                }break;
    }
}



使用特权

评论回复
14
晓伍|  楼主 | 2021-8-1 16:41 | 只看该作者

/*************************************************************************************************************************
* 函数                        :        void USBD_SetupDoneHandle(void)
* 功能                        :        USB Setup安装完成处理
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-15
* 最后修改时间         :         2020-10-15
* 说明                        :       
*************************************************************************************************************************/
void USBD_SetupDoneHandle(void)
{
#define USBD_TEST_J                  0x01    //TEST J
#define USBD_TEST_K                  0x02    //TEST K
#define USBD_TEST_SE0_NAK            0x03    //TEST SE0
#define USBD_TEST_PACKET             0x04    //TEST Packet
#define USBD_TEST_FORCE_ENABLE       0x05    //TEST Force enable
       
    switch (g_USBD_Setup.Request)
        {
                case USBD_SET_ADDRESS:                 //用来给设备分配地址
                {
                        uart_printf("USBD_SET_ADDRESS %d\r\n",sg_USBD_Data.DeviceAddr);
                        USBD_SET_ADDR(sg_USBD_Data.DeviceAddr);
                }break;
                case USBD_SET_CONFIGURATION: //用于主机指示设备采用的要求的配置
                {
                        uart_printf("\r\n");
                        if (sg_USBD_Data.ConfigValue == 0)
                        {
                                int volatile i;
                                /* Reset PID DATA0 */
                                for (i=0; i<USBD_MAX_EP; i++)
                                {
                                        if (USBD->EPx.CFG & 0x1)
                                        {
                                                USBD->EPx.RSPCTL = USB_EP_RSPCTL_TOGGLE;
                                        }
                                }
                        }
                }break;
                case USBD_SET_FEATURE:                 //用来启用或激活命令接收者的某些特性
                {
                        uart_printf("USBD_SET_FEATURE\r\n");
                        if(g_USBD_Setup.Value == USBD_FEATURE_ENDPOINT_HALT)
                        {
                                USBD_SetStall(g_USBD_Setup.Index & 0xF);
                        }
                        else if (sg_USBD_Data.isTestMode == TRUE)
                        {
                                sg_USBD_Data.isTestMode = FALSE;
                                if (sg_USBD_Data.TestSelector == USBD_TEST_J)
                                        USBD->TEST = USBD_TEST_J;
                                else if (sg_USBD_Data.TestSelector == USBD_TEST_K)
                                        USBD->TEST = USBD_TEST_K;
                                else if (sg_USBD_Data.TestSelector == USBD_TEST_SE0_NAK)
                                        USBD->TEST = USBD_TEST_SE0_NAK;
                                else if (sg_USBD_Data.TestSelector == USBD_TEST_PACKET)
                                        USBD->TEST = USBD_TEST_PACKET;
                                else if (sg_USBD_Data.TestSelector == USBD_TEST_FORCE_ENABLE)
                                        USBD->TEST = USBD_TEST_FORCE_ENABLE;
                        }
                }break;
                case USBD_CLEAR_FEATURE:        //用来清除或禁止接收者的某些特性
                {
                        uart_printf("USBD_CLEAR_FEATURE\r\n");
                        if(g_USBD_Setup.Value == USBD_FEATURE_ENDPOINT_HALT)
                        {
                                USBD_ClearStall(g_USBD_Setup.Index & 0xF);
                        }                               
                }break;
                default: break;
    }
}


使用特权

评论回复
15
晓伍|  楼主 | 2021-8-1 16:42 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        static __inline void USBD_BUS_IRQHandler(void)
* 功能                        :        USBD 总线中断处理
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-15
* 最后修改时间         :         2020-10-15
* 说明                        :       
*************************************************************************************************************************/
static __inline void USBD_BUS_IRQHandler(void)
{
        static vu32 BusIrq;
        static vu8 i;
       
        BusIrq = USBD->BUSINTSTS & USBD->BUSINTEN;                                        //获取总线中断
               
        if (BusIrq & USBD_BUSINTSTS_RSTIF_Msk)                                                 //USB端口重置
        {
               
                uart_printf("===USB端口重置\r\n");
                USBD_SwReset();
                USBD_ResetDMA();                                                                                //复位DMA
       
                for(i = 0;i < USBD_MAX_EP;i ++)
                {
                        if(sg_EpConfig.InitId == USBD_EP_INIT_ID)                //对应端点使能了,则清除数据
                        {
                                USBD->EPx.RSPCTL = USBD_EPRSPCTL_FLUSH_Msk;
                                USBD_SetEpConfig(&sg_EpConfig);                                //USB连接成功了,需要重置端口,对所有的需要使用的EP进行重新配置
                        }
                }
        }  
        else if(BusIrq & USBD_BUSINTSTS_RESUMEIF_Msk)                                //设备从挂起状态恢复
        {
               
        }
        else if(BusIrq & USBD_BUSINTSTS_SUSPENDIF_Msk)                                //总线被挂起暂停了
        {
                //USBD->OPER |= USBD_OPER_RESUMEEN_Msk;                                        //唤醒设备,不要挂起
        }
       
        //其它总线中断进行处理
        if(BusIrq && sg_USBD_Data.pUSBD_BusIRQHandlerCallBack != NULL)
        {
                sg_USBD_Data.pUSBD_BusIRQHandlerCallBack(BusIrq);                //USB总线中断处理-由于端口重置已经处理过,此处不再处理端口重置中断
        }
        USBD->BUSINTSTS = BusIrq;                                                                        //清除总线中断-总中断貌似不需要写1清除
}


使用特权

评论回复
16
晓伍|  楼主 | 2021-8-1 16:43 | 只看该作者
/*************************************************************************************************************************
* 函数                        :        static __inline void USBD_CEP_IRQHandler(void)
* 功能                        :        USBD 控制端点中断处理
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-15
* 最后修改时间         :         2020-10-15
* 说明                        :        控制端点优先处理 SETUP中断进行USB安装并开启完成中断,然后处理IN令牌中断,在IN令牌中断中发送数据,并开启发送完成中断
                                        发送完成中断中检查是否有数据要发送,没有就关闭IN中断,在完成中断中处理完成事件,并关闭完成中断
*************************************************************************************************************************/
static __inline void USBD_CEP_IRQHandler(void)
{
        static vu32 CeIrq;
        static vu16 i;
       
        CeIrq = USBD->CEPINTSTS & USBD->CEPINTEN;               
        if(CeIrq & USBD_CEPINTSTS_SETUPPKIF_Msk)                                        //SETUP处理
        {
                USBD_SetupHandle();                                                                                //SETUP相关请求处理=主机初始化设备,获取设备相关信息
                //uart_printf("->USBD->CEPCTL:0x%X\r\n", USBD->CEPCTL);
                if(sg_USBD_Data.CtrSendDataLen == 0)                                        //没有数据要发送,则清除NAK状态
                {
                        USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR);
                }
                USBD_SET_CEP_INT_BIT(USBD_CEPINTSTS_STSDONEIF_Msk);                //开启端点安装状态完成中断
        }
        //控制端点IN令牌可能会与发送完成中断一起来,这个时候要求没有发送完成中断的时候才响应IN令牌
        else if((CeIrq & USBD_CEPINTSTS_INTKIF_Msk)&& ((CeIrq & USBD_CEPINTSTS_TXPKIF_Pos)==0)
                && (USBD_CtrlIn() == TRUE))                                                                //控制端点IN令牌中断,可以响应数据给主机了
        {
                USBD_SET_CEP_INT_BIT(USBD_CEPINTSTS_TXPKIF_Msk);                //有数据要发送,开启控制端点数据发送完成中断
        }
        else if(CeIrq & USBD_CEPINTSTS_TXPKIF_Msk)                                        //控制端点数据包发送完成中断-一次数据包发送完成
        {
                if(sg_USBD_Data.CtrSendDataLen == 0)                                        //后续没有数据要发送了,关闭IN令牌中断
                {
                        USBD_CLEAR_CEP_INT_BIT(USBD_CEPINTSTS_INTKIF_Msk);        //关闭IN令牌中断
                }
                USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR);                                        //数据发送完成了,清除NAK状态
                USBD_CLEAR_CEP_INT_BIT(USBD_CEPINTSTS_TXPKIF_Msk);                //关闭端点数据发送完成中断
        }
        else if(CeIrq & USBD_CEPINTSTS_STSDONEIF_Msk)                                 //数据端口完成中断,更新状态
        {
                USBD_SetupDoneHandle();
                USBD_CLEAR_CEP_INT_BIT(USBD_CEPINTSTS_STSDONEIF_Msk);        //清除端点安装状态完成中断
        }

        if(sg_USBD_Data.pUSBD_cEpIRQHandlerCallBack) sg_USBD_Data.pUSBD_cEpIRQHandlerCallBack(CeIrq);                //控制端点中断回调
        USBD->CEPINTSTS = CeIrq;                                                                        //清除中断
}



使用特权

评论回复
17
晓伍|  楼主 | 2021-8-1 16:44 | 只看该作者

/*************************************************************************************************************************
* 函数                        :        static __inline void USBD_EPx_IRQHandler(USBD_EPx EPx)
* 功能                        :        USBD 端点中断处理
* 参数                        :        EPx:端点号,见USBD_EPx
* 返回                        :        无
* 依赖                        :        底层
* 作者                        :        cp1300@139.com
* 时间                        :        2020-10-15
* 最后修改时间         :         2020-10-15
* 说明                        :       
*************************************************************************************************************************/
static __inline void USBD_EPx_IRQHandler(USBD_EPx EPx)
{
        static vu32 EpIrq;
       
        EpIrq = USBD->EPx[EPx].INTSTS & USBD->EPx[EPx].INTEN;
       
        if(sg_EpConfig[EPx].EpIRQHandlerCallBack)
        {
                sg_EpConfig[EPx].EpIRQHandlerCallBack(EPx, EpIrq);                //数据端点中断处理
        }
        USBD->EPx[EPx].INTSTS = EpIrq;                                                                //清除中断
}



//中断服务程序
static void USBD_IRQHandler(void)
{
        static vu32 Irq;
        static vu32 i;
        static vu32 temp;
       
        Irq = USBD->GINTSTS & USBD->GINTEN;                                                        //获取总的中断状态
        if (Irq == 0)    return;

        //uart_printf("INT:0x%X\t BUS:0x%X\t CEP:0x%X\r\n", USBD->GINTSTS & USBD->GINTEN, USBD->BUSINTSTS & USBD->BUSINTEN, USBD->CEPINTSTS & USBD->CEPINTEN);
       
       
        //总线中断======================================================================================================================================
        if(Irq & USBD_GINTSTS_USBIF_Msk)                                                        //USB中断
        {
                USBD_BUS_IRQHandler();                                                                        //BUS中断处理
        }
        //控制端点中断======================================================================================================================================
        if(Irq & USBD_GINTSTS_CEPIF_Msk)                                                        //控制端点中断
        {
                USBD_CEP_IRQHandler();                                                                        //控制端点中断处理
        }
        //其它数据端点中断处理
        temp = Irq >> 2;
        for(i = 0;i < USBD_MAX_EP;i ++)
        {
                if(temp && (temp&0x01))                                                                        //指定的端点有中断
                {
                        USBD_EPx_IRQHandler((USBD_EPx)i);                                        //端点中断处理
                }
                temp >>= 1;
        }
        USBD->GINTSTS = Irq;                                                                                //清除总中断
}


使用特权

评论回复
18
晓伍|  楼主 | 2021-8-1 16:44 | 只看该作者
//USBD.h

/*************************************************************************************************************
* 文件名:                        usbd.h
* 功能:                        NUC970 USB设备相关驱动
* 作者:                        cp1300@139.com
* 创建时间:                2020-10-12
* 最后修改时间:        2020-10-12
* 详细:                       
*************************************************************************************************************/
#ifndef _USB_D_
#define _USB_D_
#include "nuc970_system.h"
#include "typedef.h"

#define USBD_MAX_EP   12                //端点数量


//端点通道定义
typedef enum
{
        USBD_EPA        =        0,                //USB端点A
        USBD_EPB        =        1,
        USBD_EPC        =        2,
        USBD_EPD        =        3,
        USBD_EPE        =        4,
        USBD_EPF        =        5,
        USBD_EPG        =        6,
        USBD_EPH        =        7,
        USBD_EPI        =        8,
        USBD_EPJ        =        9,
        USBD_EPK        =        10,
        USBD_EPL        =        11,
        USBD_CEP        =        12,                //保留的控制端点
        USBD_INVALID_EP = 0xff,        //无效的EP
}USBD_EPx;




//USBD所需全局变量定义==必须4字节对齐
//#pragma pack(4)
EPx读取数据相关信息
//typedef struct
//{
//        volatile u16 ReadDataCount;                                                                                        //已经读取的数据数量
//        volatile u16 DataBuffSize;                                                                                        //缓冲区大小
//        volatile u8 *pReadDataBuff;                                                                                        //读取的数据缓冲区
//        volatile bool isNewData;                                                                                        //新数据标志
//}USBD_EP_READ_DATA;
//#pragma pack()

typedef void (*USBD_IRQHandlerType)(u32 Status);                                                //中断服务程序定义
typedef void (*USBD_EPxIRQHandlerType)(USBD_EPx EPx, u32 Status);                //数据端口中断服务程序定义
typedef void (*USBD_CLASS_REQ)(void);                                                                        //类别请求回调处理函数定义
typedef void (*USBD_VENDOR_REQ)(void);                                                                         //厂商请求回调处理函数定义

//端点类型定义
typedef enum
{
        USBD_EP_TYPE_BULK        =        1,        //块传输
        USBD_EP_TYPE_INT        =        2,        //中断
        USBD_EP_TYPE_ISO        =        3,        //同步
}USBD_EP_TYPE;

//端点方向设置
typedef enum
{
        USBD_EP_OUTPUT                =        0,        //主机输出
        USBD_EP_INPUT                =        1,        //主机输入
}USBD_EP_DIR;


//USB请求定义 USBD_SETUP_TYPE.Request 的值
typedef enum
{
        USBD_GET_STATUS          =        0x00,        //用来返回特定接收者的状态
        USBD_CLEAR_FEATURE       =        0x01,        //用来清除或禁止接收者的某些特性
        USBD_SET_FEATURE         =        0x03,        //用来启用或激活命令接收者的某些特性
        USBD_SET_ADDRESS         =        0x05,        //用来给设备分配地址
        USBD_GET_DESCRIPTOR      =        0x06,        //用于主机获取设备的特定描述符
        USBD_SET_DESCRIPTOR      =        0x07,        //修改设备中有关的描述符,或者增加新的描述符
        USBD_GET_CONFIGURATION   =        0x08,        //用于主机获取设备当前设备的配置值(注同上面的不同)
        USBD_SET_CONFIGURATION   =        0x09,        //用于主机指示设备采用的要求的配置
        USBD_GET_INTERFACE       =        0x0A,        //用于获取当前某个接口描述符编号
        USBD_SET_INTERFACE       =        0x0B,        //用于主机要求设备用某个描述符来描述接口
        USBD_SYNC_FRAME          =        0x0C,        //用于设备设置和报告一个端点的同步帧
}USBD_REQUEST_TYPE;


//USB SETUP请求数据结构体
typedef struct
{
        //最高位BIT8:0:数据由主控发送到设备;1:数据由设备发送到主控
        //D6-D5位是请求主分类型
        //D4-D0位是表求接收这个包的接口
        u8 RequestType;                        //请求类型,
        u8 Request;                                //本描述符的请求类型
        u16 Value;                                //参数
        u16 Index;                                //标示
        u16 Length;                                //下一阶段发送数据的长度       
}USBD_SETUP_TYPE;
extern USBD_SETUP_TYPE g_USBD_Setup;

//USB设备描述符集合
typedef struct
{
        const u8 *DeveceDescripArray;           //设备描述符
    const u8 *ConfigDescripArray;                 //配置描述符
    const u8 **StringDescripPoint;                //USB字符串描述符指针的指针
    const u8 *QualifierDescripArray;        //限定描述符
    const u8 *OtherConfigDescripArray;            //其他速度配置描述符
    const u8 **HidReportDescripPoint;             //HID报告描述符的指针
    const u32 *HidReportSize;                            //HID报告描述符大小的指针
}USBD_DESCRIPTOR;

//控制端点buff
#define CEP_BUFF_OFFSET                    0                //控制端点buff缓冲区偏移
#define CEP_BUFF_SIZE                        64                //控制端点缓冲区大小

//USB描述符长度
#define USBD_LEN_DEVICE          18
#define USBD_LEN_QUALIFIER       10
#define USBD_LEN_CONFIG          9
#define USBD_LEN_INTERFACE       9
#define USBD_LEN_ENDPOINT        7
#define USBD_LEN_OTG             5
#define USBD_LEN_HID             9

//USB描述符类型
#define USBD_DESC_DEVICE         0x01                //设备描述符(Device Descriptor)
#define USBD_DESC_CONFIG         0x02                //配置描述符(Configuration Descriptor)
#define USBD_DESC_STRING         0x03                //字符串描述符(String Descriptor)
#define USBD_DESC_INTERFACE      0x04                //接口描述符(Interface Descriptor)
#define USBD_DESC_ENDPOINT       0x05                //端点描述符(EndPont Descriptor)
#define USBD_DESC_QUALIFIER      0x06
#define USBD_DESC_OTHERSPEED     0x07
#define USBD_DESC_IFPOWER        0x08
#define USBD_DESC_OTG            0x09

//USB HID描述符类型
#define USBD_DESC_HID            0x21                //获取HID描述符
#define USBD_DESC_HID_RPT        0x22                //获取HID报告描述符

//USB SETUP主请求类型
#define USBD_REQ_STANDARD        0x00        //标准请求
#define USBD_REQ_CLASS           0x20        //类别请求
#define USBD_REQ_VENDOR          0x40        //厂商请求

//定义的数据存储器类型的请求
#define USBD_BULK_ONLY_MASS_STORAGE_RESET    0xFF
#define USBD_GET_MAX_LUN                     0xFE        //获取存储器逻辑磁盘数量

//USB功能选择器
#define USBD_FEATURE_ENDPOINT_HALT           0x00
#define USBD_FEATURE_DEVICE_REMOTE_WAKEUP    0x01
#define USBD_FEATURE_TEST_MODE               0x02



/********************* Bit definition of CEPCTL register **********************/
#define USB_CEPCTL_NAKCLR               ((uint32_t)0x00000000)      //NAK clear
#define USB_CEPCTL_STALL                ((uint32_t)0x00000002)      //Stall
#define USB_CEPCTL_ZEROLEN              ((uint32_t)0x00000004)      //Zero length packet
#define USB_CEPCTL_FLUSH                ((uint32_t)0x00000008)      //CEP flush

/********************* Bit definition of EPxRSPCTL register **********************/
#define USB_EP_RSPCTL_FLUSH             ((uint32_t)0x00000001)      //Buffer Flush
#define USB_EP_RSPCTL_MODE_AUTO         ((uint32_t)0x00000000)      //Auto-Validate Mode
#define USB_EP_RSPCTL_MODE_MANUAL       ((uint32_t)0x00000002)      //Manual-Validate Mode
#define USB_EP_RSPCTL_MODE_FLY          ((uint32_t)0x00000004)      //Fly Mode
#define USB_EP_RSPCTL_MODE_MASK         ((uint32_t)0x00000006)      //Mode Mask
#define USB_EP_RSPCTL_TOGGLE            ((uint32_t)0x00000008)      //Clear Toggle bit
#define USB_EP_RSPCTL_HALT              ((uint32_t)0x00000010)      //Endpoint halt
#define USB_EP_RSPCTL_ZEROLEN           ((uint32_t)0x00000020)      //Zero length packet IN
#define USB_EP_RSPCTL_SHORTTXEN         ((uint32_t)0x00000040)      //Packet end
#define USB_EP_RSPCTL_DISBUF            ((uint32_t)0x00000080)      //Disable buffer


//USBD GINTSTS GINTEN 总的USB中断状态
#define USBD_GINTSTS_USBIF_Pos           (0)                                               
#define USBD_GINTSTS_USBIF_Msk           (0x1ul << USBD_GINTSTS_USBIF_Pos)                 //USB中断状态
#define USBD_GINTSTS_CEPIF_Pos           (1)                                               
#define USBD_GINTSTS_CEPIF_Msk           (0x1ul << USBD_GINTSTS_CEPIF_Pos)                 //控制端点中断
#define USBD_GINTSTS_EPAIF_Pos           (2)                                               
#define USBD_GINTSTS_EPAIF_Msk           (0x1ul << USBD_GINTSTS_EPAIF_Pos)                 //端点A中断
#define USBD_GINTSTS_EPBIF_Pos           (3)                                               
#define USBD_GINTSTS_EPBIF_Msk           (0x1ul << USBD_GINTSTS_EPBIF_Pos)                 //端点B中断
#define USBD_GINTSTS_EPCIF_Pos           (4)                                               
#define USBD_GINTSTS_EPCIF_Msk           (0x1ul << USBD_GINTSTS_EPCIF_Pos)                 //端点C中断
#define USBD_GINTSTS_EPDIF_Pos           (5)                                               
#define USBD_GINTSTS_EPDIF_Msk           (0x1ul << USBD_GINTSTS_EPDIF_Pos)                 //端点D中断
#define USBD_GINTSTS_EPEIF_Pos           (6)                                             
#define USBD_GINTSTS_EPEIF_Msk           (0x1ul << USBD_GINTSTS_EPEIF_Pos)                 //端点E中断
#define USBD_GINTSTS_EPFIF_Pos           (7)                                               
#define USBD_GINTSTS_EPFIF_Msk           (0x1ul << USBD_GINTSTS_EPFIF_Pos)                 //端点F中断
#define USBD_GINTSTS_EPGIF_Pos           (8)                                               
#define USBD_GINTSTS_EPGIF_Msk           (0x1ul << USBD_GINTSTS_EPGIF_Pos)                 //端点G中断
#define USBD_GINTSTS_EPHIF_Pos           (9)                                               
#define USBD_GINTSTS_EPHIF_Msk           (0x1ul << USBD_GINTSTS_EPHIF_Pos)                 //端点H中断
#define USBD_GINTSTS_EPIIF_Pos           (10)                                             
#define USBD_GINTSTS_EPIIF_Msk           (0x1ul << USBD_GINTSTS_EPIIF_Pos)                 //端点I中断
#define USBD_GINTSTS_EPJIF_Pos           (11)                                             
#define USBD_GINTSTS_EPJIF_Msk           (0x1ul << USBD_GINTSTS_EPJIF_Pos)                 //端点J中断
#define USBD_GINTSTS_EPKIF_Pos           (12)                                             
#define USBD_GINTSTS_EPKIF_Msk           (0x1ul << USBD_GINTSTS_EPKIF_Pos)                 //端点K中断
#define USBD_GINTSTS_EPLIF_Pos           (13)                                             
#define USBD_GINTSTS_EPLIF_Msk           (0x1ul << USBD_GINTSTS_EPLIF_Pos)                 //端点L中断


//USBD BUSINTSTS BUSINTEN 总线中断状态
#define USBD_BUSINTSTS_SOFIF_Pos         (0)                                               
#define USBD_BUSINTSTS_SOFIF_Msk         (0x1ul << USBD_BUSINTSTS_SOFIF_Pos)               //接收到SOF中断
#define USBD_BUSINTSTS_RSTIF_Pos         (1)                                               
#define USBD_BUSINTSTS_RSTIF_Msk         (0x1ul << USBD_BUSINTSTS_RSTIF_Pos)               //USB端口重置
#define USBD_BUSINTSTS_RESUMEIF_Pos      (2)                                               
#define USBD_BUSINTSTS_RESUMEIF_Msk      (0x1ul << USBD_BUSINTSTS_RESUMEIF_Pos)            //发生设备恢复
#define USBD_BUSINTSTS_SUSPENDIF_Pos     (3)                                               
#define USBD_BUSINTSTS_SUSPENDIF_Msk     (0x1ul << USBD_BUSINTSTS_SUSPENDIF_Pos)           //暂停请求
#define USBD_BUSINTSTS_HISPDIF_Pos       (4)                                               
#define USBD_BUSINTSTS_HISPDIF_Msk       (0x1ul << USBD_BUSINTSTS_HISPDIF_Pos)             //设备已设置为高速
#define USBD_BUSINTSTS_DMADONEIF_Pos     (5)                                               
#define USBD_BUSINTSTS_DMADONEIF_Msk     (0x1ul << USBD_BUSINTSTS_DMADONEIF_Pos)           //DMA完成中断
#define USBD_BUSINTSTS_PHYCLKVLDIF_Pos   (6)                                               
#define USBD_BUSINTSTS_PHYCLKVLDIF_Msk   (0x1ul << USBD_BUSINTSTS_PHYCLKVLDIF_Pos)         //可从收发器获得可用时钟
#define USBD_BUSINTSTS_VBUSDETIF_Pos     (8)                                               
#define USBD_BUSINTSTS_VBUSDETIF_Msk     (0x1ul << USBD_BUSINTSTS_VBUSDETIF_Pos)           //VBUS已插入


//USBD_CEPINTEN CEPINTSTS USBD控制端点中断
#define USBD_CEPINTSTS_SETUPTKIF_Pos     (0)                                               
#define USBD_CEPINTSTS_SETUPTKIF_Msk     (0x1ul << USBD_CEPINTSTS_SETUPTKIF_Pos)           //控制端点SETUP令牌中断
#define USBD_CEPINTSTS_SETUPPKIF_Pos     (1)                                               
#define USBD_CEPINTSTS_SETUPPKIF_Msk     (0x1ul << USBD_CEPINTSTS_SETUPPKIF_Pos)           //控制端点SETUP数据包中断
#define USBD_CEPINTSTS_OUTTKIF_Pos       (2)                                               
#define USBD_CEPINTSTS_OUTTKIF_Msk       (0x1ul << USBD_CEPINTSTS_OUTTKIF_Pos)             //控制端点OUT令牌中断
#define USBD_CEPINTSTS_INTKIF_Pos        (3)                                             
#define USBD_CEPINTSTS_INTKIF_Msk        (0x1ul << USBD_CEPINTSTS_INTKIF_Pos)              //控制端点IN令牌中断
#define USBD_CEPINTSTS_PINGIF_Pos        (4)                                             
#define USBD_CEPINTSTS_PINGIF_Msk        (0x1ul << USBD_CEPINTSTS_PINGIF_Pos)              //控制端点ping令牌中断
#define USBD_CEPINTSTS_TXPKIF_Pos        (5)                                         
#define USBD_CEPINTSTS_TXPKIF_Msk        (0x1ul << USBD_CEPINTSTS_TXPKIF_Pos)              //控制端点数据发送中断
#define USBD_CEPINTSTS_RXPKIF_Pos        (6)                                             
#define USBD_CEPINTSTS_RXPKIF_Msk        (0x1ul << USBD_CEPINTSTS_RXPKIF_Pos)              //控制端点数据接收中断
#define USBD_CEPINTSTS_NAKIF_Pos         (7)                                             
#define USBD_CEPINTSTS_NAKIF_Msk         (0x1ul << USBD_CEPINTSTS_NAKIF_Pos)               //控制端点NAK发送中断
#define USBD_CEPINTSTS_STALLIF_Pos       (8)                                               
#define USBD_CEPINTSTS_STALLIF_Msk       (0x1ul << USBD_CEPINTSTS_STALLIF_Pos)             //控制端点STALL发送中断
#define USBD_CEPINTSTS_ERRIF_Pos         (9)                                          
#define USBD_CEPINTSTS_ERRIF_Msk         (0x1ul << USBD_CEPINTSTS_ERRIF_Pos)               //控制端点USB错误中断
#define USBD_CEPINTSTS_STSDONEIF_Pos     (10)                                             
#define USBD_CEPINTSTS_STSDONEIF_Msk     (0x1ul << USBD_CEPINTSTS_STSDONEIF_Pos)           //控制端点状态完成中断
#define USBD_CEPINTSTS_BUFFULLIF_Pos     (11)                                          
#define USBD_CEPINTSTS_BUFFULLIF_Msk     (0x1ul << USBD_CEPINTSTS_BUFFULLIF_Pos)           //控制端点缓冲区满中断
#define USBD_CEPINTSTS_BUFEMPTYIF_Pos    (12)                                             
#define USBD_CEPINTSTS_BUFEMPTYIF_Msk    (0x1ul << USBD_CEPINTSTS_BUFEMPTYIF_Pos)          //控制端点缓冲区空中断




//USBD_OPER USBD操作命令
#define USBD_OPER_RESUMEEN_Pos           (0)                                               
#define USBD_OPER_RESUMEEN_Msk           (0x1ul << USBD_OPER_RESUMEEN_Pos)                 //如果启用了设备远程唤醒,将向主机启动一个恢复序列(发送后自动清除)。
#define USBD_OPER_HISPDEN_Pos            (1)                                               
#define USBD_OPER_HISPDEN_Msk            (0x1ul << USBD_OPER_HISPDEN_Pos)                  //USB设备控制器在复位协议期间启动线性调频序列
#define USBD_OPER_CURSPD_Pos             (2)                                               
#define USBD_OPER_CURSPD_Msk             (0x1ul << USBD_OPER_CURSPD_Pos)                   //USB设备控制器设置为“高速”


//USBD_CEPCTL USBD控制端点控制
#define USBD_CEPCTL_NAKCLR_Pos           (0)                                               
#define USBD_CEPCTL_NAKCLR_Msk           (0x1ul << USBD_CEPCTL_NAKCLR_Pos)                 //置1后,每当设置令牌被设置时,本地CPU可以花费自己的时间来完成其它工作,然后清除此位
#define USBD_CEPCTL_STALLEN_Pos          (1)                                               
#define USBD_CEPCTL_STALLEN_Msk          (0x1ul << USBD_CEPCTL_STALLEN_Pos)                //发送停止握手之后,控制端点响应任何输入或输出令牌
#define USBD_CEPCTL_ZEROLEN_Pos          (2)                                               
#define USBD_CEPCTL_ZEROLEN_Msk          (0x1ul << USBD_CEPCTL_ZEROLEN_Pos)                //USB设备控制器可以在数据阶段将零长度的数据包发送到主机到IN令牌
#define USBD_CEPCTL_FLUSH_Pos            (3)                                               
#define USBD_CEPCTL_FLUSH_Msk            (0x1ul << USBD_CEPCTL_FLUSH_Pos)                  //清除数据包缓冲区(此位自动复位)

//USBD_DMACTL  DMA控制
#define USBD_DMACTL_EPNUM_Pos            (0)                                               
#define USBD_DMACTL_EPNUM_Msk            (0xful << USBD_DMACTL_EPNUM_Pos)                  //DMA端点地址位
#define USBD_DMACTL_DMARD_Pos            (4)                                               
#define USBD_DMACTL_DMARD_Msk            (0x1ul << USBD_DMACTL_DMARD_Pos)                  //DMA读写操作
#define USBD_DMACTL_DMAEN_Pos            (5)                                               
#define USBD_DMACTL_DMAEN_Msk            (0x1ul << USBD_DMACTL_DMAEN_Pos)                  //启用DMA
#define USBD_DMACTL_SGEN_Pos             (6)                                               
#define USBD_DMACTL_SGEN_Msk             (0x1ul << USBD_DMACTL_SGEN_Pos)                   //分散收集功能
#define USBD_DMACTL_DMARST_Pos           (7)                                               
#define USBD_DMACTL_DMARST_Msk           (0x1ul << USBD_DMACTL_DMARST_Pos)                 //重置DMA状态机


//USBD_EPxINTSTS EPxINTEN 端点中断状态
#define USBD_EPINTSTS_BUFFULLIF_Pos      (0)                                               
#define USBD_EPINTSTS_BUFFULLIF_Msk      (0x1ul << USBD_EPINTSTS_BUFFULLIF_Pos)            //端点数据包缓冲区已满
#define USBD_EPINTSTS_BUFEMPTYIF_Pos     (1)                                               
#define USBD_EPINTSTS_BUFEMPTYIF_Msk     (0x1ul << USBD_EPINTSTS_BUFEMPTYIF_Pos)           //端点缓冲区为空
#define USBD_EPINTSTS_SHORTTXIF_Pos      (2)                                               
#define USBD_EPINTSTS_SHORTTXIF_Msk      (0x1ul << USBD_EPINTSTS_SHORTTXIF_Pos)            //端点最后一个数据包的长度小于最大数据包大小(EPMPS)
#define USBD_EPINTSTS_TXPKIF_Pos         (3)                                               
#define USBD_EPINTSTS_TXPKIF_Msk         (0x1ul << USBD_EPINTSTS_TXPKIF_Pos)               //端点数据发送完成中断
#define USBD_EPINTSTS_RXPKIF_Pos         (4)                                               
#define USBD_EPINTSTS_RXPKIF_Msk         (0x1ul << USBD_EPINTSTS_RXPKIF_Pos)               //端点从主机接收到数据包
#define USBD_EPINTSTS_OUTTKIF_Pos        (5)                                               
#define USBD_EPINTSTS_OUTTKIF_Msk        (0x1ul << USBD_EPINTSTS_OUTTKIF_Pos)              //端点已从主机收到数据输出令牌。 此位也由PING令牌(仅在高速中)设置
#define USBD_EPINTSTS_INTKIF_Pos         (6)                                               
#define USBD_EPINTSTS_INTKIF_Msk         (0x1ul << USBD_EPINTSTS_INTKIF_Pos)               //端点已从主机收到数据输入令牌
#define USBD_EPINTSTS_PINGIF_Pos         (7)                                               
#define USBD_EPINTSTS_PINGIF_Msk         (0x1ul << USBD_EPINTSTS_PINGIF_Pos)               //端点已从主机收到数据PING令牌
#define USBD_EPINTSTS_NAKIF_Pos          (8)                                               
#define USBD_EPINTSTS_NAKIF_Msk          (0x1ul << USBD_EPINTSTS_NAKIF_Pos)                //端点无法提供最后一个USB IN数据包,并且通过一个NAK确认
#define USBD_EPINTSTS_STALLIF_Pos        (9)                                               
#define USBD_EPINTSTS_STALLIF_Msk        (0x1ul << USBD_EPINTSTS_STALLIF_Pos)              //端点无法接受或提供最后一个USB数据包,因为端点停滞了,并被告知失速
#define USBD_EPINTSTS_NYETIF_Pos         (10)                                             
#define USBD_EPINTSTS_NYETIF_Msk         (0x1ul << USBD_EPINTSTS_NYETIF_Pos)               //端点RAM中的可用空间不足以容纳下一个即将到来的数据包
#define USBD_EPINTSTS_ERRIF_Pos          (11)                                             
#define USBD_EPINTSTS_ERRIF_Msk          (0x1ul << USBD_EPINTSTS_ERRIF_Pos)                //端点发生了错误
#define USBD_EPINTSTS_SHORTRXIF_Pos      (12)                                             
#define USBD_EPINTSTS_SHORTRXIF_Msk      (0x1ul << USBD_EPINTSTS_SHORTRXIF_Pos)            //端点收到的批量输出短数据包(包括零长度数据包)


//USBD_EPxRSPCTL 端点控制
#define USBD_EPRSPCTL_FLUSH_Pos          (0)                                               
#define USBD_EPRSPCTL_FLUSH_Msk          (0x1ul << USBD_EPRSPCTL_FLUSH_Pos)                //端点清除数据缓冲区
#define USBD_EPRSPCTL_MODE_Pos           (1)                                               
#define USBD_EPRSPCTL_MODE_Msk           (0x3ul << USBD_EPRSPCTL_MODE_Pos)                 //端点模式控制
#define USBD_EPRSPCTL_TOGGLE_Pos         (3)                                               
#define USBD_EPRSPCTL_TOGGLE_Msk         (0x1ul << USBD_EPRSPCTL_TOGGLE_Pos)               //端点切换,清除端点数据触发位
#define USBD_EPRSPCTL_HALT_Pos           (4)                                               
#define USBD_EPRSPCTL_HALT_Msk           (0x1ul << USBD_EPRSPCTL_HALT_Pos)                 //端点停止,发送一个STALL握手作为对主机令牌的响应
#define USBD_EPRSPCTL_ZEROLEN_Pos        (5)                                               
#define USBD_EPRSPCTL_ZEROLEN_Msk        (0x1ul << USBD_EPRSPCTL_ZEROLEN_Pos)              //端点收到IN令牌后,会将零数据包发送到主机
#define USBD_EPRSPCTL_SHORTTXEN_Pos      (6)                                               
#define USBD_EPRSPCTL_SHORTTXEN_Msk      (0x1ul << USBD_EPRSPCTL_SHORTTXEN_Pos)            //端点短数据包传输使能,验证缓冲区中的任何剩余数据
#define USBD_EPRSPCTL_DISBUF_Pos         (7)                                               
#define USBD_EPRSPCTL_DISBUF_Msk         (0x1ul << USBD_EPRSPCTL_DISBUF_Pos)               //端点缓冲区禁用控制,当接收到Bulk-OUT短数据包时,禁用缓冲器

//USBD_EPxCFG 端点配置
#define USBD_EPCFG_EPEN_Pos              (0)                                               
#define USBD_EPCFG_EPEN_Msk              (0x1ul << USBD_EPCFG_EPEN_Pos)                    //端点已经启用
#define USBD_EPCFG_EPTYPE_Pos            (1)                                               
#define USBD_EPCFG_EPTYPE_Msk            (0x3ul << USBD_EPCFG_EPTYPE_Pos)                  //端点类型
#define USBD_EPCFG_EPDIR_Pos             (3)                                               
#define USBD_EPCFG_EPDIR_Msk             (0x1ul << USBD_EPCFG_EPDIR_Pos)                   //端点方向
#define USBD_EPCFG_EPNUM_Pos             (4)                                               
#define USBD_EPCFG_EPNUM_Msk             (0xful << USBD_EPCFG_EPNUM_Pos)                   //端点编号,不支持两个端点具有相同的端点号

//USBD_PHYCTL USB PHY控制
#define USBD_PHYCTL_DPPUEN_Pos           (8)                                               
#define USBD_PHYCTL_DPPUEN_Msk           (0x1ul << USBD_PHYCTL_DPPUEN_Pos)                 //使能D +上拉电阻
#define USBD_PHYCTL_PHYEN_Pos            (9)                                               
#define USBD_PHYCTL_PHYEN_Msk            (0x1ul << USBD_PHYCTL_PHYEN_Pos)                  //USB PHY未挂起
#define USBD_PHYCTL_WKEN_Pos             (24)                                             
#define USBD_PHYCTL_WKEN_Msk             (0x1ul << USBD_PHYCTL_WKEN_Pos)                   //唤醒功能已启用
#define USBD_PHYCTL_VBUSDET_Pos          (31)                                             
#define USBD_PHYCTL_VBUSDET_Msk          (0x1ul << USBD_PHYCTL_VBUSDET_Pos)                //检测到VBUS

//相关操作
#define USBD_ENABLE_USB()               ((u32)(USBD->PHYCTL |= (USBD_PHYCTL_PHYEN_Msk|USBD_PHYCTL_DPPUEN_Msk)))         //使能 USB
#define USBD_DISABLE_USB()              ((u32)(USBD->PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk))                                                         //禁用 USB
#define USBD_ENABLE_PHY()               ((u32)(USBD->PHYCTL |= USBD_PHYCTL_PHYEN_Msk))                                                                 //使能硬件 PHY
#define USBD_DISABLE_PHY()              ((u32)(USBD->PHYCTL &= ~USBD_PHYCTL_PHYEN_Msk))                                                         //禁用硬件 PHY
#define USBD_SET_OPER(x)                                (USBD->OPER = (x))                                                                                                                        //设置OPER操作命令
#define USBD_SET_SE0()                  ((u32)(USBD->PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk))                                                         //Enable SE0, 强制USB PHY收发器驱动SE0
#define USBD_CLR_SE0()                  ((u32)(USBD->PHYCTL |= USBD_PHYCTL_DPPUEN_Msk))                                                         //Disable SE0
#define USBD_SET_ADDR(addr)             (USBD->FADDR = (addr))                                                                                                                 //设置USB功能地址
#define USBD_GET_ADDR()                 ((u32)(USBD->FADDR))                                                                                                                 //获取USB功能地址
#define USBD_ENABLE_USB_INT(intr)       (USBD->GINTEN = (intr))                                                                                                                //设置USB相关中断
#define USBD_ENABLE_BUS_INT(intr)       (USBD->BUSINTEN = (intr))                                                                                                        //设置USB总线中断
#define USBD_GET_BUS_INT_FLAG()         (USBD->BUSINTSTS)                                                                                                                         //获取总线中断状态
#define USBD_CLR_BUS_INT_FLAG(flag)     (USBD->BUSINTSTS = flag)                                                                                                        //清除总线中断状态
#define USBD_ENABLE_CEP_INT(intr)       (USBD->CEPINTEN = (intr))                                                                                                        //设置控制端点中断
#define USBD_SET_CEP_INT_BIT(intr)                (USBD->CEPINTEN |= (intr))                                                                                                        //设置控制端点中断-只增加
#define USBD_CLEAR_CEP_INT_BIT(intr)    (USBD->CEPINTEN &= ~(intr))                                                                                                        //清除控制端点中断-只减少

#define USBD_CLR_CEP_INT_FLAG(flag)     (USBD->CEPINTSTS = flag)                                                                                                         //清除控制端点中断状态
#define USBD_SET_CEP_STATE(flag)        (USBD->CEPCTL = flag)                                                                                                                //设置控制端点控制寄存器
#define USBD_START_CEP_IN(size)         (USBD->CEPTXCNT = size)                                                                                                                //设置控制端点传输数据长度
#define USBD_ENABLE_EP_INT(ep, intr)    (USBD->EPx[ep].INTEN = (intr))                                                                                                //设置端点x的中断
#define USBD_SET_EP_INT_BIT(ep, intr)    (USBD->EPx[ep].INTEN |= (intr))                                                                                        //设置端点x的中断-只增加
#define USBD_CLEAR_EP_INT_BIT(ep, intr)  (USBD->EPx[ep].INTEN  &= ~(intr))                                                                                        //清除端点x的中断-只减少

#define USBD_GET_EP_INT_FLAG(ep)        (USBD->EPx[ep].INTSTS)                                                                                                                //获取端点x的中断状态
#define USBD_CLR_EP_INT_FLAG(ep, flag)  (USBD->EPx[ep].INTSTS = (flag))                                                                                                //清除端点x的中断状态
#define USBD_SET_DMA_LEN(len)           (USBD->DMACNT = len)                                                                                                                //设置DMA传输长度
#define USBD_SET_DMA_ADDR(addr)         (USBD->DMAADDR = addr)                                                                                                                //设置DMA传输的地址
#define USBD_SET_DMA_READ(epnum)        (USBD->DMACTL = (USBD->DMACTL & ~USBD_DMACTL_EPNUM_Msk) | USBD_DMACTL_DMARD_Msk | epnum)         //设置DMA为读取方向
#define USBD_SET_DMA_WRITE(epnum)       (USBD->DMACTL = (USBD->DMACTL & ~(USBD_DMACTL_EPNUM_Msk | USBD_DMACTL_DMARD_Msk)) | epnum)         //设置DMA为写入方向
#define USBD_ENABLE_DMA()               (USBD->DMACTL |= USBD_DMACTL_DMAEN_Msk)                                                                                                         //使能DMA传输
#define USBD_IS_ATTACHED()              ((u32)(USBD->PHYCTL & USBD_PHYCTL_VBUSDET_Msk))                                                         //检查USB连接状态
#define USBD_WriteEPx_DataByte(ep, data)         (*((vu8*)(&(USBD->EPx[ep].DAT))) = (data))                                                                //写入BYTE数据到端点x数据发送寄存器
#define USBD_ReadEPx_DataByte(ep)                         (*((vu8*)(&(USBD->EPx[ep].DAT))))                                                                                //从端点x数据接收寄存器读取BYTE数据

#define Maximum(a,b)    (a)>(b) ? (a) : (b)
#define Minimum(a,b)    (a)<(b) ? (a) : (b)

//USBD需要使用到的内存拷贝
__inline void USBD_MemCopy(uint8_t *u8Dst, uint8_t *u8Src, int32_t i32Size)
{
    while (i32Size--) *u8Dst++ = *u8Src++;
}

//获取指定EP的最大数据包大小
__inline u16 USBD_GetEpMaxPacketSize(USBD_EPx EPx)
{
        if(EPx > USBD_EPL) return 0;       
    return USBD->EPx[EPx].MPS & 0x7FF;
}


//获取指定EP的缓冲区数据大小
__inline u16 USBD_GetEpDataCount(USBD_EPx EPx)
{
        if(EPx > USBD_EPL) return 0;       
    return USBD->EPx[EPx].DATCNT & 0xffff;
}


//EP配置
typedef struct
{
        u32 InitId;                                                                        //端点是否初始化了-不要在外部修改
        USBD_EPx EPx;                                                                //EP端点-不要在外部修改
        u32 EnableIntBit;                                                        //使能的中断
        u8 EpNum;                                                                        //EP端点编号-不要在外部修改
        u16 EpBuffOffset;                                                        //EP端点缓冲区位置(USBD缓冲区)
        u16 EpBuffSzie;                                                                //EP端点缓冲区大小(USBD缓冲区)
        u16 EpUSB20_MaxPackSize;                                        //USB2.0对应的最大数据包大小
        u16 EpMaxPackSzie;                                                        //EP端点最大数据包大小-实际数据包大小,如果是USB1.1则固定为64字节,否则等于EpUSB20_MaxPackSize
        USBD_EP_TYPE EpType;                                                //EP端点类型
        USBD_EP_DIR EpDir;                                                        //EP端点方向
        USBD_EPxIRQHandlerType EpIRQHandlerCallBack;//EP端点中断回调函数
}USBD_EP_CONFIG;





//初始化USBD
void USBD_Init(void);
void USBD_InterfaceConfig(USBD_IRQHandlerType pBusIRQCallBack, USBD_IRQHandlerType pCEpIRQCallBack, USBD_CLASS_REQ pClassReqCallBack,
        USBD_VENDOR_REQ pVendorReqCallBack, const USBD_DESCRIPTOR *pDescData);//USBD所需接口配置
void USBD_Start(void);                                                                                        //USBD启动
bool USBD_GetIdleEp(USBD_EPx *pEPx);                                                        //获取一个空闲的EP通道
void USBD_ResetDMA(void);                                                                                //复位DMA
USBD_EP_CONFIG *USBD_GetEpConfigPointer(USBD_EPx EPx);                        //获取一个端点的配置指针,可以对端点进行配置
void USBD_SetEpConfigData(USBD_EPx EPx,USBD_EP_TYPE EpType, USBD_EP_DIR EpDir, u32 EnableIntBit, u16 EpBuffOffset, u16 EpBuffSzie, u16 EpMaxPackSzie,
        USBD_EPxIRQHandlerType pCallBack);//设置一数据个端点的配置数据
void USBD_PrepareCtrlIn(u8 *pDataBuff, u8 DataLen);                                //控制端点准备响应控制命令(将数据写入缓冲区,准备等待控制端口IN令牌到来后发送到主机)
bool USBD_CtrlIn(void);                                                                                        //控制端点发送数据给主机(必须在控制端点IN令牌有效时调用)
bool USBD_BulkOut(USBD_EPx EPx, u8 *pDataBuff, u32 Len);                //接收来自Bulk OUT的数据
bool USBD_BulkIn(USBD_EPx EPx, u8 *pDataBuff, u32 Len);                        //写入数据到Bulk IN
bool USBD_ReadBulkOutPackData(USBD_EPx EPx, u8 *pData, u16 EpBuffSize);//读取一整包来自OUT的数据(需要等待缓冲区满)
u16 USBD_GetEpBuffSize(USBD_EPx EPx);                                                        //获取端点缓冲区大小(从硬件配置中获取)


void USBD_SetEpBuffAddr(USBD_EPx EPx, u32 u32Base, u32 u32Len);        //设置端点缓冲区地址
void USBD_EpConfig(USBD_EPx EPx, u8 EpNum, USBD_EP_TYPE EpType, USBD_EP_DIR EpDir);                        //端点配置
void USBD_SetEpStall(USBD_EPx EPx);                                                                //将USB端点停止状态设置为指定的端点ID。 端点将自动响应STALL令牌
void USBD_ClearEpStall(USBD_EPx EPx);                                                        //清除USB端点停止状态
u32 USBD_GetEpStall(USBD_EPx EPx);                                                                //获取指定端点ID的USB端点停顿状态
void USBD_SwReset(void);                                                                                //软复位
u16 USBD_ReadEPxOutData(USBD_EPx EPx, u8 *pData);                                //从EPx的OUT缓冲区中读取数据


void USBD_ClearStall(u8 EpNum);                                                                        //清除指定编号端点的停止状态,端点将返回ACK / NAK令牌
u32 USBD_GetStall(u8 EpNum);                                                                        //获取指定端点号的停止状态


#endif //_USB_D_


使用特权

评论回复
19
晓伍|  楼主 | 2021-8-1 16:45 | 只看该作者
测试代码,先只测试USBD底层初始化,已经EP端点初始化,后面将会实现虚拟U盘功能。

USBD_EPx g_USBD_MassStorageIN_EP = USBD_INVALID_EP;                                //host in ep 需要发送给主机的数据端点
USBD_EPx g_USBD_MassStorageOUT_EP = USBD_INVALID_EP;                        //host out ep 来自主机的数据



#define USBD_MASS_STORAGE_PACK_SIZE                        64                                        //最大数据包定义bluk大小定义
#define USBD_MASS_STORAGE_EP_BUFF_SIZE                512                                        //端点缓冲区大小定义


//USB从机线程
void TaskUSBD(void *pdata)       
{
        OS_ERR err;
        CPU_TS USBD_TaskTs;
       
        USBD_Init();        //初始化USBD
        USBD_InterfaceConfig(NULL, NULL, USBD_ClassRequest, NULL, &cg_USBD_Descriptor);//USBD所需接口配置
       
        USBD_GetIdleEp(&g_USBD_MassStorageIN_EP);                                                        //获取一个空闲的EP通道 IN
        USBD_SetEpConfigData(        g_USBD_MassStorageIN_EP,                                         //IN
                                                        USBD_EP_TYPE_BULK,                                                         //BULK
                                                        USBD_EP_INPUT,
                                                        0,
                                                        CEP_BUFF_OFFSET+CEP_BUFF_SIZE, USBD_MASS_STORAGE_EP_BUFF_SIZE, USBD_MASS_STORAGE_PACK_SIZE, NULL);                                                                //设置一数据个端点的配置数据
       
        USBD_GetIdleEp(&g_USBD_MassStorageOUT_EP);                                                        //获取一个空闲的EP通道 OUT
        USBD_SetEpConfigData(        g_USBD_MassStorageOUT_EP,                                         //OUT
                                                        USBD_EP_TYPE_BULK,                                                         //BULK
                                                        USBD_EP_OUTPUT,
                                                        USBD_EPINTSTS_RXPKIF_Msk,
                                                        CEP_BUFF_OFFSET+CEP_BUFF_SIZE+USBD_MASS_STORAGE_EP_BUFF_SIZE, USBD_MASS_STORAGE_EP_BUFF_SIZE, USBD_MASS_STORAGE_PACK_SIZE,
                                                        mass_out_ep_irq);                                                        //设置一数据个端点的配置数据
        USBD_MassStorageInit(&sg_USBD_MassStorage_Handle, g_USBD_MassStorageIN_EP, g_USBD_MassStorageOUT_EP, &cg_usbd_sd_storage, 1024*64, STORAGE_LUN_NBR);        //USB存储设备初始化(只能调用一次)
       
        //等待插上USB
        while(!USBD_IS_ATTACHED())
        {
                Sleep(10);
        }
        USBD_Start();
       
        while(1)
        {
                OSTaskSemPend(0, OS_OPT_POST_NONE, &USBD_TaskTs, &err);                        //等待一个信号量,超时时间-永久
                USBD_MassStorageHandle(&sg_USBD_MassStorage_Handle);                        //USB存储设备处理(OUT接收数据中断中调用)
    }
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

60

主题

3893

帖子

1

粉丝