基于FPGA的USB接口控制器设计(VHDL)

2023-12-02

今天给大侠带来基于 FPGA 的 USB 接口控制器设计(VHDL),由于篇幅较长,分三篇。今天带来第三篇,下篇,FPGA 固件开发、USB驱动和软件开发。话不多说,上货。
 
导读,2019年9月4日,USB-IF终于正式公布USB 4规范。它引入了Intel此前捐献给USB推广组织的Thunderbolt雷电协议规范,双链路运行(Two-lane),传输带宽因此提升,与雷电3持平,都是40Gbps。需要注意的是,你想要体验最高传输速度,就必须使用经过认证的全新数据线。USB4保留了良好的兼容性,可向下兼容USB 3.2/3.1/3.0、雷电3。除此之外,USB4将只有USB Type-C一种接口,并支持多种数据、显示协议,包括DisplayPort,可以一起充分利用高速带宽,也支持USB PD供电。
比较遗憾的是,USB4的发布时间至今暂未公布。值得注意的是,此次发布的USB4是规范,而并非USB4.0。在此之前,USB Implementers Forum(USB-IF)计划取消USB 3.0/3.1命名,统一划归为USB 3.2。其中USB 3.0更名USB 3.2 Gen 1(5Gbps),USB 3.1更名USB 3.2 Gen 2(10Gbps),USB 3.2更名为USB 3.2 Gen 2x2(20Gbps)。以上就是关于USB标准以及命名的讯息。
现在大部分USB设备(比如USB接口的鼠标、键盘、闪存、U盘等等)都是采用了USB通用驱动,而你的系统有USB通用驱动的话(比如XP就内建了USB通用驱动)就能用。而有些USB设备是需要特殊驱动的,比如某些手机,连接到电脑的USB口,是需要安装驱动才能使用的。下面我们一起动手做一做USB接口控制器设计,了解一下如何设计。
第三篇内容摘要:本篇会介绍FPGA 固件开发,包括固件模块划分、自定义包编写、分频器模块的实现、沿控制模块的实现、输入/输出切换模块的实现、请求处理模块的实现、设备收发器模块的实现、测试平台的编写;USB 驱动和软件开发,包括USB 驱动编写、USB 软件编写以及总结等相关内容。
 
六、FPGA 固件开发
6.1 固件模块划分
在本例中,固件开发指的就是 FPGA 开发,也就是使用硬件描述语言(VHDL 或者 VerilogHDL)编写 FPGA 内部程序。FPGA 的作用就是和 PDIUSBD12 进行通信,从 PDIUSBD12 中获取数据并且根据主机的要求发送数据。PDIUSBD12 和 FPGA 之间的通信就是 8 位数据总线加上若干控制信号(A0、WR_N、RD_N 等),只要控制 FPGA 产生符合 PDIUSBD12 输入/输出时序的脉冲,即可实现两者之间的通信。
FPGA 固件的模块图如图 34 所示,各个模块的功能如下。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第1张
图 34 硬件加密系统设计方案
(1)分频器模块
由于 PDIUSBD12 在读写时序上有时间限制,例如每次读写操作之间的间隔不能小于 500ns,而 FPGA 的系统时钟一般频率都比较高,所以不能直接使用系统时钟控制 PDIUSBD12,必须进行分频。分频器模块的功能就是按照要求由系统时钟生成所需频率的时钟信号。
(2)沿控制器模块
PDIUSBD12 的读写操作都各自有一个读写控制信号 WR_N 和 RD_N,每次读写操作都在对应的控制信号的下降沿触发,沿控制模块的功能就是可控地产生一个下降沿信号,用于控制读写操作。
(3)输入/输出切换模块
输入/输出切换模块在整个系统中非常重要,因为 FPGA 芯片和 PDIUSBD12 芯片之间的数据总线是双向的总线,所以当读写操作之一在进行的时候另一个操作的信号源必须关闭,否则就会造成双驱动,这不但不能得到正确的数据还会损害芯片。输入/输出切换模块的功能就是根据当前的读写状况控制信号源,保证在一个时刻只有一个信号源在驱动总线。
(4)设备收发器模块
这个模块是整个固件的核心模块,它完成的工作包括配置 PDIUSBD12 芯片、处理 PDIUSBD12产生的中断、完成从缓存读取数据,并且根据需要将数据通过 PDIUSBD12 发送。设备收发器模块完成对每个主机请求的解析工作,此外,还要将解析完成的请求数据传递给请求处理模块。
(5)请求处理模块
请求处理模块的作用是接收设备收发器模块解析完成的主机请求,并且决定如何处理此请求。
模块划分完毕之后就可以使用 ISE 创建工程了,然后就各个模块分别编写实现代码和测试平台,最后将所有模块整合起来作为一个实体并且对其进行仿真、测试,这样就是一次完整的FPGA 开发过程。
ISE 的一些基本使用方法在前面的文章已有详细介绍,这里放超链接,在此不详细说明。下面详细介绍一下各个模块的实现方法。
ISE 14.7 安装教程及详细说明
6.2 自定义包编写
在实际实现各个模块功能之前,首先需要编写两个自定义包,分别是 USB 包和 PDIUSBD12包。
USB 包定义了 USB 协议以及 USB 设备相关的数据类型、常量等内容,比如自定义数据类型、设备类型代码值、请求代码值、设备描述符、设备的工作状态机等。设备的工作状态机定义如下>
请求类型以及请求的代码定义如下:
另一个包是 PDIUSBD12 包,它定义的则是和 PDIUSBD12 相关的内容,比如 PDIUSBD12 的命令代码值、中断代码值等内容。对 PDIUSBD12 控制命令的定义如下:
鉴于篇幅以及其他原因,以上仅仅介绍 USB 包和 PDIUSBD12 包的部分内容作为参考。
 
