打印

STM32的usb串口demo移植到ucos,看枚举的过程就清晰多了

[复制链接]
3103|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ljxh401|  楼主 | 2021-1-25 18:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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();
}


使用特权

评论回复

相关帖子

沙发
Tanxjxj120a| | 2021-1-25 18:32 | 只看该作者
谢谢分享 收藏学习

使用特权

评论回复
板凳
xyz549040622| | 2021-1-25 23:38 | 只看该作者
支持一下,谢谢分享。

使用特权

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

本版积分规则

50

主题

221

帖子

3

粉丝