当前位置:首页 期刊杂志

基于ARM7TDMI的OHCI控制器驱动程序设计

时间:2024-07-28

裴晓勇,李 俨,赵凯瑞

(西北工业大学自动化学院,西安710072)

1 引言

USB设备结构简单,通用性好,因而得到了大规模使用。不仅在PC机上,越来越多的嵌入式应用中也提到了USB。在很多的嵌入式应用中,需要实现USB主机控制器的功能。OHCI(Open Host Control Interface)是Compaq,Microsoft等公司提出的一个USB主机控制器接口规范,广泛应用于嵌入式设备中。目前有关OHCI主机驱动程序的开发,大多数是基于操作系统(Linux或者WinCE)的,参考文献[3,5-6]就是典型实例。由于这种 OHCI驱动程序过于复杂和抽象,而且依赖于特定的操作系统环境,在无操作系统平台上的移植与使用有一定的困难。同时,越来越多的OHCI控制器出现在不能移植复杂操作系统的硬件平台上,比如LCP2478。本文以LPC2478为硬件平台(ARM7TDMI内核),以适用于无操作系统或者轻量级的操作系统(μC/OS-II,freeRTOS)环境为目的,实现了简单而且可靠的基于OHCI的USB主机驱动。

首先介绍USB主机控制器的体系结构,然后着重介绍了OHCI规范的主要细节,最后实现了主机驱动程序,并对所实现的驱动程序进行了验证。

2 USB主控制器体系介绍

USB设备结构简单,通用性好,大量用于电子设备中。在数据采集系统中,可以通过USB总线将采集到的数据保存到U盘,移动硬盘等大容量存储设备中。在此过程中,需要USB主机控制器的参与,才能将数据从主机传输到USB存储设备中。在USB2.0规范中定义了USB主机控制器的体系结构,USB主机控制器负责连接USB设备和上位机。当有USB设备插入USB主机控制器的时候,主机控制器会将此信息通过中断的方式告知上位机;上位机与USB设备的数据交互最终也必须通过USB主机控制器来进行。USB主机控制器是连接上位机控制器内核和USB设备的必要介质。

USB主控制器的逻辑结构如图1所示。

图1 USB主机的软硬件体系结构

HC(Host Controler)是USB主机系统的硬件核心,它位于USB主机协议栈中最低层。HC负责物理和电气特性,比如对传输的控制和处理、数据包的解析以及对传输信号的编码和解码。HCD(Host Controler Driver)负责对HC进行配置和管理,而HC通过HCD来与USB功能软件进行通信。目前USB的HC芯片组有三种,随之对应的HCI(Host Controller Interface)也有三种:EHCI(Enhanced Host Controller Interface),OHUHCI(Universal Host Controller Interface)和OHCI。在大多数的嵌入式系统中使用的是遵循OHCI规范的USB主机控制器。

3 OHCI规范

在操作和数据传输上,HC同HCD之间的接口有两条通道。第一个通道是HC的操作寄存器,包括控制、状态和列表指针寄存器。操作寄存器包含了指向一个称之为HCCA(Host Controller Communications Area)的指针,而HCCA是第二个通讯通道。HCCA保存了到中断端点描述的列表指针,完成队列的头指针以及与SOF处理相关的状态信息。

OHCI使用端点描述ED(EndpointDescriPtor)和传输描述TD(TransferDescriptor)来组织USB数据的传输,HC从ED列表获取端点信息,并从ED的TD列表逐次获取传输信息,以实现数据的传输。典型的链表结构如图2所示。

批量和控制ED列表的头指针由HC操作寄存器管理。HCD初始化这些指针,使得HC能够访问它们,当这些指针需要变更时,HC应该停止HC对需更新指针的列表的处理,更新指针,并重新启动HC。

图2 典型的OHCI的ED链表

特别要注意,LPC2478规定了USB设备使用的RAM区域,即0x7FD00000—0x7FD03FFF共16KB。HCCA以及ED,TD等数据结构定义的变量必须定义在这个区域,否则HC不能正常工作。