6.3 分频器模块的实现,分频器模块实现的基本原理就是设计一个工作在系统时钟下的计数器,循环地递减或者递加计数,在某个计数的固定值将输出翻转,即可实现时钟分频的功能。
例如,实验板上的系统时钟是 50MHz,而所需的读写周期间隔要求大于 500ns,即读写的时钟频率不能高于 2MHz,需要将原系统时钟进行至少 25 倍分频。所以,我们设定一个计数器,工作在系统时钟下,每个系统时钟周期计数减一,减到零后恢复到 13,这样,每经过 13×2=26个系统时钟周期,计数器的输出会是一个完整的周期。
分频器模块的示意图如图 35 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第2张
图 35 分频器模块的示意图
实现分频器模块的代码如下>
6.4 沿控制模块的实现
沿控制模块的功能是提供可控的下降沿输出,实现的方案如下:用一个使能信号 CE_N 控制输出。输入为分频后的时钟,当 CE_N 输入为高的时候,输出保持高电平,而当 CE_N 输入变为低的时候,将时钟接到输出上,这样就能得到连续的下降沿信号(和时钟的下降沿同步)。只要对 CE_N 进行适当的控制,就能得到需要的下降沿。
沿控制模块的示意图和时序图如图 36 所示。输入时钟连接到分频器模块的输出时钟上,使能信号控制沿输出信号,只要在某一个时钟周期内将使能信号保持低电平,就可以得到一个下降沿输出。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第3张
图 36 沿控制模块的示意图和时序图
沿控制模块的实现代码如下>
由于 PDIUSBD12 的 8 位数据线是双向总线,所以当进行读写操作的时候,应该注意避免双驱动。双驱动的意思就是在总线两边同时往总线上加输出信号,这样总线数据就处于一种不定态(用 X 表示),并且还容易损坏器件。例如,没有处理好双驱动的仿真波形就会如图 37 所示,这种情况下无法得到正确的数据的。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第4张
图 37 仿真不定态时序图
信号的 4 种基本状态是高电平(1)、低电平(0)、不定态(X)和高阻态(Z),当一个总线上同时加有两个信号时,组合起来的结果如表 35 所示。
表 35 信号状态表
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第5张
可见,当一个总线上同时有两个驱动的时候,很有可能产生不定态 X,但是如果其中一个信号为高阻态 Z 的话,则是一个确定的状态(即另一个信号的状态)。所以,避免双驱动的基本思想就是根据目前的读写状态关闭某一个驱动源,也就是说将其另一个驱动源输出设置为高阻态。由于读写操作是由各自的控制信号(WR_N、RD_N)控制的,所以可以将这两个信号作为互斥关系的信号来控制总线数据的信号源。例如,当 RD_N 为低时,要从 PDIUSBD12 读取数据,就应该关闭 FPGA 对总线的输出,即将 FPGA 的总线输出信号变为高阻态 Z。反过来也一样,当 WR_N 为低时,要向 PDIUSBD12 发送数据,此时 PDIUSBD12 也会自动关闭它在总线上的输出。以上思想可用公式表示为>
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第6张
输入/输出切换模块的示意图如图 6-38 所示。其中左边的总线表示连接到 PDIUSBD12 的总线,右边的输入、输出总线是在 FPGA 内部的总线信号,表示在 FPGA 内部将总线的输入和输出区分开来;RD_N 和 WR_N 信号分别用于读、写控制。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第7张
图 38 输入/输出切换模块的示意图
输入/输出切换模块的实现代码如下>
6.6 请求处理模块的实现
请求处理模块的功能是根据主机的请求控制设备收发器模块的处理状态。在本例中,请求处理模块实际的功能就是根据目前接收到的主机请求控制设备收发器模块发送数据,所以请求处理模块的实现就是一个简单的状态机。
请求处理模块的示意图如图 39 所示。时钟信号是由分频器的输出时钟提供;请求类型输入是一个 8 位端口,它和接收事件输入协同工作,当设备收发器接收到一个请求时,就会将请求代码发送到请求类型输入端口,在接收事件输入端口输出一个时钟周期的低电平,表示一次新的请求处理;命令输出端口和命令中断端口则用于控制设备收发器模块的操作状态。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第8张
图 39 请求处理模块的示意图
请求处理模块的实现代码如下>
6.7 设备收发器模块的实现
设备收发器模块是整个固件系统的核心,实现的基本思想是创建一个状态机,将各个处理操作都作为一个状态处理,在每个状态中按照 PDIUSBD12 的时序要求对其进行数据访问和控制。
设备收发器模块的示意图如图 40 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第9张
图 40 设备收发器模块的示意图
由于 USB 协议很复杂并且 PDIUSBD12 的控制也比较复杂,所以设备收发器状态机的状态量会较多。根据设备收发器的功能,可以将状态机各个状态的功能分为 3 类。
• 初始化器件:初始化器件就是对 PDIUSBD12 器件进行配置的状态,需要配置的内容包括设置地址/使能、设置 DMA 以及设置模式等。
• 数据访问:数据访问即实现 PDIUSBD12 和 FPGA 之间的数据读写,包括读取中断寄存器、读取前次传输状态、由端点读取数据、由端点发送数据等。
• 请求回复:请求回复是指根据各种类型请求的数据格式提取所需要的数据,并且在解析完成后通知请求处理模块。下面详细介绍一下以上 3 种状态的实现。
1)初始化器件
初始化器件相关的状态主要是 TS_DISCONNECTED 和 TS_CONNECTING(状态的定义见USB_Package.vhd 文件),其中 TS_DISCONNECTED 是系统复位后的状态,TS_CONNECTING 是配置PDIUSBD12 寄存器的状态。需要注意的是 PDIUSBD12 器件在复位后应该等待至少 3 ms 后再访问其寄存器,这样可让晶振稳定下来。
由于对寄存器配置的命令以及时序都是确定的,所以可以在自定义包中将配置数据定义为常数,例如>
上面定义的就是 PDIUSBD12 的配置参数,第一个常数数组是配置命令和数据,第二个数组表示命令、数据的顺序,最后一个参数是配置参数的总长度。定义的过程是首先向 PDIUSBD12发送命令 D12_COMMAND_SET_DMA(设置 DMA 命令),然后发送此命令的数据 D12_DMA(D12_DMA定义为 0xC0,其意义请参考图 23);之后发送设置模式命令和此命令的两个数据。D12_COMMAND_SET_DMA、D12_DMA、D12_COMMAND、D12_DATA 等都是已定义的常数,例如>
详细的常数定义请参考 PDIUSBD12 包的定义文件。这样定义虽然显得复杂,但是便于将数据与格式分离,也便于代码阅读。此外,在调用配置数据时也较为方便,只需要使用一个循环索引变量,依次读取 D12_CONNECT_DATA 数组和D12_CONNECT_DATA 数组的数值,发送给 PDIUSBD12 即可,代码如下>
以上代码运行的结果就是经过 5 个时钟周期,FPGA 完成向 PDIUSBD12 输出的一系列命令以及数据,通过编写测试平台仿真可以看到运行的结果(测试平台的编写将会在下面专门介绍),如图 41 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第10张
图 41 器件配置仿真时序图
通过上面的时序图可以看出,8 位总线上传输的是 D12_CONNECT_DATA 定义的配置命令和数据,而 a0 位表明了总线上的是命令还是数据,通过一个下降沿的写信号可以将命令或者数据发送给 PDIUSBD12。
2)数据访问状态
数据访问状态的功能简单地说就是中断监测和数据收发。每次系统复位后 FPGA 会自动配置 PDIUSBD12 器件,配置完成之后设备收发器模块会处于空闲状态(TS_IDLE)。PDIUSBD12 器件在接收到数据包时会通过中断来通知设备收发器,此外,请求处理模块也会通过命令中断信号控制设备收发器模块。所以,中断监测就是在每个时钟周期读取一次 PDIUSBD12 的中断信号和请求处理模块的命令中断信号,如果发现其中的一个中断信号为低,则转为其他状态。
中断监测的代码如下>
当监测到 PDIUSBD12 的中断时,设备收发器首先读取中断寄存器,然后就会进入数据收发状态,如果监测到的是请求处理模块的命令中断,则进入的是请求回复状态。请求回复状态包括了发送描述符、发送配置信息等,这些内容将在下面一个小节介绍。数据收发状态包括读取中断寄存器、控制端点数据收发等。读取中断寄存器的流程图如图42 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第11张
图 42 中断处理流程图
读取中断寄存器的代码如下>
下面介绍一下控制输出的处理流程。控制输出的输出是相对主机来说的,所以相对于设备来说,就是接收主机的数据。当一次控制输出发生时,设备首先会判断接收到的是不是建立包(Setup Packet),如果是则开始接收下面的数据,否则,接收前次传输所剩余的数据。控制传输的处理流程图如图 43 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第12张
图 43 控制输出流程图
从上面的流程图可以看出,设备收发器首先要选择控制输出端点,提取建立包的内容,再进行端点是为满还是空的判断。如果控制端点不为空,设备收发器将从缓冲区读出内容并将其保存。之后,它将判断设备请求的有效性,如果是一个有效的请求,设备收发器必须向控制输出端点发送应答建立命令以重新使能下一个建立阶段。
接下来,设备收发器需要证实控制传输是控制读还是写。这可以通过读建立包中bmRequestType 的第 8 位来判断。如果控制传输是一个控制读类型,那就是说器件需要在下一个数据阶段向主机发回数据包。设备收发器会设置一个标志以指示设备现在正处于传输模式,即准备在主机发送请求时进入传输状态(TS_EP0_TRANSMIT)向主机发送数据。
处理流程的各个步骤在设备收发器模块中被划分在两个状态中实现,其中选择端点和读取、保存数据的操作在 TS_READ_ENDPOINT 状态中实现,其他的内容在 TS_EP0_RECEIVE 状态中实现。下面是从端点(PDIUSBD12 的缓冲)数据读取的实现代码,即 TS_READ_ENDPOINT 状态的代码,由于篇幅原因,这里只提供部分参考代码。
下面介绍一下控制输入的处理过程。控制输入就是设备向主机发送数据,最为典型的就是设备向主机发送描述符,图 44 所示是控制输入的流程图。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第13张
图 44 控制输入流程图
从控制输入的流程图可以看出,设备收发器首先需要通过读 PDIUSBD12 的最后处理状态寄存器清零中断标志位。接着设备收发器在确认 PDIUSBD12 处于传输模式后进行数据包的发送。PDIUSBD12 的控制端点只有 16 字节 FIFO,如果传输的长度大于 16 字节,设备收发器在传输阶段就必须控制数据的数量。设备收发器必须检查要发送到主机的当前和剩余的数据大小,如果剩下的字节数大于 16,设备收发器将先发送 16 字节并继续等待下一次发送。
当下一个数据发送中断来到时,设备收发器将确定剩余的字节是否为零。如果已经没有数据要发送,设备收发器需要发送一个空的包以指示主机数据已经发送完毕。
控制输入是在 TS_EP0_TRANSMIT 和 TS_WRITE_ENDPOINT 两个状态中实现的。其中,TS_EP0_TRANSMIT 实 现 的 是 控 制 输 入 流 程 控 制 , 而 TS_WRITE_ENDPOINT 的 实 现 和TS_READ_ENDPOINT 很类似,只不过是将读取数据换为发送数据。TS_WRITE_ENDPOINT 状态的实现代码如下,由于篇幅原因,这里只提供部分参考代码。
以上便是数据访问状态的实现方法,在测试平台中可以对以上代码进行测试,测试时的输入数据应该由测试平台产生(测试平台的编写将在下面的章节进行专门介绍)。如第一次发送设备描述符的仿真波形。此仿真过程可以分为两个部分,第一部分(如图 45 所示)是接收建立包(Setup Packet)以及读取 PDIUSBD12 请求数据的过程;第二部分(如图 46 所示)是将设备描述符数据写入 PDIUSBD12 端点缓存并且使缓冲区有效。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第14张
图 45 发送设备描述符仿真波形 1
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第15张
图 46 发送设备描述符仿真波形 2
3)请求回复状态
请求回复状态的功能就是对各个请求作出响应。USB 的标准请求已经在前面做了介绍,下面就以获取描述符请求为例介绍一下请求响应的实现方法,其他的标准请求以及厂商请求(获取、设置密码)相对来说比较简单,实现的方法请读者参考源代码。
获取描述符请求是最为重要的请求,因为这在设备枚举过程中是必需的,它是主机了解设备的第一个步。获取描述符请求的处理流程如图 47 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第16张
图 47 获取描述符处理流程
获取设备描述符请求响应的实现代码如下>
 
 
6.8 测试平台的编写
上面介绍的是整个 FPGA 固件系统的实现方法,为了验证设计的正确性,还需要编写一个测试平台对整个系统进行仿真。由于实际情况下 FPGA 是和 PDIUSBD12 进行通信,所以在测试平台中需要虚拟一个 PDIUSBD12,来实现仿真的目的。
首先,在测试平台中需要产生一个虚拟的时钟信号,产生的方法就是使用 wait for 语句等待固定时间后将信号值翻转。时钟信号的实现代码如下>
其次,由于 FPGA 和 PDIUSBD12 之间有数据读写,所以要模拟所有 FPGA 向 PDIUSBD12 读取的数据。模拟数据读写的方法是将所有数据按照顺序写入一个大的测试数据数组中,使用一个变量作为该数组索引,再编写一个对读信号敏感的过程,在每次读信号的下降沿将数据送到总线上,并且将数组索引变量增加 1。测试数据数组以及索引变量的定义方法如下>
再次,需要处理好总线双驱动的问题。前面介绍的输入/输出选择模块的功能就是在必要的时候关闭总线输出来避免双驱动的发生,同样道理,在测试平台中也应该做到这一点,即当测试平台向 FPGA 固件系统读取数据时,应该关闭测试平台的总线输出,即将其设置为高阻。实现代码如下:
最后,还需要编写一个主流程,在主流程中需要进行系统复位和产生中断信号,代码如下:
 
 
 
