一、USB总体概况

1.1、USB通信过程简介

  1. 设备插到主机上
  2. 主机开始检测设备类型(高速/全速/低速)
  3. 复位设备
  4. 主机开始对设备枚举(根据枚举得到的各种信息加载合适的驱动程序,比如根据信息知道是一个鼠标设备,则加载鼠标的驱动程序对接下来的数据进行处理)
  5. 枚举完成后主机要发送令牌包(IN / OUT)查询有效端点是否有数据,有数据时设备自然会返还给主机

1.2、USB枚举过程简介

  1. 主机获取设备描述符(部分)
  2. 主机对从机设置设备地址(非零,相当于我们的学号id)
  3. 主机再次获取从机设备描述符(全部)
  4. 主机获取配置描述符(了解从机配置,接口,端点)情况
  5. 如果有字符串描述符还有获取字符串描述符
  6. 设置配置请求,就是激活配置,如果没有这一步对应的配置就不可用
  7. 针对不同的类,获取它们独特的类描述符(比如HID报告描述符)

注意:

  1. 上面的枚举1-4,6步骤是必须的,
  2. 主机和从机通信时,从机时不能主动发数据给主机的,必须要等主机给从机发送令牌包后,根据主机的需求发送相应的数据

1.3、USB 配置  接口  端点  的关系

  1、一个设备可以有多个配置,不同的配置对应不同的功能

    比如,一个USB接口的CD-ROM,作为一个设备,

    它具有两种功能,1读取光盘 和  2播放CD,所以有2个Configuration描述符

  2、一个功能的实现要涉及许多接口,

    比如当CD播放机使用时,需要音频接口,同时还需要控制CD机的接口。 

  3、一个接口又有许多端点组成,一般真正通信都是针对端点进行的,比如用端点0来进行控制枚举传输

    stm32  支持8个双向端点,16个单向端点,每个端点只能时一个方向(OUT / IN),除了端点0

二、区分高速全速 低速设备的方法

d+上面接电阻:全速/高速设备             d-  上接电阻:低速设备

三、USB设备插拔检测机制

3.1、没有插上usb设备主机情况

  1. D+和D-数据线上的下拉电阻起作用,使得二者都在低电平;主机端看来就是个SE0状态;
  2. 同样地,当数据线上的SE0状态持续一段时间了,就被主机认为是断开状态

3.2、 插上usb设备时

当主机检测到某一个数据线电平拉高并保持了一段时间,就认为有设备连上来了

主机必需在驱动SE0状态以复位设备之前, 立刻采样总线状态来判断设备的速度

四、USB通信数据包解释以及包的传输过程

4.1、Packet的组成

4.2 、USB包的分类(令牌,数据包,握手包、帧首包)

包的分类组要是靠PID域来说明的,其中令牌包最重要

4.2.1、令牌包:

IN  OUT  SETUP  三个命令可选,并且都由主机发出,用来启动一次传输

主机和从机通信时,从机时不能主动发数据给主机的,必须要等主机给从机发送令牌包后,根据主机的需求发送相应的数据

  1、IN   主机用来从设备读取数据 

  2、OUT   主机用来向设备发送数据

  3、SETUP  主机用来向设备发送控制命令,接下来就是主机发送一次命令数据给(这个数据一般时获取描述符请求)从机  一般枚举的时候用

例如SETUP包:

4.2.2、数据包:

数据包:一般是DATA0 DATA1交替发出,如本次发送DATA0 下次就发送DATA1,主要目的就是为了校验

图中DATA0 编码是0xC3

4.2.3、握手包

用来确认应答

  >> ACK:传输正确完成
  >> NAK:设备暂时没有准备好接收数据,或没有准备好发送数据
  >> STALL:设备不能进行传输
  >> NYET/ERR:仅用于高速传输,设备没有准备好或出错

4.3、包的传输顺序

一般都是先由主机发送命令,然后才是数据过程,再时应答过程

五、枚举过程

枚举过程都是主机发送标准请求然后从机做出相应的应答

5.1、枚举过程的通俗比喻

1、主机(下称H):你是什么设备(获取设备描述符请求)?
  设备(下称D):12 01 0100……Device Descriptor
2、H:你有几种功能(获取配置描述符请求)?
  D:09 02 09……Configuration Descriptor
