本文摘自ST官网的“USB CDC类入门培训”。整理的内容是我能够看得懂的,认为比较实用的,记录下来,以便以后查阅,同时也把原文档中的笔误给更正了一下。若要看更详细的可以去ST技术文档中查看,链接为:
http://bbs.21ic.com/forum.php?mod=viewthread&tid=726814&page=1&extra=#pid4225064

1 USB CDC类基础理论知识介绍

1.1 USB CDC类、USB2.0标准与PSTN之间的关系

CDC(Communication Device Class)类是USB2.0标准下的一个子类,定义了通信相关设备的抽象集合。它与USB2.0标准以及其下的子类的相互关系如下图所示:

如上图,USB2.0标准下定义了很多子类,有音频类,CDC类,HID,打印,大容量存储类,HUB,智能卡等等,这些在usb.org官网上有具体的定义,这里主要介绍通信类CDC。

1.2 从一个具体的CDC类通信数据说起


如上图,USB CDC类的通信部分主要包含三部分:枚举过程、虚拟串口操作和数据通信。其中虚拟串口操作部分并不一定强制需要,因为若跳过这些虚拟串口的操作,实际上USB依然是可以通信的,这也就是为什么上图中,在操作虚拟串口之前会有两条数据通信的数据。之所以会有虚拟串口操作,主要是我们通常使用PC作为Host端,在PC端使用一个串口工具来与其进行通信,PC端的对应驱动将其虚拟成一个普通串口,这样一来,可以方便PC端软件通过操作串口的方式来与其进行通信,但实际上,Host端与Device端物理上是通过USB总线来进行通信的,与串口没有关系,这一虚拟化过程,起决定性作用的是对应驱动,包含如何将每一条具体的虚拟串口操作对应到实际上的USB操作。需要注意的是,Host端与Device端的USB通信速率并不受所谓的串口波特率影响,它就是标准的USB2.0全速(12Mbps)速度,实际速率取决于总线的实际使用率、驱动访问USB外设有效速率(两边)以及外部环境对通信本身造成的干扰率等因素组成。

1.3 CDC类设备枚举过程

CDC类设备与其他标准USB设备枚举过程的并没有什么特殊的地方。在设备描述符内可以使用DeviceClass=0x00, SubClass=0x00, Protocol=0x00 表示此类信息在接口描述符内给出;或者也可以使用0x02,0x00,0x00;来表明该设备为CDC类设备。或者使用0xef, 0x02,0x01表示当前为复合设备。
CDC类设备在枚举过程中最主要的信息存储在配置描述符内:

如上图所示,CDC类的配置描述符一般包含两个接口:一个控制接口(Interface 0),另外一个是数据接口(Interface 1), 除此之外,还有一个虚线指向的IAD(Interface Association Description),表示这个是可选的,得根据实际情况来确定其是否真实存在。
在ST给出的CDC例程中,主要是使用SetLineCoding指令来设置和修改虚拟串口的波特率,使用GetLineCoding来获取当前波特率,使用SetControlLineState来打开或关闭串口,这种操作是在Host端CDC驱动来具体映射实现的, Device端收到控制指令可以处理也可以不处理,用CubeMx自动生成的CDC类代码对接收到的任何控制指令到没有做任何处理,如果需要的话,用户可按应用的需要来处理。

2 CDC类软件框架介绍

2.1 CDC软件框架简介


如上图所示,黄色USB Device Core部分为USB设备库文件,属于中间件,它为USB协议栈的核心源文件,一般不需要修改:

USB Device Core中,Log/debug为打印/调试开关;
core为USB设备核心;
USB request中定义了枚举过程中各种标准请求的处理;
I/O request为底层针对USB通信接口的封装。

