本帖最后由 ljxh401 于 2021-1-25 20:58 编辑
因为标准库的 usb demo 是基于状态的 不是基于流程的,分析起来很痛苦
将我劝退了好多年,终于下定决心来学习,
看完资料,将它的枚举流程 移植到 ucos2 里面 看起来就非常清晰
枚举的过程的代码如下,通过操作系统,代码容易学习多了
void JkData_Setup0(USB_REQ *pReq)
{
static INT8U recbuf[128];
INT16U len;
INT8U flag=0;
printf("r:%d\r\n",pReq->USBbRequest&0xff);
if (pReq->USBbRequest == GET_DESCRIPTOR)
{
ONE_DESCRIPTOR *pDescriptor=&Device_Descriptor;
if ( (pReq->USBbmRequestType& (REQUEST_TYPE | RECIPIENT)) == (STANDARD_REQUEST | DEVICE_RECIPIENT))
{
switch(pReq->USBwValues>>8)
{
case DEVICE_DESCRIPTOR:
pDescriptor=&Device_Descriptor;
break;
case CONFIG_DESCRIPTOR:
pDescriptor=&Config_Descriptor;
break;
case STRING_DESCRIPTOR:
pDescriptor=&String_Descriptor[pReq->USBwValues&0xff];
break;
}
if(pReq->USBwLengths>pDescriptor->Descriptor_Size)
{
len=pDescriptor->Descriptor_Size;
flag=((len%UsbMaxSize)==0);
}else
{
len=pReq->USBwLengths;
flag=0;
}
SendEp0Data(pDescriptor->Descriptor,len,flag);
}
}
else if(pReq->USBbRequest == SET_ADDRESS)
{
//返回一个空回复,作为事务的状态回复
if(SendEp0Data(NULL,0,1)==OS_NO_ERR)
SetDeviceAddress(pReq->USBwValues&0xff);
}
else if(pReq->USBbRequest==SET_CONFIGURATION)
{
//返回一个空回复,作为事务的状态回复
SendEp0Data(NULL,0,1);
}
else if (pReq->USBbRequest == SET_LINE_CODING)
{
RecEp0Data(recbuf,7);
printf("%02X %02X %02X %02X %02X %02X %02X \r\n",recbuf[0],recbuf[1],recbuf[2],recbuf[3],recbuf[4],recbuf[5],recbuf[6]);
}
else if (pReq->USBbRequest == GET_LINE_CODING)
{
//返回波特率的设置
if(pReq->USBwLengths>sizeof(linecoding))
{
len=sizeof(linecoding);
flag=((len%UsbMaxSize)==0);
}else
{
len=pReq->USBwLengths;
flag=0;
}
SendEp0Data((INT8U*)&linecoding,len,flag);
printf("Q:%02X %02X %04X%04X%04X\r\n",pReq->USBbmRequestType,pReq->USBbRequest,pReq->USBwValues,pReq->USBwIndexs,pReq->USBwLengths);
}
else if(pReq->USBbRequest == SET_CONTROL_LINE_STATE)
{
//收到这个命令之后 不久usb串口就会自动关闭,求解
SendEp0Data(NULL,0,1);
}
else
{
//printf("q:%02X %02X %04X%04X%04X\r\n",pReq->USBbmRequestType,pReq->USBbRequest,pReq->USBwValues,pReq->USBwIndexs,pReq->USBwLengths);
}
}
全部的修改代码如下
#include "includes.h"
#include "hw_config.h"
#include "usb_istr.h"
#include "usb_prop.h"
#define UsbMaxSize 64
OS_EVENT *OSQUsbEP0;
void SetUsbEP0Msg( INT32U msg)
{
OSQPost(OSQUsbEP0,(void*)msg);
}
#define UsbLinkPin PerpheralBit(GPIOC->ODR,12)
void InitUsb(void)
{
SetPinState(GPIOC,GPIO_Pin_12,GPIO_Mode_Out_PP); // mb n
UsbLinkPin=0;
Set_USBClock();
USB_Interrupts_Config();
USB_Init();
UsbLinkPin=1;
}
/*---- S E N D E P 0 D A T A ----
【功能】:上传各种数据 例如描述符 ...
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西 2021年1月25日16:35:26--------------------------------*/
INT8U SendEp0Data(INT8U *pSrc,INT16U len,INT8U flag0)
{
INT32U msg;
INT16U sendcnt;
INT8U pagesize,err=OS_ERR_NONE;
for(sendcnt=0;sendcnt<len;sendcnt+=UsbMaxSize)
{
pagesize=(len-sendcnt)>UsbMaxSize?UsbMaxSize:(len-sendcnt);
UserToPMABufferCopy(pSrc+sendcnt, GetEPTxAddr(ENDP0), pagesize);
SetEPTxCount(ENDP0, pagesize);
SetEPRxValid(ENDP0);
SetEPTxValid(ENDP0);
msg=(INT32U)OSQPend(OSQUsbEP0,OS_TICKS_PER_SEC/500,&err);
if(err!=OS_ERR_NONE)
{
break;
}
if((msg & EP_CTR_TX)== 0)
{
OSQPostFront(OSQUsbEP0, (void *)msg);
break;
}
}
if(flag0 && err==OS_ERR_NONE)
{
//发送空输入
SetEPTxCount(ENDP0, 0);
SetEPTxValid(ENDP0);
SetEPRxValid(ENDP0);
msg=(INT32U)OSQPend(OSQUsbEP0,OS_TICKS_PER_SEC/500,&err);
if((msg & EP_CTR_TX)== 0 && err!=OS_TIMEOUT)
{
OSQPostFront(OSQUsbEP0, (void *)msg);
if(len==0) printf("B");
}
else if(len==0) printf("b");
}
if(len!=0 && err==OS_ERR_NONE)
{
//等待空输出返回
SetEPRxValid(ENDP0);
msg=(INT32U)OSQPend(OSQUsbEP0,OS_TICKS_PER_SEC/500,&err);
}
SetEPRxValid(ENDP0);
return err;
}
/*---- R E C E P 0 D A T A ----
【功能】:接收设置数据
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西 2021年1月25日16:35:03--------------------------------*/
INT8U RecEp0Data(INT8U *pDst,INT16U len)
{
INT32U msg;
INT16U pagesize;
INT8U err;
do{
SetEPRxValid(ENDP0);
SetEPTxValid(ENDP0);
msg=(INT32U)OSQPend(OSQUsbEP0,OS_TICKS_PER_SEC/500,&err);
if(err==OS_TIMEOUT) break;
if((msg & (EP_CTR_RX|EP_SETUP))!= EP_CTR_RX)
{
OSQPostFront(OSQUsbEP0, (void *)msg);
break;
}
pagesize=GetEPRxCount(ENDP0);
if(pagesize>len) pagesize=len;
PMAToUserBufferCopy(pDst, GetEPRxAddr(ENDP0), pagesize);
len-=pagesize;
pDst+=pagesize;
}while(len>0);
if(len==0)
{
//接收完毕
SetEPTxCount(ENDP0, 0);
SetEPTxValid(ENDP0);
msg=(INT32U)OSQPend(OSQUsbEP0,OS_TICKS_PER_SEC/500,&err);
if((msg & EP_CTR_TX)== 0 && err!=OS_TIMEOUT)
{
OSQPostFront(OSQUsbEP0, (void *)msg);
}
}
SetEPRxValid(ENDP0);
return len;
}
extern ONE_DESCRIPTOR Device_Descriptor;
extern ONE_DESCRIPTOR Config_Descriptor;
extern ONE_DESCRIPTOR String_Descriptor[4];
extern LINE_CODING linecoding;
void JkData_Setup0(USB_REQ *pReq)
{
static INT8U recbuf[128];
INT16U len;
INT8U flag=0;
printf("r:%d\r\n",pReq->USBbRequest&0xff);
if (pReq->USBbRequest == GET_DESCRIPTOR)
{
ONE_DESCRIPTOR *pDescriptor=&Device_Descriptor;
if ( (pReq->USBbmRequestType& (REQUEST_TYPE | RECIPIENT)) == (STANDARD_REQUEST | DEVICE_RECIPIENT))
{
switch(pReq->USBwValues>>8)
{
case DEVICE_DESCRIPTOR:
pDescriptor=&Device_Descriptor;
break;
case CONFIG_DESCRIPTOR:
pDescriptor=&Config_Descriptor;
break;
case STRING_DESCRIPTOR:
pDescriptor=&String_Descriptor[pReq->USBwValues&0xff];
break;
}
if(pReq->USBwLengths>pDescriptor->Descriptor_Size)
{
len=pDescriptor->Descriptor_Size;
flag=((len%UsbMaxSize)==0);
}else
{
len=pReq->USBwLengths;
flag=0;
}
SendEp0Data(pDescriptor->Descriptor,len,flag);
}
}
else if(pReq->USBbRequest == SET_ADDRESS)
{
//返回一个空回复,作为事务的状态回复
if(SendEp0Data(NULL,0,1)==OS_NO_ERR)
SetDeviceAddress(pReq->USBwValues&0xff);
}
else if(pReq->USBbRequest==SET_CONFIGURATION)
{
//返回一个空回复,作为事务的状态回复
SendEp0Data(NULL,0,1);
}
else if (pReq->USBbRequest == SET_LINE_CODING)
{
RecEp0Data(recbuf,7);
printf("%02X %02X %02X %02X %02X %02X %02X \r\n",recbuf[0],recbuf[1],recbuf[2],recbuf[3],recbuf[4],recbuf[5],recbuf[6]);
}
else if (pReq->USBbRequest == GET_LINE_CODING)
{
//返回波特率的设置
if(pReq->USBwLengths>sizeof(linecoding))
{
len=sizeof(linecoding);
flag=((len%UsbMaxSize)==0);
}else
{
len=pReq->USBwLengths;
flag=0;
}
SendEp0Data((INT8U*)&linecoding,len,flag);
printf("Q:%02X %02X %04X%04X%04X\r\n",pReq->USBbmRequestType,pReq->USBbRequest,pReq->USBwValues,pReq->USBwIndexs,pReq->USBwLengths);
}
else if(pReq->USBbRequest == SET_CONTROL_LINE_STATE)
{
//收到这个命令之后 不久usb串口就会自动关闭,求解
SendEp0Data(NULL,0,1);
}
else
{
//printf("q:%02X %02X %04X%04X%04X\r\n",pReq->USBbmRequestType,pReq->USBbRequest,pReq->USBwValues,pReq->USBwIndexs,pReq->USBwLengths);
}
}
u8 SetupHandle(void)
{
USB_REQ req;
INT8U *pBuf = PMAAddr + (u8 *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */
req.USBbmRequestType=*pBuf++;
req.USBbRequest=*pBuf++;
pBuf+=2;
req.USBwValues=pBuf[0]+((INT16U)pBuf[1]<<8);
pBuf+=4;
req.USBwIndexs=pBuf[0]+((INT16U)pBuf[1]<<8);
pBuf+=4;
req.USBwLengths=pBuf[0]+((INT16U)pBuf[1]<<8);
JkData_Setup0(&req);
return 1;
}
/*---- U S B T A S K ----
【功能】:将usb
的端点0的控制中断,描述符上移动到这里来,让代码更加清晰,这里是尝试移植stm32的虚拟串口的
【参数】:****
【返回】:****
【说明】:****
--------------作者:卢杰西 2021年1月23日17:12:35--------------------------------*/
void UsbTask(void *pt)
{
INT8U err;
INT32U msg;
CREATE_SMSG(OSQUsbEP0, 10);
InitUsb();
while(1)
{
msg=(INT32U)OSQPend(OSQUsbEP0,0,&err);
if ((msg & EP_CTR_TX) != 0)
{
printf("B");
SetEPRxValid(ENDP0);
}
else if ((msg &EP_SETUP) != 0)
{
SetupHandle();
}
else if ((msg & EP_CTR_RX) != 0)
{
printf("C");
SetEPRxValid(ENDP0);
}
}
}
void CTR_LP(void)
{
u32 wEPVal = 0;
/* stay in loop while pending ints */
while (((wIstr = _GetISTR()) & ISTR_CTR) != 0)
{
_SetISTR((u16)CLR_CTR); /* clear CTR flag */
/* extract highest priority endpoint number */
EPindex = (u8)(wIstr & ISTR_EP_ID);
if (EPindex == 0)
{
_SetEPRxStatus(ENDP0, EP_RX_NAK);
_SetEPTxStatus(ENDP0, EP_TX_NAK);
wEPVal = _GetENDPOINT(ENDP0);
if ((wEPVal & EP_CTR_TX) != 0)
_ClearEP_CTR_TX(ENDP0);
else if ((wEPVal &EP_SETUP) != 0)
_ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */
else if ((wEPVal & EP_CTR_RX) != 0)
_ClearEP_CTR_RX(ENDP0);
SetUsbEP0Msg(wEPVal);
}/* if(EPindex == 0) */
else
{
/* Decode and service non control endpoints interrupt */
/* process related endpoint register */
wEPVal = _GetENDPOINT(EPindex);
if ((wEPVal & EP_CTR_RX) != 0)
{
/* clear int flag */
_ClearEP_CTR_RX(EPindex);
/* call OUT service function */
(*pEpInt_OUT[EPindex-1])();
} /* if((wEPVal & EP_CTR_RX) */
if ((wEPVal & EP_CTR_TX) != 0)
{
/* clear int flag */
_ClearEP_CTR_TX(EPindex);
/* call IN service function */
(*pEpInt_IN[EPindex-1])();
} /* if((wEPVal & EP_CTR_TX) != 0) */
}/* if(EPindex == 0) else */
}/* while(...) */
}
/*******************************************************************************
* Function Name : USB_LP_CAN_RX0_IRQHandler
* Description : This function handles USB Low Priority or CAN RX0 interrupts
* requests.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void USB_LP_CAN_RX0_IRQHandler(void)
{
OSIntEnter();
USB_Istr();
OSIntExit();
}
|