3、H:每个功能有几个接口(获取接口描述符)?
  D:09 04 00……Interface Descriptor
4、H:每个接口使用哪几个端点(获取端点描述符)?
  D:06 05 82……Endpoint Descriptor
5、H:好了,我知道你是谁了,开始传输数据吧!
  D:OK, Read Go

5.2、主机标准请求

主机要获得从机的描述符就要发送相关8字节标准请求

5.3、描述符介绍

5.3.1、设备描述符

以stm32为例:

/*usb_desc.c*//* USB Standard Device Descriptor */
const uint8_t Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] ={0x12,                       /*bLength */USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/0x00,                       /*bcdUSB */0x02,0x00,                       /*bDeviceClass*/0x00,                       /*bDeviceSubClass*/0x00,                       /*bDeviceProtocol*/ 0x40,                       /*bMaxPacketSize 64*/0x83,                       /*idVendor (0x0483)*/0x04,0x10,                       /*idProduct = 0x5710*/0x57,0x00,                       /*bcdDevice rel. 2.00*/0x02,1,                          /*Index of string descriptor describingmanufacturer */2,                          /*Index of string descriptor describingproduct*/3,                          /*Index of string descriptor describing thedevice serial number */   0x01                        /*bNumConfigurations*/}; /* Joystick_DeviceDescriptor */

5.3.2、配置描述符

    0x09, /* bLength: Configuration Descriptor size */USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */JOYSTICK_SIZ_CONFIG_DESC,  /*#define JOYSTICK_SIZ_CONFIG_DESC   34   这是一个大数组,整个数组大小34字节*//* wTotalLength: Bytes returned   */0x00,0x01,         /*bNumInterfaces: 1 interface*/0x01,         /*bConfigurationValue: Configuration value*/0x00,         /*iConfiguration: Index of string descriptor describingthe configuration*/0xE0,         /*bmAttributes: Self powered */0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

5.3.3、 接口描述符

    /************** Descriptor of Joystick Mouse interface ****************//* 09 */0x09,         /*bLength: Interface Descriptor size*/USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/ 0x00,         /*bInterfaceNumber: Number of Interface 序号,编号从0开始,第二个接口就是1*/0x00,         /*bAlternateSetting: Alternate setting*/ 0x01,         /*bNumEndpoints  该接口的端点数目*/  0x03,         /*bInterfaceClass: HID*/0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/  0x02,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/0,            /*iInterface: Index of string descriptor*/

5.3.4、类描述符(比如HID类描述符)这个时可选的(如果不是标准类,就不需要)

   /******************** Descriptor of Joystick Mouse HID ********************//* 18 */0x09,         /*bLength: HID Descriptor size*/HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/0x00,         /*bcdHID: HID Class Spec release number*/0x01,0x00,         /*bCountryCode: Hardware target country*/0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/0x22,         /*bDescriptorType*/JOYSTICK_SIZ_REPORT_DESC,/*wItemLength: Total length of Report descriptor*/0x00,/******************** Descriptor of Joystick Mouse endpoint ********************/

5.3.5、端点描述符

    /******************** Descriptor of Joystick Mouse endpoint ********************//* 27 */0x07,          /*bLength: Endpoint Descriptor size*/USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/  0x81,          /*bEndpointAddress: Endpoint Address (IN)*/ 0x03,          /*bmAttributes: Interrupt endpoint 0控制  1等时  2批量  3中断*/0x04,          /*wMaxPacketSize: 4 Byte max */0x00,0x20,          /*bInterval: Polling Interval (32 ms)*/

5.4、获取设备描述符

5.5、设置地址请求

5.6、获取配置描述符

5.7、设置配置请求

就是让某个配置有效

5.8、stm32 枚举代码分析

/*usbh_core.c*/

void USBH_Process(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost)
{volatile USBH_Status status = USBH_FAIL;switch (phost->gState){、、、、、、、、、、、、case HOST_ENUMERATION:     /* Check for enumeration status */  if ( USBH_HandleEnum(pdev , phost) == USBH_OK){ /* The function shall return USBH_OK when full enumeration is complete *//* user callback for end of device basic enumeration */phost->usr_cb->EnumerationDone();phost->gState  = HOST_USR_INPUT;    }break;、、、、、、、、、、default :break;}}

/*usbh_core.c*/