黄色USB Device Class部分为USB类文件,也属于中间件,USB设备库,目前ST DEMO中支持的类有HID, Customer HID, CDC, MSC, DFU, Audio, ST提供了这些类的源码框架,其他的Class或者是复合设备需要自己根据实际需求情况进行扩展或定制。如果用户需求只是需要一个标准类,比如CDC通信,那么最好就使用现成的代码,不需要做任何修改就可以实现这个CDC类通信的功能。
蓝色USB Device HAL Driver为HAL库部分,是对USB外设接口的封装,属于底层驱动,不需要修改,它分为PCD和LL Driver,PCD处于LL Driver之上。
洋红色USB Device Configuration为USB配置封装,位于USB底层HAL层驱动与中间件USB协议栈之间,一方面向上层(USB设备库)提供各种操作调用接口,另一方面,向底层USB驱动提供各种回调接口。正是由于它的存在,使得USB协议栈(USB设备库)与底层硬件完全分离,从而使USB设备库具有更加兼容所有STM32的通用性。USB Device Configuration为开放给用户的源文件,用户可以根据自己的某些特殊需要进行修改,也可以使用默认的源文件,假如没有任何特殊要求的话,我们使用默认即可。
Application为应用层,USB Device Class有可能将自己对应该的操作接口封装在一个操作数据结构中,由应用来具体实现这些操作,在系统初始化时,由应用将已经定义好的操作接口注册到对应的USB类中,比如usbd_cdc_if, 就这样,使得应用层的应用代码与属于中间件层的USB协议栈分离。同时,USB协议栈会将一些字符串描述符放到APP中,当USB初始化时将这些已经定义好的字符串通过指针初始化到USB协议栈中,以便后续需要时获取。

2.2 工程源码文件与软件框架的对应关系

2.3 USBD内核与USBD_CDC的关系

2.1节中,提到过ST官方Cube库中提供的官方USB协议栈,主要是包含了USBD内核与USB各种类。USBD内核一般是固定的,用户一般不需要修改,但USBD类,如果用户需要修改或者扩展,比如复合设备或者用户自定义设备,还有就是,ST目前官方提供的USB设备类的DEMO程序并没有囊括所有USB类,因此,若用户需要实现这些官方提供DEMO之外的USB类时,则用户需要根据自己的需要来定制化自己的USB类。
ST提供的USB协议栈中已经有USBD内核,且这个内核源文件一般是不需要修改的,我们需要自定义这么一个USB类,我们首先得知道要自定义的USB类是如何与USBD内核打交道的。
USB协议栈将所有USB类都抽象成一个数据结构:USBD_ClassTypeDef,其定义如下所示:

这个结构体是一个抽象类,定义了一些虚拟函数,比如初始化,反初始化,类请求指令处理函数,端点0发送完成,端点0接收处理,数据发送完成,数据接收处理,SOF中断处理,同步传输发送未完成,同步传输接收未完成处理等等;用户在实现自己具体的USB类的时候需要将它实例化,USBD_ClassTypeDef结构体是USBD内核提供给外部定义一个USB设备类的窗口,而USB类文件(如usbd_cdc.c)实际就是实现这个结构体具体实例化的过程。最后将这个具体实例化的对象注册到USBD内核的同时, USBD内核与USBD类也进行了关联。

可以这么说,USBD内核与USBD类之间的纽带就是USBD_ClassType这个结构体
下面我们来看看ST提供的CDC DEMO中具体CDC类:

这个就是具体一个CDC类实例化的对象,上层应用通过USBD_RegisterClass函数,将此对象注册到usbd内核 :

它主要在usbd_cdc.c源文件中实现它的各个成员函数,当然,usbd_cdc.c源文件中,除了这些CDC类成员函数的具体实现之外,还包含其他一些对上层提供的接口,比如发送USBD_CDC_TransmitPacket, USBD_CDC_RegisterInterface,上层应用通过调用USBD_CDC_TransmitPacket来发送数据,通过USBD_CDC_RegisterInterface来注册操作接口,这也是我们接下来将要讲述的内容。

2.4 USBD_CDC与USBD_CDC_If的关系

讲完了USBD内核与USBD_CDC的关系,接下来讲USBD_CDC与上层应用是如何对接的。为了将USBD_CDC与上层应用层完全分离出来,类似USBD内核与USBD_CDC类完全分离一般,USBD_CDC类对上层同样提供一个抽象的数据操作接口USBD_CDC_If结构体:

