STM32-USB
+ -

STM32F407的USB类请求回调函数USBD_Class_cb_TypeDef

2022-06-17 570 0

前面介绍了获取描述会和USB设备状态的回调函数,这里界绍USB在实际使用过程中的USB请求通讯。这里还是以STM32F407的U盘为示例来说明。

STM32F407的USB类请求使用结构体USBD_Class_cb_TypeDef来整合回调函数。

typedef struct _Device_cb
{
  uint8_t  (*Init)         (void *pdev , uint8_t cfgidx);
  uint8_t  (*DeInit)       (void *pdev , uint8_t cfgidx);
 /* Control Endpoints*/
  uint8_t  (*Setup)        (void *pdev , USB_SETUP_REQ  *req);  
  uint8_t  (*EP0_TxSent)   (void *pdev );    
  uint8_t  (*EP0_RxReady)  (void *pdev );  
  /* Class Specific Endpoints*/
  uint8_t  (*DataIn)       (void *pdev , uint8_t epnum);   
  uint8_t  (*DataOut)      (void *pdev , uint8_t epnum); 
  uint8_t  (*SOF)          (void *pdev); 
  uint8_t  (*IsoINIncomplete)  (void *pdev); 
  uint8_t  (*IsoOUTIncomplete)  (void *pdev);   

  uint8_t  *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length); 
#ifdef USB_OTG_HS_CORE 
  uint8_t  *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length);   
#endif

#ifdef USB_SUPPORT_USER_STRING_DESC 
  uint8_t  *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index,  uint16_t *length);   
#endif  

} USBD_Class_cb_TypeDef;

相关的回调函数初始化为:

USBD_Class_cb_TypeDef  USBD_MSC_cb = 
{
  USBD_MSC_Init,
  USBD_MSC_DeInit,
  USBD_MSC_Setup,
  NULL, /*EP0_TxSent*/  
  NULL, /*EP0_RxReady*/
  USBD_MSC_DataIn,
  USBD_MSC_DataOut,
  NULL, /*SOF */ 
  NULL,  
  NULL,     
  USBD_MSC_GetCfgDesc,
#ifdef USB_OTG_HS_CORE  
  USBD_MSC_GetOtherCfgDesc,
#endif
};

USBD_MSC_Init

该函数用于设备工作后,对端点的初始化操作。

uint8_t  USBD_MSC_Init (void  *pdev, 
                            uint8_t cfgidx)
{
  USBD_MSC_DeInit(pdev , cfgidx );

  /* Open EP IN */
  DCD_EP_Open(pdev,
              MSC_IN_EP,
              MSC_EPIN_SIZE,
              USB_OTG_EP_BULK);

  /* Open EP OUT */
  DCD_EP_Open(pdev,
              MSC_OUT_EP,
              MSC_EPOUT_SIZE,
              USB_OTG_EP_BULK);

  /* Init the BOT  layer */
  MSC_BOT_Init(pdev); 

  return USBD_OK;
}

cfgidx为选择配置描述符的ID。这里为USB-BOTU盘设备,故初始化BULK传输的输入和输出端点,最后初始化U盘.
BOT的U盘支持UFI命令,这里使用结构体USBD_STORAGE_cb_TypeDef来整合。

typedef struct _USBD_STORAGE
{
  int8_t (* Init) (uint8_t lun);
  int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint32_t *block_size);
  int8_t (* IsReady) (uint8_t lun);
  int8_t (* IsWriteProtected) (uint8_t lun);
  int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
  int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
  int8_t (* GetMaxLun)(void);
  int8_t *pInquiry;
}USBD_STORAGE_cb_TypeDef;


USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops =
{
    STORAGE_Init,
    STORAGE_GetCapacity,
    STORAGE_IsReady,
    STORAGE_IsWriteProtected,
    STORAGE_Read,
    STORAGE_Write,
    STORAGE_GetMaxLun,
    (int8_t *)STORAGE_Inquirydata,
};
USBD_STORAGE_cb_TypeDef  *USBD_STORAGE_fops=&USBD_MICRO_SDIO_fops;//Ö¸ÏòUSBD_MICRO_SDIO_fops½á¹¹Ìå.

可以看到,这里对应UFI的相关命令回调函数。

关于U盘的UFI BOT命令,详参见站站的http://www.usbzh.com/article/forum-57.html

USBD_MSC_DeInit

反初始化。

uint8_t  USBD_MSC_DeInit (void  *pdev, 
                              uint8_t cfgidx)
{
  /* Close MSC EPs */
  DCD_EP_Close (pdev , MSC_IN_EP);
  DCD_EP_Close (pdev , MSC_OUT_EP);

  /* Un Init the BOT layer */
  MSC_BOT_DeInit(pdev);   
  return USBD_OK;
}

USBD_MSC_Setup

SETUP令牌包,其实就是U盘的类特定请求,如BOT_GET_MAX_LUN等。

