在嵌入式系统中,异步串行通信接口往往作为标准外设出现在单片机和嵌入式系统中。但是随着个人计算机通用外围设备越来越少地使用串口,串口正在逐渐从个人计算机特别是便携式电脑上消失。于是嵌入式开发人员常常发现自己新买来的计算机上没有串口,或者出现调试现场用户的计算机没有串口的尴尬局面。本文所要实现的USB CDC类,当用户将设备通过USB口连接到个人计算机后,在操作系统中表现为一个串口设备,这意味着USB接口对于传统的串口调试工具和用户基于串口的应用程序是透明的,开发人员完全不用更改PC端的调试和应用程序。
一、USB接口 通用串行总线(Universal Serial Bus USB),是一种快速、灵活的总线接口。与其它通信接口比较,USB接口的最大特点是易于使用,这也是USB的主要设计目标。作为一种高速总线接口,USB适用于多种设备,如数码相机、MP3播放机、高速数据采集设备等。易于使用还表现在USB接口支持热插拔,并且所有的配置过程都由系统自动完成,无需用户干预。USB接口支持1.5Mb/s(低速)、12Mb/s(全速)和高达480Mb/s(USB 2.0规范)的数据传输速率,扣除用于总线状态、控制和错误监测等的数据传输,USB的最大理论传输速率仍达1.2Mb/s或9.6Mb/s,远高于一般的串行总线接口。 USB提供了四中传输方式:控制传输;同步传输;中断传输;批传输。它们在数据格式、传输方向、数据包容量限制、总线访问限制等方面有着各自不同的特征: 控制传输(Control Transfer) 1. 通常用于配置、命令、状态等情形; 2. 其中的设置操作(setup)和状态操作(status)的数据包具有USB定义的结构,因此控制传输只能通过消息管道进行; 3. 支持双向传输; 4. 对与高速设备,允许数据包最大容量为8,16,32或64字节,对于低速设备只有8字节一种选择; 5. 端点不能指定总线访问的频率和占用总线的时间,USB系统软件会做出限制; 6. 具有数据传输保证,在必要时可以重试。 同步传输(Isochronous Transfer) 1. 是一种周期的、连续的传输方式,通常用于与时间有密切关系的信息的传输; 2. 数据没有USB定义的结构(数据流管道); 3. 单向传输,如果一个外设需要双向传输,则必须使用另一个端点; 4. 只能用于高速设备,数据包的最大容量可以从0到1023个字节; 5. 具有带宽保证,并且保持数据传输的速率恒定(每个同步管道每帧传输一个数据包); 6. 没有数据重发机制,要求具有一定的容错性; 7. 与中断方式一起,占用总线的时间不得超过一帧的90%。 中断传输(Interrupt Transfer) 1. 用于非周期的、自然发生的、数据量很小的信息的传输,如键盘、鼠标等。 2. 数据没有USB定义的结构(数据流管道); 3. 只有输入这一种传输方式(即外设到主机); 4. 对于高速设备,允许数据包最大容量为小于或等于64字节,对于低速设备只能小于或等于8字节; 5. 具有最大服务周期保证,即在规定时间内保证有一次数据传输; 6. 与同步方式一起,占用总线的时间不得超过一帧的90%; 7. 具有数据传输保证,在不要时可以重试。 批传输(Bulk Transfer) 1. 用于大量的、对时间没有要求的数据传输; 2. 数据没有USB定义的结构(数据流管道); 3. 单向传输,如果一个外设需要双向传输,则必须使用另一个端点; 4. 只能用于高速设备,允许数据包最大容量为8,16,32或64字节; 5. 没有带宽的保证,只要有总线空闲,就允许传输数据(优先级小于控制传输); 6. 具有数据传输保证,在必要时可以重试,以保证数据的准确性。 本文将要介绍的CDC是基于第一种方式实现,同时,基于CDC类实现的USB虚拟串口的通信方式,不但省去了开发USB驱动的麻烦,更重要的是解决了因主机(通常为PC)设备与便携式设备因无标准串口而无法通信的尴尬,从而为主机设备与便携式设备通信提供了一种更好的解决方法。下面笔者将详细介绍其实现方法。
二、硬件连接
图1 USB连接原理图
USB接口的硬件连接原理图如:图1所示,读者在参考时,只需按图-1中所示连接即可。其中有几点需要说明以下,以便读者理解。 (1)XS2扁平座上的4个与USB有关的信号,在图-1中给出:VBUS向外提供+5V电源,DGND是地线,DDP(D+)和DDM(D-)是差分数据线对。这4个信号是对外的接口,而此扁平座除了USB信号线接口,还包括了其他信号接口如:JTAG调试、RS232等。为此,笔者为读者提供了一种简便的调试方法:读者可以找一根USB线,将B型插头端拆开,将看到红(VBUS)、白(D-)、绿(D+)、黑(GND)4条线,将这4条线分别一一对应与XS2上的4个信号线相连接,并将A型插头插到PC端A型插座即可。当然,读者也可以在实际的应用中,将上面提到的XS2上的相关USB信号线做成标准的B型插座。 (2)在图-1所示的图中,我们可以看到DDP(D+)信号线上连接了1.5K的上拉电阻,在ATMEL的参考原理图上,其是连接在一I/O口上,通过配置I/0口来控制的。而通过笔者实践,直接将其连接到3.3V上也是可行的。其主要作用是为PNP信号识别。
三、软件实现 (1)首先我们先看CDC类的设备描述符,详细的描述读者可以参看USB协议规范,在此笔者直接给出其描述文件,并做简要的说明。 const char devDescriptor[] = { /* 设备描述 */ 0x12, // 长度 0x01, // 描述类型 0x10, // bcdUSBL 0x01, // 0x02, //CDC类 0x00, // CDC子类 0x00, // CDC设备协议 0x08, //包最大字节数 0xEB, // idVendorL 0x03, // 0x24, //厂商代码低位 0x61, //厂商代码高位 0x10, // 0x01, // 0x00, // 0x00, // 0x00, // 0x01 // }; 在此设备描述符里,需要注意厂商代码,因为,在USB设备枚举时,需要根据此来选择适合设备自身的驱动程序,读者不必担心,此驱动Atmel公司已经提供,后面将会介绍。 (2)USB设备的初始化函数,主要设置USB设备需要的时钟、CDC结构初始化等工作。 void AT91F_USB_Open(void) { AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ; // 使能 48MHz USB 时钟UDPCK 和系统外部USB时钟 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); // CDC结构初始化 AT91F_CDC_Open(&pCDC, AT91C_BASE_UDP); }
|