/*** @brief  USBH_HandleEnum *         This function includes the complete enumeration process* @param  pdev: Selected device* @retval USBH_Status*/
static USBH_Status USBH_HandleEnum(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost)
{USBH_Status Status = USBH_BUSY;  uint8_t Local_Buffer[64];switch (phost->EnumState){case ENUM_IDLE:  /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize 得到8字节设备描述符 */if ( USBH_Get_DevDesc(pdev , phost, 8) == USBH_OK){phost->Control.ep0size = phost->device_prop.Dev_Desc.bMaxPacketSize;/* Issue Reset 复位设备 */HCD_ResetPort(pdev);phost->EnumState = ENUM_GET_FULL_DEV_DESC;/* modify control channels configuration for MaxPacket size */USBH_Modify_Channel (pdev,phost->Control.hc_num_out,0,0,0,phost->Control.ep0size);USBH_Modify_Channel (pdev,phost->Control.hc_num_in,0,0,0,phost->Control.ep0size);      }break;case ENUM_GET_FULL_DEV_DESC:  /* Get FULL Device Desc 得到整个设备描述符 */if ( USBH_Get_DevDesc(pdev, phost, USB_DEVICE_DESC_SIZE)\== USBH_OK){/* user callback for device descriptor available */phost->usr_cb->DeviceDescAvailable(&phost->device_prop.Dev_Desc);      phost->EnumState = ENUM_SET_ADDR;}break;case ENUM_SET_ADDR: /* 设置地址 set address */if ( USBH_SetAddress(pdev, phost, USBH_DEVICE_ADDRESS) == USBH_OK)  /*#define USBH_DEVICE_ADDRESS 1*/{USB_OTG_BSP_mDelay(2);phost->device_prop.address = USBH_DEVICE_ADDRESS;/* user callback for device address assigned */phost->usr_cb->DeviceAddressAssigned();phost->EnumState = ENUM_GET_CFG_DESC;/* modify control channels to update device address */USBH_Modify_Channel (pdev,phost->Control.hc_num_in,phost->device_prop.address,0,0,0);USBH_Modify_Channel (pdev,phost->Control.hc_num_out,phost->device_prop.address,0,0,0);         }break;case ENUM_GET_CFG_DESC:  /* 得到配置描述符get standard configuration descriptor */if ( USBH_Get_CfgDesc(pdev, phost,USB_CONFIGURATION_DESC_SIZE) == USBH_OK){phost->EnumState = ENUM_GET_FULL_CFG_DESC;}break;case ENUM_GET_FULL_CFG_DESC:  /* get FULL config descriptor (config, interface, endpoints) */if (USBH_Get_CfgDesc(pdev, phost,phost->device_prop.Cfg_Desc.wTotalLength) == USBH_OK){/* User callback for configuration descriptors available */phost->usr_cb->ConfigurationDescAvailable(&phost->device_prop.Cfg_Desc,phost->device_prop.Itf_Desc,phost->device_prop.Ep_Desc[0]);phost->EnumState = ENUM_GET_MFC_STRING_DESC;}break;case ENUM_GET_MFC_STRING_DESC: if (phost->device_prop.Dev_Desc.iManufacturer != 0){ /* 字符串描述符Check that Manufacturer String is available */if ( USBH_Get_StringDesc(pdev,phost,phost->device_prop.Dev_Desc.iManufacturer, Local_Buffer , 0xff) == USBH_OK){/* User callback for Manufacturing string */phost->usr_cb->ManufacturerString(Local_Buffer);phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;}}else{phost->usr_cb->ManufacturerString("N/A");      phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;}break;case ENUM_GET_PRODUCT_STRING_DESC:   if (phost->device_prop.Dev_Desc.iProduct != 0){ /* Check that Product string is available */if ( USBH_Get_StringDesc(pdev,phost,phost->device_prop.Dev_Desc.iProduct, Local_Buffer, 0xff) == USBH_OK){/* User callback for Product string */phost->usr_cb->ProductString(Local_Buffer);phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;}}else{phost->usr_cb->ProductString("N/A");phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;} break;case ENUM_GET_SERIALNUM_STRING_DESC:   if (phost->device_prop.Dev_Desc.iSerialNumber != 0){ /* Check that Serial number string is available */    if ( USBH_Get_StringDesc(pdev, phost,phost->device_prop.Dev_Desc.iSerialNumber, Local_Buffer, 0xff) == USBH_OK){/* User callback for Serial number string */phost->usr_cb->SerialNumString(Local_Buffer);phost->EnumState = ENUM_SET_CONFIGURATION;}}else{phost->usr_cb->SerialNumString("N/A");      phost->EnumState = ENUM_SET_CONFIGURATION;}  break;case ENUM_SET_CONFIGURATION:/* 设置配置请求set configuration  (default config) */if (USBH_SetCfg(pdev, phost,phost->device_prop.Cfg_Desc.bConfigurationValue) == USBH_OK){phost->EnumState = ENUM_DEV_CONFIGURED;}break;case ENUM_DEV_CONFIGURED:/* user callback for enumeration done */Status = USBH_OK;break;default:break;}  return Status;
}

