通用串行总线(Universal Serial Bus)是连接计算机系统与外部设备的一种串行总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通信产品。USB总线是最复杂的总线之一,但其广泛使用。本文首先直接使用USB相关的驱动的应用,后面再具体开始编程做自己的USB驱动程序。
USB1.0最早是在1996年出现,速度只有1.5Mb/s,后经多次发展升级,目前使用广泛的是USB2.0以及USB3.0,最新的USB3.1与USB3.2也在普及中,各版本性能如下表所示:
USB版本 |
出现年代 |
传输速度 |
驱动能力 |
USB1.0 |
1996 |
1.5Mbps |
500mA |
USB1.1 |
1998 |
12Mbps |
500mA |
USB2.0 |
2000 |
480Mbps |
500mA |
USB3.0 |
2008 |
5Gbps |
900mA |
USB3.1 |
2013 |
10Gbps |
Type-A 900mA Type-C 100W |
USB2.0及以下版本采用四线通信,如图1-1所示:
其中ID数据线没有画出,只有在OTG功能中才会使用ID这个信号。USB电缆的4根线在USB接口中有固定不变的数字编号以及不同的颜色,这位电缆的识别和使用提供了方便,下表列出了这些数字和颜色规定。
编号 |
信号 |
电缆颜色 |
1 |
Vbus |
红色 |
2 |
D- |
白色 |
3 |
D+ |
绿色 |
4 |
GND |
黑色 |
USB3.0向下兼容USB2.0所需要的Vbus,D-,D+和GND四个引脚外,还新增了两组差分导线,加上一组屏蔽线。新增的双差分线用于超速数据传输,新增的屏蔽线作为屏蔽线终端,用于处理信号中断和电子干扰。USB 3.0 Standard-A引脚分配如下:
其中ID数据线没有画出,只有在OTG功能中才会使用ID这个信号。USB电缆的4根线在USB接口中有固定不变的数字编号以及不同的颜色,这位电缆的识别和使用提供了方便,下表列出了这些数字和颜色规定。
编号 |
信号 |
电缆颜色 |
1 |
Vbus |
红色 |
2 |
D- |
白色 |
3 |
D+ |
绿色 |
4 |
GND |
黑色 |
USB3.0向下兼容USB2.0所需要的Vbus,D-,D+和GND四个引脚外,还新增了两组差分导线,加上一组屏蔽线。新增的双差分线用于超速数据传输,新增的屏蔽线作为屏蔽线终端,用于处理信号中断和电子干扰。USB 3.0 Standard-A引脚分配如下:
引脚编号 |
信号 |
描述 |
插合顺序 |
1 |
Vbus |
Power |
Second |
2 |
D- |
USB2.0 differential pair |
Third |
3 |
D+ |
||
4 |
GND |
Ground for power return |
Second |
5 |
StdA_SSRX- |
Super speed receiver differential pair |
Last |
6 |
StdA_SSRX+ |
||
7 |
GND_DRAIN |
Ground for signal return |
|
8 |
StdA_SSTX- |
Super speed receiver differential pair |
|
9 |
StdA_SSTX+ |
||
Shell |
Shield |
Connector metal shell |
First |
Linux-USB Gadget驱动框架实现了USB协议定义的设备端的软件功能。Gadget框架提出了一套标准API,在底层,USB设备控制器(USB DeviceController,UDC)驱动则实现这一套API,不同的UDC需要不同的驱动,基于API,Gadget驱动实现了一套硬件无关的功能,这基本可以对应到USB协议里的各种USB Class。
基于底层提供的资源,Gadget驱动可以运行在各种硬件平台上。重要的驱动有:
Gadget Zero,类似于dummyhcd,该驱动用于测试udc驱动。它会帮助您通过USB-IF测试。
Ethernet over USB,该驱动模拟以太网网口,它支持多种运行方式:
CDC Ethernet: usb规范规定的CommunicationsDevice Class “Ethernet Model” protocol。
CDC Subset:对硬件要求最低的一种方式,主要是 Linux 主机支持该方式。
RNDIS:微软公司对CDCEthernet的变种实现。
File-backed Storage Gadget最常见的U盘功能实现。
Serial Gadget实现,包括:
Generic Serial实现(只需要Bulk-in/Bulk-out端点+ep0)
CDC ACM规范实现。
Gadget Filesystem,将GadgetAPI接口暴露给应用层,以便在应用层实现user modedriver。
MIDI: 暴露ALSA接口,提供recording以及playback功能。
ZYNQ7000中有两个USB外设,它们都可以当做OTG功能使用,为了使其变成可以虚拟串口或U盘等USB从设备,需要将USB配置为从设备。
Linux内核提供了Gadget模块,该模块提供了USB的许多通用功能,包括虚拟串口,大容量存储设备等功能。在内核编译时配置其为编译成模块。
在内核文件路径下make menuconfig后,配置选项:
Device Drivers --->
[*]USB support --->
[*]USB Gadget Support --->
[M]USB Gadget Drivers
...
[M]Serial Gadget(with CDC ACM and CDC OBEX support)
保存退出后,编译内核,在/drivers/usb/gadget目录下会生成以下驱动文件:
g_serial.ko, libcomposite.ko, usb_f_acm.ko, usb_f_obex.ko, usb_f_serial.ko, u_serial.ko.
配置设备树,设置USB0为从设备模式,将原来的dr_mode="host"更改为:
dr_mode="peripheral":
&usb0 {
status = "okay";
dr_mode = "peripheral";
phy_type = "ulpi";
};
生成新的设备树devicetree.dtb文件。
将编译好的内核,设备树文件放入SD卡,并启动Linux,按顺序加载前面生成的驱动模块:
Z-turn# insmod u_serial.ko
Z-turn# insmod libcomposite.ko
Z-turn# insmod usb_f_serial.ko
Z-turn# insmod usb_f_obex.ko
Z-turn# insmod usb_f_acm.ko
Z-turn# insmod g_serial.ko
g_serial gadget: Gadget Serial v2.4
g_serial gadget: g_serial ready
zynq-udc: bind to driver g_serial
Z-turn# g_serial gadget: high-speed config #2: CDC ACM config
g_serial gadget: high-speed config #2: CDC ACM config
输出上述信息表示加载模块成功。此时打开设备文件发现多了/dev/ttyGS0设备,这个就是虚拟的串口设备。连接USB数据线到电脑,发现设备管理器中增加了一个串口设备(ELMO GMAS(COM14))。WIN7和WIN10会自动加载基于udc标准的串口驱动,即免驱。
打开串口调试助手,在ZYNQ终端中输入发送测试命令:
Z-turn# echo hello > /dev/ttyGS0
在串口调试助手中可以收到hello\r\n
在ZYNQ终端输入串口接收命令:
Z-turn# cat /dev/ttyGS0
在串口调试助手中输入:hello\n,则ZYNQ终端中可以收到hello。
注:在终端中发送与接收串口数据都是以'\n'为终止条件,即发送的数据会追加'\n',接收的数据必须在收到'\n'时回显。
在调试Linux系统时,我们经常需要修改SD卡中的文件,更新文件系统或者Linux内核、设备树等文件,需要实现通过USB数据线与PC连接,作为PC的存储设备,PC可以直接拷贝文件到开发板中,或者把开发板中的文件通过USB数据线拷贝到PC端,实现数据交互。本文办卡采用Linux3.15内核,ZYNQ7010处理器。
在内核文件路径下make menuconfig后,配置选项:
Device Drivers --->
[*]USB support --->
[*]USB Gadget Support --->
[M]USB Gadget Drivers
...
[M]Gadget Filesystem
[M]Mass Storage Gadget
编译内核后,在/drivers/usb/gadget中生成了g_mass_storage.ko文件,把这个文件复制到开发板中。
在嵌入式Linux系统中,SD卡在系统中识别为/dev/mmcblk0,如果有多个分区则每个分区分别是/dev/mmcblk0p1,/dev/mmcblk0p2等,将SD卡目录挂载到PC中进行读写的方法如下:
在终端中执行命令:
Z-turn# modprobe g_mass_storage file=/dev/mmcblk0 removable=1
该命令加载了gadget msc驱动,传递SD卡位模块参数。连接USB数据线到PC,这时在PC端识别了SD卡所有分区,FAT32格式的分区可以显示内容,对于SD卡的ext4,ext3等文件系统无法在windows中显示,只显示一个盘符。此时可以通过USB数据线读写SD卡了。
如果只需要挂载一个分区,修改file参数即可:
Z-turn# modprobe g_mass_storage file=/dev/mmcblk0p1 removable=1
首先创建一个50M的内存文件:
Z-turn# dd if=/dev/zero of=/dev/50M bs=1M count=50
加载Gadget相关的模块:
Z-turn# modprobe g_mass_storage file=/dev/50M removable=1
加载模块后在windows中弹出是否格式化新增的盘符,格式化为FAT格式,往该盘符中添加文件,在Linux中将/dev/50M挂载到/mnt目录下,查看/mnt目录可以发现添加的文件在其中。
需要注意的是,该文件系统是RAMDISK文件系统,系统重启后所有的数据内容会丢失。
使用USB来共享网络可以不需要连接路由器,减少开发设备。
配置内核:
Device Drivers --->
[*]USB support --->
[*]USB Gadget Support --->
[M]USB Gadget Drivers
...
[M]Ethernet Gadget(with CDC Ethernet support)
[*] RNDIS support
如下图所示:
还需要配置RNDIS模块,其位于:
Device Driver--->
Network device support
USB Network Adapters
[*]Multi-purpose USB Networking Framework
HOST for RNDIS and ActiveSync devices
编译内核后,rndis_hos.ko的路径为/drivers/net/usb/rndis_host.ko