4 OHCI主机驱动程序的实现

4.1 OHCI相关数据结构的构建

HCD主要构建的数据结构有端点描述符ED、传输描述符TD和主机控制器通信区域HCCA。

每个ED对应一个USB设备端点,不同的设备端点拥有不同的ED。同种传输类型的ED组成一链表,OHCI有三种ED链表:控制传输数据链表,批量传输数据链表和周期性数据链表(中断数据传输和同步传输同属此类),HC通过相应的操作寄存器访问各个ED链表。程序中ED数据结构定义如下:

TD用来指定每次发送给USB设备的数据所保存的位置或者接收USB设备发送给主机数据的保存位置。根据OHCI规范对TD的定义,定义TD的数据结构。程序中TD的数据结构定义如下:

HCCA是256字节的系统内存结构,系统软件通过这一结构来向HC发送和从HC接收特定的控制和状态信息。这一结构在内存中以256字节为单位来对齐绑定。系统必须为HC指定HcHCCA的值即HCCA结构地址。通常系统与HC的交互能够通过读取HC写入这一结构的数值来完成。程序中HCCA结构定义如下:

4.2 软硬件接口的实现

HCD向USB功能软件提供以下几个接口函数,用来操作和控制主机控制器。

4.2.1 OHCI主机控制器初始化函数Host_Init(void)

USB 2.0规范要求USB外设的工作时钟必须是48MHZ。LPC2478的外设功率控制寄存器(PCONP)决定外设的使能与否,最高位(32位)置1使能USB外设,初始化OHCI控制器首先要将此位置1。同时,通过置OTG时钟控制寄存器(OTGClkCtrl)的主机时钟使能位,使能主机时钟,至此OHCI可以正常工作了。

将LPC2478对应功能的引脚配置为OHCI后,需要初始化一些常用的变量如控制ED,批量ED,HCCA区域,TD数组等,另外,为了便于数据传输,要定义一个数据缓冲区指针。注意这些变量必须定义到LPC2478所指定的USB RAM(0x7FD00000-0x7FD03FFF)中,要传输到USB设备的数据必须首先将数据保存到USB RAM中,然后启动发送过程;接收到来自USB设备的数据也首先保存到USB RAM中,然后再将数据拷贝到所对应的缓冲区中。

最后初始化OHCI寄存器。OHCI寄存器分为4类:控制与状态类寄存器,存储器指针类寄存器,帧计数器类寄存器和根集线器类寄存器。

控制与状态类寄存器中,最主要是初始化与中断有关的寄存器。与USB设备通信的中断标志位主要有两个,分别是WDH位和RHSC位。每当一个TD传输结束后,HC会将此TD的地址写入Hc-DoneHead寄存器,HC然后将此寄存器的内容写入HCCA区域,此时就会产生WDH中断,程序可以通过此中断来标识一次数据传输的结束;而每次USB设备插入主机或者从主机拔出的时候,都会初始化RHSC中断,程序通过此标志来枚举USB设备或者处理USB设备拔出的善后工作。

存储器指针类寄存器,主要用来初始化一些指针,比如控制ED的指针,批量ED的指针,HCCA区域的指针等。这些指针可以随时修改。

帧计数器类寄存器,主要用来设置处理在一个帧的时间长短,HC处理周期ED和非周期ED的时间比率。通过设置 HcFmInterval寄存器的FrameInterval来决定HC处理一个帧的时间长短,注意此域的频率是12MHZ,及1ms中的 bit时间是12000。默认设置是11999,即一个USB帧的时间长度的1ms。另外HcPeriodicStart决定了在一个帧中处理非周期ED的长度。

根集线器寄存器主要用来标识根集线器的状态,初始化一般按照默认配置,在程序运行期间,通过读取此对应寄存器的各个位来得到端口的状态。至此,OHCI的初始化结束。初始化流程如图3所示。

图3 OHCI控制器初始化过程

4.2.2 USB设备枚举函数Host_EnumDev(void)