uint8_t  USBD_MSC_Setup (void  *pdev, USB_SETUP_REQ *req)
{

  switch (req->bmRequest & USB_REQ_TYPE_MASK)
  {

  /* Class request */
  case USB_REQ_TYPE_CLASS :
    switch (req->bRequest)
    {
    case BOT_GET_MAX_LUN :

      if((req->wValue  == 0) && 
         (req->wLength == 1) &&
         ((req->bmRequest & 0x80) == 0x80))
      {
        USBD_MSC_MaxLun = USBD_STORAGE_fops->GetMaxLun();
        if(USBD_MSC_MaxLun > 0)
        {
           USBD_CtlSendData (pdev,
                             &USBD_MSC_MaxLun,
                              1);
        }
        else
        {
          USBD_CtlError(pdev , req);
          return USBD_FAIL; 

        }
      }
      else
      {
         USBD_CtlError(pdev , req);
         return USBD_FAIL; 
      }
      break;

    case BOT_RESET :
      if((req->wValue  == 0) && 
         (req->wLength == 0) &&
        ((req->bmRequest & 0x80) != 0x80))
      {      
         MSC_BOT_Reset(pdev);
      }
      else
      {
         USBD_CtlError(pdev , req);
         return USBD_FAIL; 
      }
      break;

    default:
       USBD_CtlError(pdev , req);
       return USBD_FAIL; 
    }
    break;
  /* Interface & Endpoint request */
  case USB_REQ_TYPE_STANDARD:
    switch (req->bRequest)
    {
    case USB_REQ_GET_INTERFACE :
      USBD_CtlSendData (pdev,
                        &USBD_MSC_AltSet,
                        1);
      break;

    case USB_REQ_SET_INTERFACE :
      USBD_MSC_AltSet = (uint8_t)(req->wValue);
      break;

    case USB_REQ_CLEAR_FEATURE:  

      /* Flush the FIFO and Clear the stall status */    
      DCD_EP_Flush(pdev, (uint8_t)req->wIndex);

      /* Re-activate the EP */      
      DCD_EP_Close (pdev , (uint8_t)req->wIndex);
      if((((uint8_t)req->wIndex) & 0x80) == 0x80)
      {
        DCD_EP_Open(pdev,
                    ((uint8_t)req->wIndex),
                    MSC_EPIN_SIZE,
                    USB_OTG_EP_BULK);
      }
      else
      {
        DCD_EP_Open(pdev,
                    ((uint8_t)req->wIndex),
                    MSC_EPOUT_SIZE,
                    USB_OTG_EP_BULK);
      }

      /* Handle BOT error */
      MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
      break;

    }  
    break;

  default:
    break;
  }
  return USBD_OK;
}

这里应关注USB_REQ_CLEAR_FEATURE,可以看到当设备的端点有问题时,主机使用CLEAR_FEATURE清除端点,这里一般执行端点的关闭和重新打开。

USBD_MSC_DataIn

输入端点的回调,即设备的BULK传输发送数据到主机。

uint8_t  USBD_MSC_DataIn (void  *pdev, 
                              uint8_t epnum)
{
  MSC_BOT_DataIn(pdev , epnum);
  return USBD_OK;
}

void MSC_BOT_DataIn (USB_OTG_CORE_HANDLE  *pdev, 
                     uint8_t epnum)
{

  switch (MSC_BOT_State)
  {
  case BOT_DATA_IN:
    if(SCSI_ProcessCmd(pdev,
                        MSC_BOT_cbw.bLUN,
                        &MSC_BOT_cbw.CB[0]) < 0)
    {
      MSC_BOT_SendCSW (pdev, CSW_CMD_FAILED);
    }
    break;

  case BOT_SEND_DATA:
  case BOT_LAST_DATA_IN:
    MSC_BOT_SendCSW (pdev, CSW_CMD_PASSED);

    break;

  default:
    break;
  }
}

USBD_MSC_DataOut

端点输出数据,即主机发送数据到设备。如CBW等。

uint8_t  USBD_MSC_DataOut (void  *pdev, 
                               uint8_t epnum)
{
  MSC_BOT_DataOut(pdev , epnum);
  return USBD_OK;
}
void MSC_BOT_DataOut (USB_OTG_CORE_HANDLE  *pdev, 
                      uint8_t epnum)
{
  switch (MSC_BOT_State)
  {
  case BOT_IDLE:
    MSC_BOT_CBW_Decode(pdev);
    break;

  case BOT_DATA_OUT:

    if(SCSI_ProcessCmd(pdev,
                        MSC_BOT_cbw.bLUN,
                        &MSC_BOT_cbw.CB[0]) < 0)
    {
      MSC_BOT_SendCSW (pdev, CSW_CMD_FAILED);
    }

    break;

  default:
    break;
  }

}
HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