如上所示,如何处理来自Host端发送过来的控制指令和数据,完全是由应用层来决定,具体实现是应用层将此抽象的操作接口具体实例化,并注册到USBD_CDC类对象中:

如上图所示,通过引入USBD_CDC_If这么一个数据结构,就实现了USBD_CDC类与应用层的完全分离。USBD_CDC_If的具体实例化对象如下:

源文件usbd_cdc_if.c就是实现这些成员函数的过程,除此之外,还包含发送接口。最后应用层通过调用USBD_CDC_RegisterInterface函数将此操作接口注册到USBD_CDC类中 :

2.5 应用接口

初始化 :

如上图所示 :
初始化分4步:
1> 初始化USBD内核
2> 给USBD内核注册USBD_CDC类
3> 给USBD_CDC类注册USBD_CDC_If接口
4> 正式启动USBD

  • 发送数据:
    uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
  • 接收回调处理:
    static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len);
  • 接收控制指令处理 :
    static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length);

3 实践动手部分

3.1 实验环境及STM32F072-Discovery板简介

硬件准备:

  • STM32F072 Discovery板一块
  • Mini USB线两根
  • PC一台

软件准备:

  • IAR V6.7.0 或者以上版本
  • STM32CubeF0 V1.7.0
  • STM32CubeMX V4.19
  • SSCOM串口工具
  • VCP虚拟串口驱动

3.2 使用STM32CubeMx制作CDC工程


使用内部48M的HSI48 RC作为时钟源



最终生成的代码工程与USB CDC类软件框架的对应关系:

3.3 添加测试代码

为了更好的验证通信,我们需要添加点测试代码:

在接收回调中,我们将接收到的数据转给HandleReceiveData函数处理:

而在HandleReceiveData函数中我们将收到的数据原样返回给Host端,这样一来,Host端的串口工具将发送什么就将收到什么。

另一方面,我们定义了一全局变量StartFlag,它用来标志是否循环从Device端向Host端主动发送数据,其值由外部按键控制。然后在Main函数内的while(1)循环内添加如下测试代码:

只要StartFlag标志为1,在枚举结束后则不断向Host端发送数据。

3.4 验证结果

在编译完并将代码烧录进MCU后,我们首先验证PC端通过串口工具发送数据的情况:

如上图所示,串口工具发送63个字节到Device端后,能够接收到从Device端返回到的一模一样的数据,这说明发送与接收都是正常的。

在按下用户按键后,串口工具能够无限收到来自Device端的数据。

收发同时进行也是正常的。至此,USB CDC设备端的收发验证均正常。

3.5 注意事项

  • STM32CubeMx默认生成的工程在发送64整数倍数据的时候PC端收不到,这个问题可以参考以下两个链接:
    http://blog.csdn.net/flydream0/article/details/53205286
    http://bbs.21ic.com/icview-1708972-1-1.html

  • CDC device端若无限向PC端发送数据,若PC端没有及时读走数据,导致PC端接收缓存爆满,此时PC端回复NACK,此时会导致发送返回BUSY。