当有USB设备插入到OHC的端口上的时候,程序调用此函数对USB设备进行枚举过程。枚举过程主要是根据USB规范所定义的枚举过程进行的。通过枚举,程序可以获得USB设备的设备描述符,类描述符,配置描述符,端点描述符等,根据这些信息来初识化对应的ED。本实现根据USB2.0规范实现了标准的枚举过程。

4.2.3 TD传输函数Host_ProcessTD()

Host_ProcessTD()函数原型为Host_ProcessTD(HCED*ed,INT32U token,INT08U*buffer,INT32U buffer_len);此函数用来处理链接到端点描述符ED上的TD。根据参数ed的Control域,可以知道USB数据传输的类型(控制传输,批量传输,中断传输和同步传输),然后根据参数token来决定每种数据传输类型所处的阶段,这样就可以把从起始地址为buffer、一共buffer_len个字节的数据发送到USB设备对应的端点缓冲区,或者从对应的端点缓冲区接收buffer_len字节的数据到起始地址为buffer的缓冲区。连续调用该函数可以完成USB协议定义的标准传输类型。在此基础上,就可以实现基于USB标准传输的更复杂的协议。

通过Host_ProcessTD()函数就可以实现USB设备中常用的控制传输和批量传输。控制传输首先传输一个SETUP TD,然后根据需要传输两个IN TD或者OUT TD。而批量传输,根据需要,在生成对应的ED后,直接就可以传输IN TD或者OUT TD。以控制写为例,流程图如下:

图4 控制写流程

5 程序验证

驱动程序实现了标准的USB设备枚举过程。通过测试枚举过程中读取到的USB设备描述符来验证驱动程序的正确与否。嵌入式开发环境Keil uVision4配合仿真器J-LINK可以在仿真调试环境下查看全局和局部变量的值。验证过程中选择了一款金士顿的U盘作为USB设备。图5为通过Keil uVision4在仿真状态下读取到的U盘设备描述符:

图5 金士顿U盘的设备描述符

图6为同一个U盘在Windows XP操作系统中枚举成功后所读取到的属性。

可以看出,在图5中,idVendor0和idVender1两个字节组合起来代表了U盘的VID(Vender ID),由于是大端显示,所以驱动程序显示的VID实际为0x1043,同理idProduct0和idProduct1两个字节组合起来代表了U盘的PID(Product ID),PID为0x8012。在图6中,U盘的VID显示是0x1043,PID显示是0x8012。通过图5和图6,说明驱动程序设计是正确的。

图6 金士顿U盘在PC机上的属性

6 结束语

本文实现了一种适用于简单嵌入式软硬件平台的OHCI主机驱动程序。在实际的实现过程中,首先初始化了OHCI主机控制器,根据具体的实际应用,优化了OHCI规范中规定的ED链表操作。并在此基础上通过实验,分别实现了控制传输,批量传输和中断传输。另外程序还实现了对USB设备的标准枚举过程,一旦USB设备枚举成功,通过相应的USB设备描述符,加载不同类型的驱动程序,为上层的应用程序提供了稳定可靠的接口函数。实验证明,驱动程序的设计是正确实用的。

[1] Universal Serial Bus Mass Storage Class Bulk-Only Transport revision1.0[S].USB-IF,1999.

[2] Open Host Controller Interface Specification for USB Compaq Microsoft National Semiconductor[S].Release:1.0a,1999-09.

[3] 冯光磊,郭忠文,李正宝,等.基于 ARM和 Linux的USB OHCI驱动的设计与实现[J].计算机应用,2009,29(6):53-56.

[4] 陈明智,李锋,尚淮.USB通信协议分析和系统设计[J].自动化与仪器仪表,2006(6):43-46.

[5] 张卓亮.基于Linux系统的USB HOST驱动程序设计与实现[J].中国集成电路,2007,16(11):30-33.

[6] 刘锋,韩超,汪磊峰,等.基于linux的嵌入式USB主机控制器接口实现[J].微计算机信息,2010,26(42):75-77.

免责声明

我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!