六、 USB枚举后的数据传输过程  以及    四种传输类型

usb 四种传输类型是针对端点而言的,并不是usb整个传输过程为一种传输类型

1、控制传输(Control Transfers):  枚举  

  (一般用于枚举过程端点0,主机给从机发命令或回应状态时,这个过程是随机突发的的,也就是主机随时发命令,从机只能是待命)

2、大容量数据传输 批量传输(Bulk Transfers):       U盘

        大容量传输一般用于非零端点,并且针对大数据传输(如U盘),数据可以占用任意带宽,并容忍延迟 ,并且这个过程也是随机突发的,因为控制权在主机,用户随时要读取设备(u盘)数据,所以这个过程是非周期的

stm32 大容量传输分析

3、同步传输(Isochronous Transfers):    摄像头           

        周期性的,持续性的传输,用于传输与时效相关的信息,并且在数据中保存时间戳的信息 比如(摄像头图像传输)

4、中断传输(Interrupt Transfers):   鼠标键盘

  周期性,低频率,比如hid鼠标键盘,主机是周期性查询端点有没有数据的,只要鼠标有动作,就可以往端点缓存送数据,等到主机查询的时候,数据就会被主机读走)所以在设备初始化的时候要初始化主机查询时间间隔

超时轮询时间间隔在从机端点描述符中获取

stm32中断传输分析