STM32F103 UVC设备源代码(模拟相机)
1.STM32F103 UVC设备源代码(模拟相机)https://pan.baidu.com/s/1treoRRxQndFoE0K8oRFndg 提取码:0jt3其它资料:1.各种工具1.USB协议分析工具https://pan.baidu.com/s/1DeXqRWsM7BOYTdrmIE8KB......
USB键盘在Linux环境下一直返回NAK的输入端点和一直OUT数据的输出端点
群里有同学反馈,自己做的USB键盘在Windows下正常,但在Linux下就失败,想让帮忙分析一下原因。一个比较好的消息是他那边有USB总线分析仪,所以只需要抓包就可以进行分析了。最好开他给的抓包截图是样子的:从它的截图可以看到,USB键盘在获取了该键盘的HID报告描述符后,紧跟着一下发Report......
USB2.0 CLEAR_FEATURE传输及事务
USB2.0 CLEAR_FEATURE传输及事务,更多详见CLEAR_FEATURE标准请求......
STM32 USB Audio 开发板
一、背景我个人从事音频行业有好几年的时间。后面慢慢的做起了声卡,也就是USB Audio。自己也走了不少的弯路。之前一起是拿开发板配套Demo去学习。但Demo离商用还是有点距离。要么就是不稳定要么就是功能不全面。我前面也写了篇文章关于stm32实现USB Audio的过程。因为是公司的代码。所以没......
STM32发送数据与接收到的数据长度不一致问题
群里一位同发提了一个问题,自己弄了一个USB HID游戏控制器,一次发送了7字节,不过通过BUSHOUND抓到只有5字节。还贴上了图。各位,请问一下我做的一个USBHID游戏控制器,一次发送的是7位数据,为什么BusHound上只接收到五位?由于没有显示长度,所以刚开始我还以为是BUSHOU......
USB全速STM32F407管脚初始化
STM32F407ZG的管脚PA11和PA12是一个复用功能引脚。其功能如下:管脚USBPA11OTG_FS_DM(D-)PA12OTG_FS_DP(D+)由于其内部D+有一个可配置上拉电阻,所以其硬件原图如下:故只需要分别将连接器P11的46管脚和35管脚短......
STM32F407 USB设备模块数据结构及初始化入口函数USBD_Init
本人以STM32F404自带的读卡器SLAVE代码为来解说。STM32F404支持OTG功能,其自带一个全速的USB功能。其USB初始化其实就是写相应的函数代码,这些函数代码却是通一个个的结构体整合起来成回调函数,这些函数是由我们自己写的。而STM32的库函数根据这些构体中的函数指针负责回调我们自......
STM32F407入口函数USBD_Init详解
从前面可知,USBD_Init是USB设备的初始化函数,这里USB后面的D是指DEVICE的意思。USBD_Init全代码为:void USBD_Init(USB_OTG_CORE_HANDLE *pdev, USB_OTG_CORE_ID_TypeDef core......
STM32F407的USB用户回调函数USBD_Usr_cb_TypeDef
前面了解过USBD_Usr_cb_TypeDef结构体中是用户的回调函数。用户的回调函数位于usbd_user.c文件中。typedef struct _USBD_USR_PROP{ void (*Init)(void); void (*DeviceReset)(uint8_t s......
STM32F407的USB获取描述符请求回调函数USBD_DEVICE
STM32F407的USB获取描述符请求回调函数使用结构体USBD_DEVICE来整合。typedef struct _Device_TypeDef{ uint8_t *(*GetDeviceDescriptor)( uint8_t speed , uint16_t *length); ......
STM32F407的USB类请求回调函数USBD_Class_cb_TypeDef
前面介绍了获取描述会和USB设备状态的回调函数,这里界绍USB在实际使用过程中的USB请求通讯。这里还是以STM32F407的U盘为示例来说明。STM32F407的USB类请求使用结构体USBD_Class_cb_TypeDef来整合回调函数。typedef struct _Device_cb......
嵌入式STM32常用USB术语
术语解释AHBAMBA High-performance BusAMBAAdvanced Microcontroller Bus ArchitectureCDCCommunication Device ClassDCDDevice Core Driver......
STM32 USB Device Core函数总结
包含三个文件:usbd_core.c :初始化及设备状态请求回调usbd_ioreq.c: API函数封装usbd_req.c :USB标准请求(设备、接口、端点),是usbd_core中USBD_SetupStage函数的详细化udbd_core.cUSB设备库的初始化函数以及相关的USB请......
STM32 USB_OTG_Driver函数总结
USB_OTG_Driver目录下的文件有:usb_bsp_template.c :与硬件初始化相关的空模板usb_core.c :比较底层USB函数usb_dcd.c:USB作为设备时需要的API函数usb_dcd_int.c :作为设备时的中断处理usb_hcd.c :USB作为主机时的AP......
STM32 USB-HID设备示例及工程结构
STM32 USB-HID设备工程结构对于HID示例工程,其代码数据结构如下:APPapp.c :main函数stm32fxxx_it.c :STM32中断usb_bsp.c :平台硬件相关的。主要是USB_OTG_BSP_Init和USB_OTG_BSP_EnableInterruptus......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!