USB CDC从理论到实践相关推荐

  1. delphi usb 读写_写作论语 | 崔嵘:写我所读——国外整本书阅读中读写结合的理论与实践(上)...

    崔嵘简介 崔嵘,博士,首都师范大学初等教育学院副教授.硕士研究生导师, 澳大利亚弗林德斯大学教育学院客座副教授,美国明尼苏达大学访问学者,北京市语文现代化研究会秘书长.全国名师工作室联盟学术委员会学术 ...

  2. 干货 | 清华大学郑方:语音技术用于身份认证的理论与实践

    本讲座选自清华大学语音和语言技术中心主任郑方教授近期于清华大数据"技术·前沿"系列讲座上所做的题为<语音技术用于身份认证的理论与实践>的演讲. 以下为演讲的主要内容: ...

  3. [转]Android 常见安全漏洞修复理论与实践

    前言 前段时间公司对应用在爱加密上进行了安全扫描,本文将基于爱加密的漏洞分析报告,针对部分内容,介绍理论修复实践 最小化特权准则概念介绍 最小化特权准则,即指组件只能供自身应用调用,尽可能禁止其他应用 ...

  4. ARM NEON指令集优化理论与实践

    ARM NEON指令集优化理论与实践 一.简介 NEON就是一种基于SIMD思想的ARM技术,相比于ARMv6或之前的架构,NEON结合了64-bit和128-bit的SIMD指令集,提供128-bi ...

  5. CPU消耗,跟踪定位理论与实践

    CPU消耗,跟踪定位理论与实践 一.性能指标之资源指标定位方案 1.打tprof报告方法 抓取perfpmr文件 60秒. perfpmr.sh 60 从结果文件中取出tprof.sum 或直接抓取t ...

  6. UI设计培训之如何将设计理论与实践相结合

    学习UI设计理论知识与实践技术都是要有的,很多人都不爱去听理论知识,这对以后的工作是没有任何帮助的,只有将设计理论与实践相结合才能帮助到自己,那么如何将设计理论与实践相结合?来看看本期下面的详细介绍. ...

  7. Java 理论与实践: 非阻塞算法简介——看吧,没有锁定!(转载)

    简介: Java™ 5.0 第一次让使用 Java 语言开发非阻塞算法成为可能,java.util.concurrent 包充分地利用了这个功能.非阻塞算法属于并发算法,它们可以安全地派生它们的线程, ...

  8. Microsoft NLayerApp案例理论与实践 - 项目简“.NET研究”介与环境搭建

    项目简介 Microsoft – Spain团队有一个很不错的面向领域多层分布式项目案例:Microsoft – Domain Oriented N-Layered .NET 4.0 App Samp ...

  9. 重磅直播|立体视觉之立体匹配理论与实践​

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 大家好,本公众号现已开启线上视频公开课,主讲人通过B站直播间,对3D视觉领域相关知识点进行讲解,并在微 ...

最新文章

  1. 整合quickx到普通cocos2dx
  2. 【Android View事件分发机制】原理
  3. 机器学习需要理解的五个基本概念
  4. c语言定义链式队列用菜单,数据结构之---C语言实现链式队列
  5. 2019年末逆向复习系列之努比亚Cookie生成逆向分析
  6. “钉钉打卡神器”开发者被判五年半!
  7. Linux系统:centos7下搭建ZooKeeper3.4中间件,常用命令总结
  8. 【华为云技术分享】云图说|应用编排服务AOS,助力应用上云自动化
  9. vue 获取元素高度
  10. the enigma x64 6.7_颜值不输宝马,零百加速6.7秒,国产最强轿跑SUV就是它了
  11. Software--IoC 依赖倒置 控制反转
  12. MATLAB数字图像处理实验题目要求
  13. Python自动发送微信消息
  14. 【Spring系列】 Ioc 实现原理,Spring获取bean的方式,创建对象的方式和懒加载
  15. SpaceSyntax【空间句法】之DepthMapX学习:第二篇 输出了什么东西 与 核心概念
  16. iOS 打开第三方应用
  17. CTF---Web入门第七题 猫抓老鼠
  18. javascript 自己主动绑定JS callback 的方法函数
  19. catalog start with
  20. C# 网络爬虫+HtmlAgilityPack+Xpath+爬虫工具类的封装的使用

热门文章

  1. JVM内存模型总结,有各版本JDK对比、有元空间OOM监控案例、有Java版虚拟机,综合学习更容易!
  2. JavaScript谬论体系
  3. Mysql数据库的几个特点
  4. 用迅雷快速下载LOL
  5. 软考高项学习教程【第一阶段】:第6章-IT服务管理知识产权信息系统工程监理
  6. sklearn神经网络分类
  7. 在线阅读计算机基础,计算机基础知识点.docx
  8. 静态程序分析(一)—— 大纲思维导图与内容介绍
  9. 干掉activity、flowable,阿里开源工作流引擎compileflow使用指南
  10. 《软件测试的艺术》第四章 测试用例的设计