官方提供的USBD驱动太随意,根本没法直接使用,折腾好久原因是我的开发板上面使用了一个很老的HUB芯片,是USB1.1的,导致没法使用USB2.0,后续测试都是基于USB1.1的,实际上USB2.0会更简单,因为支持的bluk可以支持512字节,USB1.1只有64字节,但是实际使用中除了速度区别,别的区别不大,因为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 PHYSYS_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);                                        //复位地址为0USBD_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);                                     //复位地址为0AIC_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中断
}/*************************************************************************************************************************
* 函数            :   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[i] = USBD_ReadEPx_DataByte(EPx);//读取数据}return len;
}/*************************************************************************************************************************
* 函数            :   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[i].InitId != USBD_EP_INIT_ID)       //找到空闲的EP了{*pEPx = (USBD_EPx)i;return TRUE;}}return FALSE;
}/*************************************************************************************************************************
* 函数            :   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;
}/*************************************************************************************************************************
* 函数            :   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;}
}/*************************************************************************************************************************
* 函数            :   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[i].CFG & 0xf0) >> 4) == EpNum) {USBD->EPx[i].RSPCTL = (USBD->EPx[i].RSPCTL & 0xf7) | USB_EP_RSPCTL_HALT;}}}
}/*************************************************************************************************************************
* 函数            :   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[i].CFG & 0xf0) >> 4) == EpNum) {USBD->EPx[i].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令牌中断使能,等待发送数据}
}/*************************************************************************************************************************
* 函数            :   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[i]);}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();                                  //启动DMAwhile(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;
}/*************************************************************************************************************************
* 函数            :   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);       //端点地址使用端点号+1for (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;
}/*************************************************************************************************************************
* 函数            :   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);                                           //端点地址使用端点号+1for (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;
}/*************************************************************************************************************************
* 函数            :   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[i].CFG & 0xf0) >> 4) == EpNum) {return (USBD->EPx[i].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);
}/*************************************************************************************************************************
* 函数            :   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 hostswitch (g_USBD_Setup.Request) {case USBD_GET_CONFIGURATION: //获取设备配置描述符-主机枚举设备{uart_printf("GET_CONFIGURATION\r\n");// Return current configuration settingUSBD_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");// Deviceif (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 deviceswitch (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;}}
}/*************************************************************************************************************************
* 函数            :   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;}
}/*************************************************************************************************************************
* 函数            :   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 enableswitch (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[i].CFG & 0x1) {USBD->EPx[i].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;}
}/*************************************************************************************************************************
* 函数            :   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();                                        //复位DMAfor(i = 0;i < USBD_MAX_EP;i ++){if(sg_EpConfig[i].InitId == USBD_EP_INIT_ID)     //对应端点使能了,则清除数据{USBD->EPx[i].RSPCTL = USBD_EPRSPCTL_FLUSH_Msk;USBD_SetEpConfig(&sg_EpConfig[i]);             //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清除
}/*************************************************************************************************************************
* 函数            :   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;                                  //清除中断
}/*************************************************************************************************************************
* 函数            :   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;                                        //清除总中断
}

//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端点AUSBD_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_MaxPackSizeUSBD_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_

测试代码,先只测试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(); //初始化USBDUSBD_InterfaceConfig(NULL, NULL, USBD_ClassRequest, NULL, &cg_USBD_Descriptor);//USBD所需接口配置USBD_GetIdleEp(&g_USBD_MassStorageIN_EP);                           //获取一个空闲的EP通道 INUSBD_SetEpConfigData(   g_USBD_MassStorageIN_EP,                    //INUSBD_EP_TYPE_BULK,                          //BULKUSBD_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通道 OUTUSBD_SetEpConfigData(  g_USBD_MassStorageOUT_EP,                   //OUTUSBD_EP_TYPE_BULK,                             //BULKUSBD_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存储设备初始化(只能调用一次)//等待插上USBwhile(!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接收数据中断中调用)}
}

NUC970 裸机USBD驱动(第一章)相关推荐

  1. 【正点原子MP157连载】第一章 本书学习方法-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  2. Android项目驱动式开发教程 第2版,《Android项目驱动式开发教程》第一章开发入门.ppt...

    <Android项目驱动式开发教程>第一章开发入门 1.4 项目框架分析 4 android:versionName="1.0" > 5 8 第9行代码andro ...

  3. 微型计算机与裸机,第一章 微型计算机基础

    考点一.理解微处理器.微型计算机和微型计算机系统的概念及其相互关系. 1.1微信计算机系统组成 微型计算机是指以微处理器为核心,配上存储器,输入/输出接口电路等所组成的计算机. 微型计算机系统是指以微 ...

  4. [转]写一个块设备驱动(第一章)

    写一个块设备驱动1,2(转) 2009/09/03 15:42 第1章 +---------------------------------------------------+ |          ...

  5. 一步一步走进块驱动之第一章

    第一章 本教程修改自赵磊的网上的一系列教程.本人觉得该系列教程写的非常不错.以风趣幽默的语言将块驱动写的非常详细,对于入门教程,应该属于一份经典了. 本人在这对此系列教程对细微的修改,仅针对Linux ...

  6. 【正点原子MP157连载】第一章 Ubuntu系统安装-摘自【正点原子】【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  7. 知道第一章计算机基础知识作业答案,大学计算机基础作业答案

    大学计算机基础作业答案 第一章 现代社会与计算机 1. 什么事信息,其主要特征是什么? 答:信息是可传递和共享的,可消除人们认知上的不确定因素,对人们的决策具有现实或潜在价值的知识. 特征:普遍性.依 ...

  8. 【王道考研】操作系统 笔记 第一章

    特此鸣谢王道考研 本文参考王道考研的相关课程 若有侵权请联系,立删 其余笔记链接: [王道考研]操作系统笔记 第一章_才疏学浅743的博客-CSDN博客 [王道考研]操作系统 笔记 第二章上 进程调度 ...

  9. 操作系统王道考研复习——第一章(计算机系统概述)

    操作系统王道考研复习--第一章(计算机系统概述) 计算机系统概述 1.1操作系统的基本概念 1.1.1 操作系统的概念 1.1.2 操作系统的特征 1. 并发 2. 共享 3. 虚拟 4. 异步 1. ...

最新文章

  1. Nature:剖腹产到底好不好?——肠道菌群的视角
  2. SecureRandom
  3. IOS的pch文件,NSTimer定时器,运行消息循环,随机色使用
  4. Codeforces Round #686 (Div. 3) E. Number of Simple Paths 基环树 + 容斥
  5. arm linux挂载ubi,挂载ubifs文件系统分区
  6. DT CMS致力于Spring Boot2.3.5 Vue前后端分离的RBAC权限框架(盛世美颜!)
  7. ASP.NET Core:使用IdentityServer构建可靠的身份验证和授权系统
  8. socket编程之回声服务器
  9. vue-router parmas与query的区别
  10. 《Java程序员职场全功略:从小工到专家》连载六:亚洲企业工作模式
  11. jenkins安装与自动部署详细说明
  12. 手把手写一个vue3的组件
  13. python3生成exe文件_python3.7打包成exe就三步
  14. 让你的网站用上炫酷的中文字体
  15. 互联网寒冬、裁员,作为程序员的我们,应该如何去应对?
  16. python urllib.parse_Python3的urllib.parse常用函数小结(urlencode,quote,quote_plus,unquote,unquote_plus等)...
  17. Linux--详细安装教程
  18. 网络爬虫技术是什么,网络爬虫的基本工作流程是什么?
  19. [ATF] ARM Trusted firmware 构建选项
  20. Hexo系列(四) NexT主题配置

热门文章

  1. VS2017运行时控制台一闪即逝解决方法
  2. 如何选择网络任务才能够轻松赚钱?(快营通分享)
  3. 中科院吕本富:“互联网+”已产生泡沫
  4. SQL Server2008r2安装
  5. LSM树的基本原理-学习笔记
  6. cron表达式,看这篇就够了
  7. linux切换网口,linux多网口绑定
  8. java的protect_java中protect是什么
  9. Qt几个月的学习心得及展望
  10. 如何分析一个开源工程的代码