如未特别说明, 现阶段学习的usb主要是指usb从机/设备.
简单阅读过一些介绍USB应用基础和协议栈的文档之后, 发现协议栈的内容主要是约定要怎样怎样, 数据包格式啊, 通信机制啊. 但是, 真正落实到MCU上的程序设计时, 首要要搞清楚的是, 哪些工作是由硬件完成的, 那些工作是由软件完成的. 需要软件完成的部分, 可以参考已有的很多优秀且开源的usb协议栈程序, 作为用户来讲, 这部分代码就不需要从头设计编写了, 直接复用就好. 而硬件部分在各个芯片上各有不同, 而当我们需要某个特定的芯片平台上使用usb功能时, 就需要使用具体的usb控制器想方设法满足上层协议栈软件对数据和事件响应的需求, 完成usb协议最终栈的移植.
这里以复杂度相当的文件系统fatfs和以太网协议栈lwip作为类比, 用户在移植时, 只要实现底层简单的读写操作, 并嵌入到协议栈的底层函数中, 中间关于协议栈的复杂机制对于大多数用户来讲都是黑盒子, 用户直接调用协议栈的应用层API就能使用. usb相对于这些协议栈来说, 在底层也比较简单, 但需要明确搞清楚对硬件的需求. 作为一个通信类的协议栈, usb协议栈的基本操作就是传数, 全部数据都是通过"端点"传输的, 而端点在硬件上就是一段内存的缓冲区, 可以向其中写数据(发数), 也可以从中读数据(收数). 另外, usb通信过程中还有一些事件告诉usb协议栈需要分情况处理, 这些事件在硬件上反应在usb的通信包, 有些集成度比较高的usb控制器模块简化了软件判断的工作, 能够使用硬件电路自动检测到这些特殊的通信包, 然后在寄存器上通过一个状态标志位告诉软件, 这样usb的软件部分只要安心处理有效数据的收发就好.
但usb相对于fatfs和lwip相对难学一点的主要原因在于:
usb从机开发使用典型的从机开发模型. 基本的usb应用是从机部分, 整个通信过程都是受主机控制, 用户需要编程的从机是需要配合主机进行通信, 主动权不在用户手里, 说白了, 不是平时调程序那样, 想走就走, 想停就停. 这里的应对思路是, 就是要用通信系统的从机开发模型考虑usb的开发过程. 在通信系统的从机开发模型中, 从机不会主动启动通信, 都是被动地在任何可能的时间点接受主机的触发. 这就意味着, 所有的程序执行过程都需要从中断开始. 这样看, 就限定了usb从机编程的基本框架, 对于初学者来说, 至少在阅读现有的usb工程时, 可以找到处理usb实践的入口了. 相似的编程模型可以参考I2C从机.
从机模型通常只能等待主机读或者主机写, 比如u盘设备. 但例如usb键盘这样需要上传给主机数据的设备, 怎样主动向主机发送数据呢? 在usb通信机制中, 至少有两种方法可以处理类似的情况: usb主机会每隔1ms向总线上发一次问询, 问问有没有从机要上报数据, 没错, 这就是轮询; 另一种是远程唤醒, 这是用在低功耗场景中的, 可以以后再看. 所以说, 大体上看, 整个usb系统还是使用轮询机制从从机读数或者写数的, 但具体再usb从机的设计上, 考虑到同时还要执行除usb之外其他的工作, 因此还是将相应主机操作的程序全部放在中断中. 更进一步, 在有些优化的usb协议栈中, 还将usb中断服务程序和多线程结合起来, 紧要的回复先在中断服务程序中进行, 不紧要的处理通过标志位传递给任务中, 让任务慢慢去处理.
usb协议栈可以支持多种设备的灵活性. usb的功能不向文件系统那么单一, 它需要支持多种多样的设备, 可以是输入设备的键盘或鼠标, 还可以是输出设备的U盘. usb是通过各种各样的"描述符"让PC识别成不同设备的, 这就是usb的"枚举过程". 其实这个"枚举过程"并没有那么神秘, 在本质上还是传数而已. 我们很多人有使用过LCD屏的经验, 当使用LCD屏之前需要配置一些参数到LCD屏的控制器中, 才能让LCD屏正常工作. usb的"枚举过程"就是向主机初始化的过程, 从机在初始化过程中向主机发送一些信息(或者按照格式填写登记表格), 让主机识别自己, 对应地以特定的模式与本机协同工作. 在初始化到不同的工作模式后, 对应的数据包格式也各自不同. 这些"表格"的格式都有模板, 拿现有的样例程序结合usb协议栈的各种选项表改改, 就能定制自己需要的功能了.
这些就是嵌入式开发者学习usb的基本思路.
建议的学习方式是:
不要一开始就啃usb协议栈, 可以先了解一些usb的基本概念, 科普一下.
然后仔细看看自己选用硬件平台上的usb控制器有什么功能, 能够实现哪些基本操作.
找一款自己倾向的usb协议栈实现代码, 作为usb纯软件部分的框架(这部分代码没必要自己再敲一遍), 最好应用例程比较丰富, 便于自己后期修改.
想方设法将自己的硬件平台同软件组件对接上.
usb应用层的部分与硬件完全无关, 可以用选用的usb协议栈自带的程序验证一下. 大多数情况下, 到这一步就能够满足绝大多数初学者的应用需求了, 例如hid鼠标键盘, cdc串口, msd大容量存储设备等, 再复杂一点就是复合类, 也有不少usb协议栈的实现提供了样例程序.
阅读自己移植好的代码, 再看usb协议栈的文档, 尝试定制自己的功能. 例如, 改改设备设备的字符串, 或者定制更复杂的设备等等.
End
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/suyong_yq/article/details/104302876
|
|