/*主机 usbh_hid_core.c*/static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev , void   *phost)
{、、、、、、switch (HID_Machine.state){、、、、、case HID_GET_DATA: USBH_InterruptReceiveData(pdev, HID_Machine.buff,HID_Machine.length,HID_Machine.hc_num_in);start_toggle = 1; HID_Machine.state = HID_POLL;HID_Machine.timer = HCD_GetCurrentFrame(pdev);break;case HID_POLL: if(( HCD_GetCurrentFrame(pdev) - HID_Machine.timer) >= HID_Machine.poll)//超时轮询{HID_Machine.state = HID_GET_DATA;}else if(HCD_GetURB_State(pdev , HID_Machine.hc_num_in) == URB_DONE){if(start_toggle == 1) /* handle data once */{start_toggle = 0;  HID_Machine.cb->Decode(HID_Machine.buff);}}else if(HCD_GetURB_State(pdev, HID_Machine.hc_num_in) == URB_STALL) /* IN Endpoint Stalled */{/* Issue Clear Feature on interrupt IN endpoint */ if( (USBH_ClrFeature(pdev, pphost,HID_Machine.ep_addr,HID_Machine.hc_num_in)) == USBH_OK){/* Change state to issue next IN token */HID_Machine.state = HID_GET_DATA;}}      break;default:break;}return status;
}

转载于:https://www.cnblogs.com/shenLong1356/p/11287833.html

stm32f4 USB项目开发详解相关推荐

  1. Android USB 开发详解

    Android USB 开发详解 先附上 Android USB 官方文档 Android通过两种模式支持各种 USB 外设和 Android USB 附件(实现Android附件协议的硬件):USB ...

  2. php调用linux摄像头,Linux_Linux中开发USB摄像头驱动详解,USB摄像头以其良好的性能和低 - phpStudy...

    Linux中开发USB摄像头驱动详解 USB摄像头以其良好的性能和低廉的价格得到广泛应用.同时因其灵活.方便的特性,易于集成到嵌入式系统中.但是如果使用现有的符合Video for Linux标准的驱 ...

  3. STM32 之三 标准外设版USB驱动库详解(架构+文件+函数+使用说明+示例程序)

    写在前面 目前,ST的USB驱动有两套,一套是早期的独立版USB驱动,官方培训文档中称为Legacy library:一套为针对其Cube 系列的驱动,根据芯片不同可能有区别,具体见对应芯片的Cube ...

  4. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  5. UML应用开发详解--视频

    UML应用开发详解 地址:http://v.51work6.com/courseInfoRedirect.do?action=courseInfo&courseId=240574 通过本教程, ...

  6. EasyPR中文开源车牌识别系统 开发详解

     在上篇文档中作者已经简单的介绍了EasyPR,现在在本文档中详细的介绍EasyPR的开发过程. 正如淘宝诞生于一个购买来的LAMP系统,EasyPR也有它诞生的原型,起源于CSDN的taotao ...

  7. JMessage Android 端开发详解

    JMessage Android 端开发详解 目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 ...

  8. wpf 客户端【JDAgent桌面助手】开发详解(四) popup控件的win8.0的bug

    目录区域: 业余开发的wpf 客户端终于完工了..晒晒截图 wpf 客户端[JDAgent桌面助手]开发详解-开篇 wpf 客户端[JDAgent桌面助手]详解(一)主窗口 圆形菜单... wpf 客 ...

  9. 《Linux设备驱动开发详解 A》一一2.3 接口与总线

    本节书摘来华章计算机出版社<Linux设备驱动开发详解 A>一书中的第2章,第2.3节,作者:宋宝华 更多章节内容可以访问云栖社区"华章计算机"公众号查看.1 2.3 ...

  10. 基于Java的音频转发服务器_javaCV开发详解之5:录制音频(录制麦克风)到本地文件/流媒体服务器(基于javax.sound、javaCV-FFMPEG)...

    javaCV系列文章: 补充篇: 前言:本篇文章基于javaCV-FFMPEG,关于javaCV官方是没有文档或者api文档可以参考的,所以还有很多地方需要研究: 本章对于ffmpeg的需要有一定了解 ...

最新文章

  1. java操作跨页的word cell,“excle如何打印不出现断行“EXCEL中,如何不跨页断行打印或显示,谢谢...
  2. TensorFlowSharp入门使用C#编写TensorFlow人工智能应用
  3. Spring 自动装配及其注解
  4. 网络推广方案分享网站想要更快的优化到首页的技巧!
  5. prefixspan java_PrefixSpan序列模式挖掘算法
  6. 六年级下册百分数计算题_小学六年级数学期末考,题量较大,出题全面、灵活...
  7. 哈哈哈,程序员没有女朋友的原因,我终于找到了!
  8. sql删除主键_产品经理的第一节SQL课——ID到底是干什么的?!
  9. oracle两表联查分页公式,Oracle中分页查询和联表查询
  10. Unity MRTK RadialView
  11. thinkphp tp 框架如何查看版本
  12. 《Revisiting Pre-trained Models for Chinese Natural Language Processing》(MacBERT)阅读记录
  13. 公网IP地址获取:移动网络IP、Wifi IP
  14. html多重阴影,CSS3多重阴影特效
  15. php生成拟合线,excel拟合曲线怎么做
  16. 开源MySQL数据仓库解决方案:Infobright
  17. chrome设置浏览器网页编码
  18. mysql等保测评命令_安全计算环境-二级等级保护测评指导和自动化脚本
  19. Python 读取.msg文件中的附件和内容
  20. Linux 显示行数 number

热门文章

  1. 土壤数据库一些参数解释和补充说明
  2. 员工转正述职答辩问什么问题_实习期员工转正述职报告
  3. 2021-11-19 工作记录--apiCloud-YDUI下拉框
  4. 2021-09-06 工作记录--YDUI-让弹窗打开后,弹窗下面的页面不可以上下滑动
  5. 9.20残差网络 ResNet
  6. 产品经理需要NPDP证书吗?
  7. Mac下虚拟机win10键盘不兼容解决方案-MS Office Word篇
  8. 用Java代码实现区块链技术
  9. 大学C语言学习笔记(C语言程序设计第五版——谭浩强,翁凯C语言基础教程)基础、算法、程序结构、数组、函数、指针、枚举、结构、联合
  10. 重装服务器系统鼠标键盘用不了,win7重装系统后鼠标键盘不能用怎么办