七、USB 驱动和软件开发
7.1 USB 驱动编写
以上介绍的是 FPGA 固件的开发过程,由于本例中设计的不是一个类设备,所以要使设备正常工作,还需要编写专门的驱动程序和软件。由于驱动和软件不是本篇的重点,故下面只简要介绍其编写方法。
1)USB 驱动模型
USB 体系的主机软件可分为两层,即 USB 系统软件和客户端驱动程序,如图 48 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第17张
图 48 USB 接口软件模型
USB 系统软件根据功能可以分为 USBD 和 HCD 上下两部分,其中 HCD 为上层提供了主机控制器的抽象以及数据在总线上的传输抽象。USBD 为上层的客户端驱动程序提供了 USB 设备的抽象,并在客户端驱动和所驱动的设备之间提供了数据传输的抽象。
客户端驱动程序从用户的角度来讲相当于传统意义上的驱动程序。不过设备端不同的接口对应不同的驱动程序,如果设备只有一个接口,那么从用户的角度来讲,两者是一样的,客户端驱动程序通过 USB 系统软件提供的接口与设备交互,而不是通过过去的 I/O 地址或者端口进行访问。
2)使用 Driver Studio 开发 USB 驱动
上面介绍的是 USB 软件模型,对于驱动开发人员来说,需要编写的就是客户端驱动程序。编写客户端驱动程序需要安装 DDK,即 Windows Driver Development Kit,通过 DDK 我们就能够访问 USB 系统软件的接口从而实现与设备的交互。但是,如果只使用 DDK 开发驱动程序的话,会比较复杂,所以可以使用一些驱动开发的专用工具,例如 Driver Studio、WinDriver 等。本例选用的是 Driver Studio 2.7 进行开发,下面介绍一下开发的基本步骤。安装完 DDK 以及 Driver Studio 后,运行 Driver Studio 的 Driver Wizard。在第 1 步中输入驱动工程名称和路径,如图 49 所示。单击 Next 按钮进入如图 50 所示对话框。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第18张
图 49 Driver Wizard 第 1 步 
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第19张
图 50 Driver Wizard 第 2 步
第 2 步选择工程类型 WDM Driver,单击 Next 按钮进入如图 51 所示对话框。
第 3 步选择驱动类型 WDM Function Driver。单击 Next 按钮进入如图 52 所示对话框。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第20张
图 51 Driver Wizard 第 3 步 
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第21张
图 52 Driver Wizard 第 4 步
第 4 步比较重要,是选择驱动总线类型,应该选择 USB(WDM Only),并且注意要在 USB VendorID 和 USB Product ID 中输入和固件中设备描述一致的信息。这里请注意 Vendor ID 一定是0x0471,因为使用的是 Philips 的 PDIUSBD12 芯片,其 Vendor ID 固定为 0x0471。单击 Next按钮,进入如图 53 所示对话框。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第22张
图 53 Driver Wizard 第 5 步
第 5 步是端点定义,可以根据需要定义端点的类型(输入输出)、端点号、缓存大小等。
第 6 步到第 9 步是一些开发辅助信息的定义,可以保持为默认值,如图 54~图 57 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第23张
图 54 Driver Wizard 第 6 步 
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第24张
图 55 Driver Wizard 第 7 步
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第25张
图 56 Driver Wizard 第 8 步 
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第26张
图 57 Driver Wizard 第 9 步
第 10 步是设备类的定义,如图 58 所示。定义打开设备的方式,Symbolic Link 表示按照设备名称打开,Interface(WDM Only)表示按照设备的 GUID 打开,这里选择使用设备名称打开。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第27张
图 58 Driver Wizard 第 10 步
第 11 步定义的是设备的 IO 控制接口,也就是驱动和应用程序之间的接口,如图 59 所示。单击 Add 按钮可以定义 IO 控制接口,如图 60 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第28张
图 59 Driver Wizard 第 11 步 
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第29张
图 60 定义 IO 控制接口
最后,第 12 步进行一些额外的设置,如图 61 所示,可以保持默认值。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第30张
图 61 Driver Wizard 第十二步
以上便是使用 Drive Studio 的 Driver Wizard 生成驱动框架的完整过程,现在我们已经有了一个完成了大部分驱动工作的代码框架,只需要增加一些自定义的处理代码即可。
3)使用 Visual C++编译驱动
运行 Visual C++ 6.0 打开 Driver Wizard 生成的工程文件,可看到在***Device 这个类中已经有了很多设备操作的处理函数,例如上电(OnDevicePowerUp)、休眠(OnDeviceSleep)启动(OnDeviceStart)等,可以根据需要修改这些函数,如果没有特殊要求,可以保持默认设置,如图 62 所示。
基于FPGA的USB接口控制器设计(VHDL) (https://ic.work/) 可编辑器件 第31张
图 62 设备操作处理函数
另外还需要完成的工作就是对上面定义的 IO 控制接口函数进行处理,其功能就是建立一个厂商请求。由于本次设计的 USB 设备是一个加密设备,它不是类设备,所以会有一些特定的请求(厂商请求)。为了介绍厂商请求的实现方法,本系统用到了两个厂商请求:设置密码和获取密码。由 Driver Wizard 自动生成的驱动一般都已经包括了标准请求的建立,但是不会包括厂商请求的建立。厂商请求是在 IO 控制接口函数中建立的,即 Driver Wizard 第 11 步所定义的两个函数,建立厂商请求的函数主要是 BuildVendorRequest 函数,其格式如下>
 
 
 
 
其中需要开发人员注意的是前 6 个参数,其意义如下>
• PUCHAR TransferBuffe 数据缓冲。如果是数据输入,用于存储接收到的数据;如果是数据输出,则是待发送数据的数据源;如果没有数据传输,此参数可是为空(NULL)。
• ULONG TransferBufferLength 发送或者接收数据的长度。
• UCHAR RequestTypeReservedBit 请求类型的位掩码,一般为零。
• UCHAR Request 请求代码。
• USHORT Value 即 USB 请求中的 wValue 位,• BOOLEAN bIn=FALSE 此参数为 TRUE 表示数据输出,反之则表示数据输入。
其余的参数可以保持默认。下面就从 USBSOFTLOCK_IOCTL_GET_PASSWORD_Handler 处理函数为例介绍一下 BuildVendorRequest 函数的用法,代码如下>
 
 

文章推荐

相关推荐