USB 2.0规范及控制器
文章目录
- USB 2.0规范及控制器
-
- USB2.0
-
- Univerasl Serial Bus
-
- USB
- Host
- USB总线
-
- 接口标准
- 总线信号
- USB拓扑结构
- 数据流模型
- 数据编解码和位填充
- USB逻辑部件
- USB时间基准
- USB 描述符
- USB设备
-
- USB设备供电方式
- USB设备分层
- USB设备插入检测机制
- USB设备状态
- USB总线枚举
- USB传输
-
- 传输类型
- 包(Packet)
- 事务(transaction)
- 传输(transfer)
-
- 传输种类
- 传输机制
- Zynq USB Device
-
- Hardware System
-
- 系统接口
- 控制器结构
- Configuration, Control, Status
-
- Data Structures
- Functional Description
-
- DMA引擎
- 协议引擎
- 通用定时器
- Programming And Reference
-
- 操作模式控制
- Device Mode Control
-
- 控制器状态
- USB总线复位响应
- Device Endpoint Data Structures
-
- Link-List Endpoint Descriptors
- Manage Endpoints
- Endpoint初始化
- Device Endpoint Packet Operational Model
-
- Prime Transmit Endpoints
- Prime Receive Endpoints
- 中断及批量端点操作模型
- 中断及批量端点总线响应
- Device Endpoint Packet Descriptor Reference
-
- Endpoint Queue Head Descriptos (dQH)
- Endpoint Transfer Descriptor(dTD)
- Endpoint Transfer Overlay Area(参考figure15-14)
- Device Controller 编程模型
-
- 设备控制器初始化
- 管理传输描述符
- 利用传输描述符管理传输
-
- 建立一个传输描述符(dTD)
- DCD执行一个dTD
- 传输完成
- 传输完成
文章图片
本文为ug585及usb2.0的个人学习及理解过程,后续将给出USB Device 源码分析;
文章一部分图片因github图床加载的原因未展示感兴趣可直接通过github查看;
? OTG及Host模式在裸机模式下不支持,结论来自Xilinx官网USB开源工程;
USB2.0 Univerasl Serial Bus
USB USB1.0-> 1.5Mb/s Low-Speed 12Mb/s Full-Speed
USB2.0-> 480Mb/s High-Speed
特点 : 轮询总线,由Host发起所有的数据传输
鲁棒性 :
- 差分驱动,接收器保证信号完成
- 控制和数据传输过程中CRC校验
- 设备插拔检测
- 超时机制检测丢失或损坏的包,传输失败最多进行3次重传
- 流式数据的流量控制,保证同步和硬件缓冲管理
管理Host和Device之间的控制流,数据流; 收集USB总线状态和活动数据信息; 为连接USB总线的设备供电;
USB总线
接口标准 A型 B型 Mini型
总线信号
- 差分传输模式
? 两根数据线D+ D- : 差分信号1 : D+ > 2.8V,D- < 0.3V ; 差分信号0 : D- > 2.8V,D+ < 0.3V;
- J状态 K状态
低速 D+为’0’ D-为’1’ 为J状态, K状态相反
全速 同高速
高速 D+为’1’ D-为’0’ 为J状态, K状态相反
- SE0状态
D+为’0’ D-为’0’
- IDEL状态
低速 空闲状态为’K’状态
全速 空闲状态为’J’状态
高速 空闲状态为SE0状态
- 针对全速模式
- reset信号
? 主机和设备通信前会发送reset信号来把设备配置到默认的未配置状态.
? SE0状态保持10ms
- resume信号
? 20ms的K状态 + 低速EOP
? suspend信号
? 3ms以上的J状态
- SOP信号
从IDLE状态切换到K状态
- EOP信号
持续2位时间的SE0信号,后跟随1位时间的J状态
- SYNC信号
3个重复的K ,J状态切换, 后跟随2位时间的K状态
- reset信号
- 主从结构
主机 : Host
? 从机 : Device 分为USB Function和USB HUB
- 星型拓扑结构
以HOST为顶层,以HUB为中心,HUB串联级数最多5层
- 数据节点
- USB Physical Device: 具有一定功能的USB设备硬件
- Client Software : 在Host上运行与USB Device通讯的软件,一般与具体的USB设备配套
- USB System Software : USB系统软件,一般与操作系统配套 与具体的USB设备和Client Software无关
- USB Host Controller:包括软硬件,允许USB设备连接到Host
- 层级
- USB bus Interface提供物理,信号,包的连接
- USB Device层负责USB系统软件与设备交互
- 功能层为USB设备与Host交互匹配合适的Client Software
- NRZI(非归零编码) : 输入数据0编码成"电平翻转"; 输入数据1,编码成"电平不变"
- 位填充
- 目的是为保证发送的数据序列有足够的电平变化
- 填充的对象为输入数据 即先填充后编码
- 填充方式为数据流中每6个连续的’1’插入一个’0’
文章图片
特征
- USB设备是端点的集合, 分组端点构成一个接口
- USB系统通过默认控制管道来管理设备
- Client Software使用管道来管理接口
- 通过Host的buffer和USB设备的端点来请求数据
- Host Controller 打包数据并将数据发送出去
- Endpoint是USB设备上可被独立识别的端口,Host与Device通讯流的逻辑终点
- USB设备的最小收发单元,一系列相互独立的端点构成USB逻辑设备
- 设备上的每个端点会在接入总线时被分配唯一端点号,并决定其传输方向
- Host 通过"设备地址 + 端点号 + 数据传输方向"对其进行唯一寻址
- 分类
- 0端点 : 控制端点,一个设备只有一个,对设备进行枚举和基本控制功能, 数据双向传输
- 非0端点 : LS最多支持2个, HS/FS最多支持15组, 单向通讯,且在设备被成功配置之后, 只有向主机报告端点特性之后才能被成功激活
- Host Softwarw的buffer与设备 Endpoint之间的数据搬运模型;
- 同端点配套,意味着其存在一个Host对Device的默认控制管道, 在上电和总线复位时有效, 用于Device鉴别和配置;
- 分类
- 流管道
数据传输无USB定义结构, first in first out, 通信流总是单向的;
- 信息管道
主机向USB设备发送请求,随后进行数据传输,最后进行传输状态确认, 数据中加入USB定义格式以用来区别请求/数据/状态,允许双向数据流;
- 流管道
USB时间基准
- 帧 LS\FS上建立的1ms时间基准 微帧 HS模式下建立的125us时间基准; 这个时间由控制器内部定时器产生;
- 一个时间基准可包含多组事务
根据传输类型定义可包含的事务类型
每N个时基为总线提供同步和中断端点的窗口(针对中断传输和同步传输)
N值取值参考具体传输方式
Device(具体参见USB2.0 Table 9-8)
- 描述有关USB设备的常规信息(一个USB设备具有唯一此描述符)
- 包含全局适用于设备和所有设备配置的信息
- 具有全速和高速不同设备信息的高速设备也必须具有 设备限定 描述符
- 所有USB设备具有一个默认控制管道, 设备描述符描述设备默认控制管道的最大数据包大小
- 描述有关高速设备的信息
- 此描述符会返回与当前运行速率相反状态的信息,eg:以全速运行会返回如何以高速运行的信息
- 描述关于特定设备配置的信息
- 描述符包含一个bConfiguration Value字段,此字段的值用于做SetConfiguration请求的参数时会使设备采用所描述的配置
描述高速设备的配置
如果以其他速率运行,其结构与配置描述符相同
Interface
- 描述配置中的特定接口 ,接口描述符总是作为配置描述符的一部分返回
- 一个配置提供一个或多个接口,每个接口具有零或多个端点描述符,用于描述配置中的一组唯一端点
- 当配置支持多个接口特定接口的端点将遵循GetConfig( )请求返回的数据中的接口描述符
- 接口描述符不能通过GetDescriptor( ) \ SetDescriptor( )直接返回
- 描述端点 接口的每个端点都有各自的描述符
- 包含主机为确认每个端点的带宽需求所需要的信息
- 一个端点描述符总是作为配置描述符的一部分返回
- 端点描述符不能通过GetDescriptor() 或 SetDescriptor( )请求直接访问
- 端点0 不存在端点描述符
- 描述字符串 可选
- 如设备不支持字符串描述符, 则必须将设备,配置,接口描述符中对字符串描述符的所有引用重置为0,否则会导致host枚举失败
USB设备供电方式
- 自供电设备 设备从外部电源获取电压
- 总线供电 设备从VBUS(5V)取电
- 低功耗设备
最大功耗不超过100mA - 高功耗设备
枚举时最大功耗不超过100mA
枚举配置结束后功耗不超过500mA
- 低功耗设备
- 底层
传输和接收数据包的总线接口 - 中间层
处理总线接口和设备上各个端点之间的路由数据
端点是数据的最终消费者和提供者 - 顶层
串行总线设备提供的功能,eg 鼠标等
设备连接主机时,主机检测到相应数据线拉高,认为设备连接,此时主机必须在复位设备前采样数据线判断设备速度;
- 全速/高速 D+上拉
- 低速 D-上拉
- 连接状态
设备接入总线系统中状态依据规范
- 上电状态
设备通过配置描述符报告其电源功能
根据设备供电选项上游端口进行对应供电策略
- 默认状态
上电后不进行任何响应,直至复位信号到来
接到复位信号后,使用默认地址对设备进行寻址
此状态完成后设备在正确的速度下进行操作
- 地址状态
所有USB设备在加电复位后都使用缺省地址
每一个设备在连接或复位后由主机分配一个唯一的地址
USB设备处于挂起后保持此地址不变
USB设备支队默认通道(pipe)请求发生响应,而不管设备是否已经分配地址或者使用默认地址
- 配置状态
USB设备正常使用前,必须正常配置
- 设备角度
使用一个非零配置值正确处理SetConfiguration()请求
配置一个器件或者改变一个可变的设备设置会使与这个相关接口的端点的所有状态与配置值被设为缺省值;
包括正在使用的data toggle的end point data taggle被设置为DATA0
- 挂起状态
USB设备在探测不到总线传输时自动进入挂起状态,
USB保持本身的内部状态,包括地址及配置
供电 -> 复位 -> 获取DeviceDescriptor前8个字节 -> 复位 -> 分配地址 -> 获取Device Descriptor -> 获取String Descriptor -> 配置
- 检测电压变化,报告给主机
HUB检测到有电压变化,利用自己的中断将信息反馈给主机
- 主机探寻设备详细信息
主机通过查询HUB确认此次变化的详细种类
发送Get_Port_Status()请求给hub
- Hub检测所插入的设备是高速还是低速
hub通过检测USB总线空闲(IDLE)时的差分线电平来判断所连接设备的速度类型
接收Get_Port_Status()请求后回复速度类型
此操作必须先于复位操作
- hub复位设备
主机得知新设备连接,至少等待100ms以等待插入操作及设备电源稳定
之后向hub发送Set_Port_Feature()请求 让hub复位其管理的端口
hub驱动 D+D-为0以复位设备
- Host检测所连接的全速设备是否支持高速模式
高速设备在初始时默认全速状态
是否支持取决于设备的上拉电阻切换及总线电流(参考中文网)
- HUb建立设备与主机之间的信息通道
主机不断发送Get_Port_Status请求来查询是否复位成功
- 主机发送Get_Descriptor请求,获取设备描述符
默认管道(Default Pipe)在设备一端视为端点0,此时发送的请求是默认地址0,端点0
设备描述符的第8字节代表设备端点0 的最大包大小
当完成第一次控制传输后,系统会要求hub对设备及性能再次复位,以使设备进入一个确认状态
- 主机给设备分配地址
主机控制器通过Set_Address请求向设备分配一个为唯一地址, 设备进入地址状态,之后启动新地址
- 主机获取设备的信息
主机再次发送Get_Descriptor请求到新地址读取设备描述度
- 主机给设备挂载驱动
主机通过解析描述符获取信息,之后选择一个合适的驱动给设备
之后调用设备模型提供的device_add将设备添加到USB总线的设备列表
- 设备驱动选择一个配置
驱动根据前面设备回复的信息,发送Set_configuration()请求来正式确定设备的工作配置
设备处理处于配置状态(Configured),设备使能其各个接口
供电;
总线传输数据以包(Packet)为基本单位, 上层称为事务(transaction) 由不同的包组成, 之后组成一次transfer
传输类型 域组包->包组事务->事务组传输
- 批量传输 同步传输 中断传输 控制传输 一次transfer为一次transation
- 控制传输分为如下过程 :
- 建立过程 一个transation
- 状态过程 一个transation
- 数据过程 一个或多个transation
但都以同步域SYNC开始,紧跟标识符PID,并以EOP结束符结束
SOP包起始位同步域的一部分
EOP界定符和SYNC等都是通过电气特性描述,扎包工具并能抓到
- PID域(8bit)
- 标识一个包的类型 8bit
前四位为PID0~3
后四位为前四位取反用于校验PID - 种类
令牌包
分为: OUT->0001; IN->1001; SOF(start_of_frame)-> 0101; SETUP->1101
数据包
分为: data0->0011; data1->1011; data2->0111; mdata->1111
握手包
分为: ACK->0010; NAK->1010; STALL->1110; NYET->0110
特殊包
分为: PRE->1100; ERR->1100(复用PRE); SPLIT->1000; PING->0100; 保留->0000
具体参考table8-1 - 仅在帧首传输一次SOF包
- 标识一个包的类型 8bit
- 地址域(11bit)
- 设备地址域(低7位)
默认为0,必须在设备枚举阶段被定义 - 端点地址域(高4位)
LS设备最多3个端点
FS / HS最多16个端点
- 设备地址域(低7位)
- 端点域(4bit)
- 定义在IN SETUP OUT令牌包及PING包中
- 指示由Device端点
低速最大支持3个端点 一个控制端点两个默认
FS/LS 支持16个种类同上
- 帧号域(11bit)
- 主机每发出一个帧,帧号自动加1,直至0x7FF归零
- 数据域(n bytes)
控制传输
HS:64 FS:64 LS:8
批量传输
HS:512 FS:64 LS:N/A
中断传输
HS:1024 FS:64 LS:8
同步传输
HS:1024 FS:1023 LS:N/A
- CRC域
token CRC
G(X) = X^5+ X^2 + 1
data CRC
G(X) = X^16+ X^15+ X^2 + 1
- 包类型
- 令牌包
OUT
通知设备将要输出一个数据包
IN
通知设备返回一个数据包
SETUP
只用在控制传输中,通知设备将要输出一个数据包
与OUT区别在于只是用DATA0数据包,
且只能发送Device的控制端点
- SOF
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B6mM3gV3-1649168263498)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/5_sof.png)]
在每帧开始时以广播的形式发送,USB主机会对当前帧号进行统计,每次帧开始前通过SOF包发送帧号;
主机以全速总线每 1.00ms±0.0005ms 和高速总线 125us±0.0625us 的标称速率发出
- 数据包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kst98ezy-1649168263499)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/6_data.png)]
- 握手包
handshake describe NAK 设备暂时没有好接受数据或发送数据 STALL 设备不能用于传输 YET/ERR 仅用于高速传输,设备没有准备好或出错 CK 传输正确完成
- 握手包
- 令牌包
- 组成
Token packet +data packet + 可选的(handshake packet) - 分类
事务类型 | describe |
---|---|
setup事务 | 主机用来设备发送控制命 |
数据输入事务(IN) | 主机用来从设备读取数据 |
数据输出事务(OUT) | 主机用来向设备发送数据 |
- 控制传输
特点:
突发, 非周期性; 主机软件发起的"请求/响应"通信, 通常用于"命令/状态"操作
- 同步传输
特点:
主机与设备之间的定期, 连续通信, 通常用于对时间敏感的数据; 此传输类型保留了封装在数据中的时间概念
- 中断传输
特点:
低频,有限延迟通信 数据量小不连续,但实时性要求很高的传输
约束:
- 中断管道
? 流式管道->单向数据传输, 端点描述符给定中断管道的通信流的方向
- 传输包约束
中断管道端点,指定它将发送或接收的最大数据有效载荷 LS: 8bytes FS:64bytes HS:1024Bytes
? USB系统软件确定配置期间用于中断管道的最大数据有效负载大小 此大小在设备配置的整个生命周期保持不变
? USB系统软件确认最大负载数据后确认总线时间,在保证总线时间能够容纳最大数据负载后建立管道
? 端点传输数据时必须始终保持数据量不超过wMaxPacketSize 值,Device可以通过大于wMaxPacketSize的中断管道传输数据
? Client SW可以通过IRP(See I/O Requset Packet)来接收数据,当数据拆包为多个事务时,Client SW设置缓冲实现
传输数据包完成标志
已准确传输预期的数据量
数据有效负载大小小于最大负载,或数据包长度为0
中断传输完成后主机控制器退出当前IRP,进入下一IRP
如实际传输负载大于预期,此中断IRP将"aborted/retired",并且管道将停止接收IRP
高速默认接口传输最大负载不能超过64Bytes
总线接口约束
- 高速 传输不能超过80%微帧时间 最大带宽53.248MB/s->对应512Byte最大装载值;
- 全速/低速 传输不能超过90%微帧时间 最大带宽1.216MB/s ,48KB/s->对应64Byte/8Byte最大装载值;
- 总线访问访问周期 高速 -> 2^(1~16)*125us ; 全速 -> 1ms~255ms; 低速 -> 10ms~255ms;
- 总线错误会阻断传输;
- Client SW由一个IRP用于挂起的中断传输时才会轮询端点;
- 如执行中断传输的总线时间到IRP没有挂起,那么端点将不能传输, 等待IRP可用;
- client 和Device依赖于host确保与端点两次事务尝试之间的持续时间不长于事实时间;
- 中断管道
- 批量传输
特点
非周期性,大数据包突发通信 ; 通常用于可以使用任何可用带宽的数据
数据量大但对时间要求不高的传输
- 中断传输
IN事务(Host->Device) -> Data(Device->Host) -> ACK(Host->Device)
OUT事务(Host->Device) -> Data(Host->Device) -> ACK(Device->Host)
- 同步传输
IN事务(Host->Device) -> Data(Device->Host)
OUT事务(Host->Device) -> Data(Host->Device)
两路控制器信号独立;
文章图片
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yi61nbUJ-1649168263503)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/9_block.png)]
系统接口 每个控制控制器DMA传输通过AHB总线连接到PS片内互联;
控制及状态寄存器由APB映射到系统内存空间进行系统编址;
两个USB控制器有独立的复位信号及输出到GIC的中断信号;
控制器结构 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3U2oB9S-1649168263504)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/10_contr.png)]
DMA, Protocol Engines, Context and FIFOs
DMA引擎与协议引擎一起处理endpoints,periodic elements,queue heads,等其他传输描述符;
软件将数据结构写入系统内存,DMA引擎获取这些数据结构并将其复制到控制器的本地双端口RAM;
控制器在处理数据结构时读取和写入DPRAM中的数据结构;
当传输完成时,描述符通过DMA引擎返回内存;
除数据结构的上下文信息,控制器同时使同DPRAM来实现TX RX 的FIFO;
这些FIFO为系统内存和USB实时传输提供缓冲;
FIFO的使用方式跟随模式变动, 主机模式下通过DPRAM在每个方向上保持单个数据信道;
设备模式下,针对每个活动设备端点维护RX和TX数据FIFO通道,并且FIFO通道可以异步和实时操作;
Port Transceiver Controller
端口收发器提供 暂停/恢复,并且用于设备模式,chirp 控制功能(两次上电reset后的chrip K信号);
端口控制器控制8位的数据总线传递到8位的ULPI;
USB控制器的整个后端与PHY的60 MHz USB时钟同步工作;
ULPI(USB Low Pin Interface) Link Wrapper
协议引擎包括一个类似与UTMI+的内部总线;
ULPI wrapper 在此总线和ULPI接口之间提供一座桥梁,对用户透明;
ULPI Wrapper传递数据包并解释RX命令以及发送 TX命令;
ULPI Rx/Tx Commands
Rx命令由PHY启动以设置状态位,从而时软件能够查看PHY事件,这些指令设置控制器状态位;
Tx命令由软件通过寄存器写入来启动,以控制PHY功能,这些指令由ULPI规范定义;
Programmable Timers
两个控制器有独立的通用定时器用于生成超时或测量时间活动;
控制器用定时器生成帧(微帧)间隔并为Host控制器调度程序生成选通信号;
Software Programming Interface
除系统内存中维护数据和缓冲区结构,软件还读取和写入控制和状态寄存器;
控制器可以生成由DMA和协议引擎活动,PHY和其他控制器功能引起的中断;
Control and Status Registers
控制和状态寄存器包括常量,配置和 操作/状态(ECHI Host模式)兼容性以及非ECHI功能(Device,OTG);
Clock and reset
ULPI接口和协议引擎工作在通过ULPI接口输入的60MHz下;
AHB总线工作在CPU_1x;
CPU_1x和60MHz的跨时钟域通过DPRAM实现;
控制器复位: PS 复位系统(全控制器复位), usb.USBCMD[RST] bit位(部分控制器复位用于OTG);
ULRL PHY 复位: GPIO输出控制信号;
USB Bus 复位:OTG模式下的自动复位 , USB复位控制传输;
Configuration, Control, Status 软件管理控制器自身的配置和控制 以及 用于USB事务的一组一致的数据结构和内存缓冲区;
两种数据结构模型: data 和 host;
三种控制模式: Host, Device, OTG, OTG使用主机或器件模式;
Data Structures [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-etXoee8R-1649168263505)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/11_endpoint.png)]
响应Host请求,DCD(Device Controller Driver)设置一个端点描述符并管理端点的实时需求;
内存和ULPI之间的高速数据传输由控制器使用Queue Head和传输描述符进行管理;
每次传输的结果都由DCD进行确认并执行相应的操作;
Host Mode
Device Controller包括一个简单描述符模型用来快速响应主机请求;
12个端点每一个都有2个 device Queue Heads(dQH),一个用于IN事务,一个用于OUT事务,共有24个设备dQH;
使用一个dQH和≥1个的设备传输描述符(dTD)来定义一次数据传输;
Link-List Concept
Host和 Device控制器使用链表描述符来管理内存buf的双向传输流;
首TD(Transfer Descriptors)指向Queue Head,具体结构如下:
文章图片
Functional Description
文章图片
DMA引擎 数据传输
主机模式下,数据结构由EHCI规范定义, 表示由主机控制器执行的而周期行异步传输队列,包括允许控制器将数据包发送到FS/LS设备,该设备位于外部的Hs Hub或根Hub的下游;
主机模式使用队列头 (QH), 队列元素传输描述符 (QTD), 等时传输描述符(ITD), 分割事务等时传输描述符 (SITD)和周期帧跨越横向节点(FSTN)数据结构;
器件模式,数据结构较为简单,由链表形式的设备队列头(dQH)和设备传输描述符(dTD)组成;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XDrYUHYN-1649168263509)(14_dma.png)]
协议引擎 协议引擎解析令牌包,生成相应包响应,以及执行错误检测功能;
引擎执行所有的错误检查, 检查字段生成,格式化总线上的所有的握手,ping,数据响应包,并根据基于USB规范的时间范围生成所需的信号;
文章图片
协议引擎功能
- 令牌状态机跟踪总线上的所有令牌并根据令牌上的地址和端点信息进行过滤;
- CRC5/CRC16 生成器/校验器电路检查并生成令牌和数据包的CRC域;
- 【FPGA-ZYNQ|Zynq7000 USB2.0协议解析及USB控制器详解】数据和握手状态机生成USB所需的任何响应,并将数据包数据通过DPRAM传送到DMA控制器;
- 间隔定时器提供识别重要总线定时事件的定时选通: 总线超时间隔,微帧间隔,帧开始间隔,总线复位,恢复和暂停间隔;
- 向DMA引擎报告所有传输状态;
该定时器受控于其自身的控制及装载寄存器: usb.GPTIMERxCTRL and usb.GPTIMERxLD ;
控制寄存器包含定时器配置及一个数据字段,可以查询运行计数值,粒度1us;
Programming And Reference
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G0LmDjLm-1649168263511)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/14_stack.png)]
操作模式控制 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JLQwDDvW-1649168263513)(15_mode.png)]
Device Mode Control
控制器处于控制模式时, 软件启动其控制端点, 根据设备的功能准备描述符并准备必要的端点;
控制器状态 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6JLoJJe-1649168263514)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/16_state.png)]
软件负责维护状态变量以区分默认 FS/HS状态和地址/配置状态;
根据USB2.0协议,根据设备枚举过程中的配置更改相应地址及配置状态;
进入地址状态后,设备地址寄存器由DCD(Device Controller Dirver)操作;
进入配置状态后操作端点控制寄存器并初始化关联的队列达到配置所有需使用的端点的目的;
USB总线复位响应 Host下发初始化指令复位总线;
当检测到总线复位时,设备控制器硬件重新协商连接速度(LS\FS\HS)并将设备地址复位,并通过中断通知DCD,接收到复位后,除控制端点(0端点)外禁用所有端点,并任何已启动的事务都被设备控制器取消;
DCD接收到复位时必须执行如下任务:
- 读取usb.ENDPTSETUPSTAT寄存器并写回usb.ENDPTSETUPSTAT寄存器达到清除所有设置令牌信号量;
- 通过读取usb.ENDPTCOMPLETE寄存器并写回usb.ENDPTCOMPLETE寄存器来清除所有端点完成状态位;
- 等待usb.ENDPTPRIME寄存器中的所有位为0后将0xFFFF_FFFF写入usb.ENDPTFLUSH寄存器达到取消所有已启动状态;
- 读取PORTSC1寄存器中的复位位并确保其保持有效,USB复位时间保持3ms以上,在这之前软件必须完成重置,否则就需要进行硬件复位控制器;
- 向usb.USBCMD [RST]写1进行一次硬件复位,硬件复位后设备清除 运行/停止 位 从而从总线系统上脱离,因此硬件复位后软件需重新初始化控制器;
- 释放所有的dTD,因为他们不再由设备控制器执行; 如果此次复位为DCD的首次执行,那么有可能并没有分配dTD,此时DCD会将控制权移交操作系统,因为在端口更改探测前不允许对设备有任何的更改;
检测到端口变化后,器件达到默认状态,同时DCD读 PORTSC1寄存器确认器件的速率模式; 此时设备控制器已经就已经进入正常工作模式,根据USB2.0协议进行事务响应;
Device Endpoint Data Structures
端点链表描述符组成器件端点的数据结构,软件为其提供初始化并控制;
Link-List Endpoint Descriptors device 控制器存在两种类型描述符: device Queue Head(dQH) ,device Transfer Descriptor(dTD);
DMA引擎使用Link-List描述符来响应来自host的端点包请求;
DCD维护每个队列头的dTD链表的头尾指针; 因为dQH只维护当前工作dTD和下一个执行的dTD;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VdVUSXSm-1649168263516)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/17_device_link_list.png)]
Descriptor and Data Flow
每个端点一个Queue Head;
根据上述章节所描述的内容,驱动层在初始化时初始端点并设置dQH,dQH维护当前执行dTD及下一次dTD,这个结构加上Tx_Buf组成发送数据结构,同时驱动层为达到保护内存的目的去维护dTD的头尾;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Sq78SXf-1649168263517)(18_data_flow.png)]
Manage Endpoints 端点为USB设备唯一可寻址的部分,其作用在于Host和Device的信道中获取或接受数据;
端点地址由端点编号和端点方向共同确定;
Host和Device端点之间为数据管道,Device 的端点0始终适用于设备发现和枚举的控制端点; 端点类型与传输类型一一对应; 端点数量最大12个(针对Zynq);
DCD可以启动, 禁用, 配置端点类型, 每个端点方向独立存在,即可以在每个方向上配置不同的行为; eg: endpoint1 的IN和OUT可以为不同的端点类型;
每一个端点方向在内存中需要一个dQH, 这意味着最高需要24个dQH来描述
Endpoint初始化 硬件复位后所有非0端点都是禁用且未初始化的;
DCD通过写入配置寄存器 usb.ENDPTCTRLx 使能和配置每一个端点;
每个32位 usb.ENDPTCTRLx 分为上半部分和下半部分, 下半部分用于接收或OUT端点,上半部分用于配置相应的发送或IN端点; 控制端点必须在usb.ENDPTCTRLx寄存器的上半部分和下半部分配置相同否则为未定义定位;
Stall 参考USB2.0 chapter 8.4
如下两种情况下Device需要向Host返回STALL:
- Functions Stall: 软件启动(仅限非控制端点);
- Protocol Stall : 硬件启动(控制端点)
Protocol Stall(协议停顿),用于控制端点, 并在新的控制事务(设置阶段)开始时由设备控制符自动清除. 启动协议停顿时,DCD应成对启动停顿位(IN and OUT),对usb.ENDPTCTRLx 寄存器一次写入保证两个停止位同时设置;
注: 任何写入usb.ENDPTCTRLx 寄存器的操作必须保留端点模式字段;
Data Toggle 参考USB2.0 chapter 8.6
数据切换对应到USB2.0 即为包域的Data 0/1 切换及一系列的机制跳转;
DCD可以复位数据翻转状态位, 并通过usb.ENDPTCTRLx [TXR]寄存器中的数据翻转位写入1来使设备控制器中的数据翻转序列复位,这个操作只有在 配置/初始化/从STALL条件返回 时需要执行;
Device Endpoint Packet Operational Model
所有传输由USB Host发起,Device在一定时间范围内进行响应;
主机无法精确预测每个单个管道的顺序去向设备控制器发送请求, 因此无法为设备控制器准备单个数据包来执行,但是 当考虑端点编号和方向时,数据包请求的顺序是可预测的, eg:端点3(传输方向)配置为bulk pipe,那么可预期主机向该端点发送IN请求;
所有传输由USB Host发起,Device在一定时间范围内进行响应;
主机无法精确预测每个单个管道的顺序去向设备控制器发送请求, 因此无法为设备控制器准备单个数据包来执行,但是 当考虑端点编号和方向时,数据包请求的顺序是可预测的,
eg:端点3(传输方向)配置为bulk pipe,那么可预期主机向该端点发送IN请求;
Prime and Flush Endpoints
器件控制器的实现方式为预测主机对每个端点或方向所发出的请求.;
准备响应总线上的主机发起的事务发送或接受数据的设备控制器的过程称为"prime"端点;
"flush"用于清除排队执行的数据包的操作;
flushing一个控制器端点会导致此端点 de-primed(意味着端点必须完成重新初始化才能继续使用);
Prime Transmit Endpoints 启动发送端点会触发控制器获取dQH指向的事务的dTD; 取到dTD后其会被复制到dQH中,直到Device Controller完成dTD描述的传输; 从dQH覆盖区域中复制dTD允许Device Controller获取处理来自主机的请求所需的操作而不需要遵循dTD链表,从接受主机请求的dQH开始;
设备加载dTD后,数据包中的前导数据存储在设备控制器的FIFO中; 此FIFO被拆分为虚拟通道,已达到存储多
端点前导数据的摸底,拆分量取决于初始化时配置的端点量;
启动请求完成后, 端点状态在ENDPTSTATUS寄存器中报告. 对于已启动的发送端点,device controller就可以进行IN事务的响应且严格满足USB总线周转时间;
由于控制器FIFO中只进行前导数据的存储,因此设备控制器需要在事务开始后填充前导数据,同时考虑系统内存总线对FIFO大小的影响;
Prime Receive Endpoints DCD层面接收端点和发送端点一致;
设备控制器层面,其与发送端点区别在于前导数据包数据没有数据移动, 因为数据是从主机接收;
接收FIFO不分通道且大小固定;
中断及批量端点操作模型 中断端点和批量端点操作一致;
所有有效的传输事务通过BULK管道, 端点准备好进行数据传输, 未准备全部返回NAK;
Device Controller会收回dTD当传输描述符中描述的包完成时, 每个dTD描述了根据USB协议的变长协议计算的需传输的N个报文,设备控制器根据最大装载和需传输总字节数计算USB发送和接收数据包的数量和长度,计算公式如下:
N = INT(Number of Bytes/Max. Packet Length) + 1; (With Zero Length Termination dTD.ZLT == 0)
N = MAXINT(Number of Bytes/Max. Packet Length); (With Zero Length Termination dTD.ZLT == 1)
注: dQH.Mult 域在中断 , 批量, 控制传输中必须设置为 “00”
关于dTD.ZLT 在批量及控制传输中的操作:
- 默认值 = 0;
意味着Zero Length Termination开启;
满足下列条件时,硬件会自动附加一个零长度数据包:
- 传输的数据包等于最大数据包长度
- dTD已发出所有字段
- 传输的数据包等于最大数据包长度
- dQH.ZLT = 1,意味着Zero Length Termination关闭;
硬件不在自动添加零长度数据包;
在接收时,其不需要零长度的数据包来销毁最后一个数据包等于最大数据包的dTD. 一旦总字节数为0,或收到一个短数据包,dTD自动销毁;
在一个数据包未完成时,dQH将指向错误的dTD, 并尝试恢复,恢复手段为清除活动位来重新初始化dQH, 并在尝试重新启动端点之前跟新到下一个dTD指针;
注: 类似握手缺失或CRC失败等数据包级操作控制器会自动重传, 不需要与DCD进行交互;
中断及批量端点总线响应
文章图片
注:
- BS Error->强制位填充错误;
- NYET/ACK->NYET除非dTD描述的数据大于最大状态即有剩余的数据包 then ACK(此处对ug585的表述不太理解) 根据抓包判断正常传输返回ACK , 当返回NYET时下次传输Host会在下发OUT事务前先行下发PING包, 那么可以理解为NYET是向主机包括存在下一次接收句柄存在风险(当前包接收成功但没有空间接收下一帧),Host下发PING包确认状态后在下发OUT;
- BTO->总线超时;
- SYSERR->延迟FIFO大小合适 DCD有相应 此错误不会发生;
Endpoint Queue Head Descriptos (dQH) dQH用于所有的Device Controller传输的管理, 大小为48Bytes, 在实现时字节对齐至64字节;
在端点启动时,硬件从系统内存中读取dQH和第一个dTD, 并将其覆盖在dQH的2~8 (双字节),如下:
??Dword 0?? | 端点 特点及容量 |
---|---|
31:30 | Mult. 高带宽管道Multiplier,该字段用于指示每个dTD执行的数据包数量 00: N个数据包 N的取值见chapter C, 非同步传输端点必须设置为 00; 01 : 1个事务, 10 : 2个事务, 11: 3个事务 .同步端点任选 |
29 | ZLT 见chapter C |
28:27 | 保留,设置为0 |
26:16 | 最大装载长度, 对应关联端点的wMaxPacketSize , 最大 0x400 |
15 | 设置时中断, IOS, 被用于控制端点,指示USBINT是否响应接收 |
14:0 | 保留 设置为0 |
Dword 1 | 当前dTD指针 |
31:5 | 指向传输覆盖区域中表示的dTD的指针, 在端点启动或队列推进器件该字段由设备控制器修改为下一个dTD指针. 设备控制器使用当前dTD指针来定位正在进行的传输. 此字段仅由设备控制器硬件使用, DCD不能对其进行操作; |
4:0 | 保留 设置为0 |
Dword 2 | 下一dTD指针及中止 dQH Dword:2 dTD Dword:0 |
31:5 | 下一个要处理的dTD的系统内存指针 |
4:1 | 保留 设置为0 |
0 | 中止传输 T; 0->链接到下一个dTD指针, 且地址有效; 1->中止传输,下一个dTD指针域无效 |
Dword 3 | Total Bytes, MultO, and Status dQH Dword:3 dTD Dword:1 |
31 | 保留 设置为0 |
30:16 | Total Byte: 此次传输描述的字节数总量,在事务成功完成时进行递减 DCD能存储最大值为5*4K = 0x5000; (仅当Dword4偏移量为0时); 一般建议最大值取16KB; |
15 | 完成时中断, 指示是否设置USBINT以响应设备控制器完成此dTD |
14:12 | 当前页 , 器件模式保留 |
11:10 | Multiplier 覆盖,用于传输同步数据包, |
9:8 | 保留 设置为0 |
7:0 | 设备控制器使用该字段将单个命令执行状态返回DCD;
此字段包含在此dTD上执行的最后一个事务的状态; Bit[7]活动状态, bit[6]暂定状态 bit[5]数据缓冲区错误状态 bit[3]传输错误状态 其余位保留 |
Dword 4 | 第0页缓冲区指针及当前偏移量 dQH Dword:4 dTD Dword:2 |
31:12 | Buffer Point : 4KB边界对齐的系统内存地址 |
11:0 | 当前偏移量 |
Dword 5 | 第1页缓冲区指针及帧号 dQH Dword:5 dTD Dword:3 |
31:12 | Buffer Point : 4KB对齐的系统内存地址 |
11 | 保留 |
10:0 | 帧号 ,由设备控制器进行写入,以指示分组完成的帧号; 通常用于将分组的相对完成时间关联在ISO端点上; |
Dword 6-8 | 第2-4页缓冲区指针 dQH Dword:4-6 dTD Dword:6-8 |
31:12 | Buffer Point : 4KB对齐的系统内存地址 |
11:0 | 保留, 设置为0 |
Dword 9 | 保留 |
Dword 10 | 设置缓冲区字节 [31:24]->Byte3 , [23:16]->Byte2 , [15:8]->Byte1 , [7:0]->Byte0 |
Dword 11 | 设置缓冲区字节 |
实现时对齐到32字节;
DCD不能修改正在活动中的dTD任何字段, next dTD可以;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rnqM1kZS-1649168263521)(https://raw.githubusercontent.com/H-voyager/markdown-photo/main/usb-device/21_dtd.png)]
Endpoint Transfer Overlay Area(参考figure15-14) 控制器从内存中读取dQH并链上一个dTD. dTD同样从内存中读取, 并写入dQH的覆盖区;
覆盖区域的7个双字空间代表设备控制器的事务工作空间. 端点准备好后, 设备控制器将把dTD复制到此dQH的这个空间.在传输未完成之前, DCD不能写入队列头覆盖区域或关联的dTD. 传输完成后,设备控制器会将dTD写回系统内存(添加状态结果)并推进队列指针;
如果链表存在后续, 则从内存中取出另外一个dTD并将其写入dQH的传输覆盖区域. 处理完链表,dQH写回系统内存, 端点服务完成.
Device Controller 编程模型
设备控制器的功能是将内存映射中的请求传输到USB或从USB获取. 设备控制器根据应用层协议对端点进行编程和初始化. 控制器执行一组链表传输控制符,dQH指向,设备控制器执行请求的数据传输.
设备控制器初始化 硬件复位之后,器件在Run/Stop位未置为1处于禁用状态, 在禁用状态下, 为防止放生连接,USB 的D+上拉电阻不活动. 为创建连接,须在设备连接发生之前为控制端点 0 设置dQH. 之后设备启动,并进行USB协议的连接控制进行一系列的操作包括再复位,dQH是设备控制器可以存储转入的设置数据包的前提;
为达到初始化器件的目的,DCD必须执行以下操作:
- 设置控制器为器件模式, 向usb.USBMODE [CM] 位写10
- 从主机模式转换到设备模式需要在修改USBMODE之前复位设备控制器
- Set usb.OTGSC [OT] bit = 1.
- 分配并初始化dQH
- 至少为控制端点0 接受和发送初始化dQH\
- 控制端点的dQH初始化必须在端点使能之前;
- 配置端点链表地址
- 使能软件中断
- 在GIC中使能IRQ中断(53/76)
- 在usb.USBINTR 寄存器中使能器件中断 参考table15-2
- USB 中断 (UI)
- USB错误中断 (UEI)
- 端口状态探测 (PCI)
- USB复位接受 (URI)
- DC延迟 (SLI)
- 使能Run Mode 设置Run/Stop位
- 设置运行位后,会发生 Device USB复位, DCD必须监测复位时间并按照总线复位的调整DCD状态;
- 端点0仅设计为控制端点, 不需要进行ENDPTCTRL0寄存器配置;
每个端点存在两个数据结构: IN 和 OUT ;
设备模式数据结构包括一个dQH和N个dTD, dQH定义数据传输类型并指向第一个dTD,dTD包括指向系统内存缓冲区的系统地址, USB数据在此由DMA进行读写;
存在一个dQH链表对24个dQH建立索引, 为建立一次传输,软件需要去为IN/OUT事务构造dQH和dTD. 软件必须在系统内存中为控制器维护一组一致的descriptors, schedules/lists,data buffers .当端点准备好传输数据时软件启动端点;
设备控制器将相关的dQH和dTD读取到控制器的DPRAM中,DMA及协议引擎进行访问. 当dTD的DMNA完成后, 控制器将"dTD + 传输结果"写回系统内存.
当终止位T = 0(存在下一个dTD),则控制器从系统内存中获取下一个dTD, 否则控制器停止处理端点dQH并将dQH写回系统内存, 在一个较长的链表中,控制器将从系统内存与DPRAM之间反复读写dTD;
初始化dQH
-
- 根据控制传输获取的最大装载值并写入wMaxPacketSize字段;
- 向控制,批量, 中断端点的Mult设置为0,同步端点设置为1~3个事务作为与USB协议的交互带宽,在FS模式下只能设置为1;
-
- 中止传输: 设置下一个dTD的中止字段 为 1;
- 将状态字段中的活动位写为0;
- 将状态字段中的HALT位写入0;
Operational Model for Setup Transfers
DCD6应对设置传输包进行特殊处理, 设置传输不使用dTD, 而是将来自设置数据包的输入数据存储在dQH的8字节缓冲区内;
- 从dQH-RX中复制设置缓冲区内容到软件缓冲区;
- 通过将 1 写入usb.ENDPTSETUPSTAT中写入相应位置来确认设置数据包;
- 确认必须发生在继续处理下一设置数据包之前;
- 确认后,DCD将不能访问dQH-Rx的数据缓冲区,DCD的来源只能是软件缓冲区的数据副本;
- 检查来自之前控制传输的未处理数据或者dTD,如果存在,则按照相应规则刷新端点;
- 设备控制器可以在先前的控制传输完成之前接收设置数据包,必须刷新正在进行的现有控制数据包并完成新的控制数据包;
- 初始化前7个双字, 将所有DWord中的所有位写入0;
- 设置中止位,如果仅有一个dTD或此dTD为最后一个,设置中止位为1;
- 状态传输大小进 toatal Bytes 字段
- 根据需求设置完成时中断
- 初始化状态字段 . 设置活跃位为 1 其余状态位为 0\
- 装填第0页数据指针和偏移地址 (偏移地址指向数据缓冲区的起始位)
- 装填第1~4页的缓冲区指针,使其比前面的每个缓冲区指针都大 1;
- 在设备控制器到达dTD链表的末尾时, 添加新的dTD至链表末尾
Link list为空:
- 写入dQH 下一指针和dQH终止位 = 0 (单DWord操作)
- 清除dQH中的活动和停止位 (防止之前的错误设置)
- 装载端点, 将1写入usb.ENDPTPRIME 中的正确位置;
- 添加dTD至链表尾部
- 读取usb.ENDPTPRIME的正确装载位 (1 ->Done)
- 设置usb.USBCMD[ATDTW] 位 = 1
- 读取usb.USBPTSTAT的正确状态位 (存储在TMP中,等待)
- 读取usb.USBCMD[ATDTW]位 0->返回第三步 1->继续第6步
- 写入usb.USBCMD[ATDTW] = 0
- 判断第四步的状态值, 1->Done 0->跳转至Link list为空的第一步;
注: 多个dTD可以在单端点完成通知时完成. 完成通知后,DCD必须检索dTD链表并退出所有已完成的dTD(活动位清除). 通过读取已完成dTD的状态字段,DCD可以通过以下状态位判断传输结果:
Active = 0 & Halted = 0 & Transaction Error = 0 & Data Buffer Error = 0
上述结果之外的所有结果均为失败 ,DCD必须进行相应的措施;
除检查状态为之外,DCD必须读取传输传输字节字段来确认实际传输的字节;
传输完成后, 传输的总字节数减去传输的实际字节数;
对于发送数据包,只有实际字节数达到0 后数据包才为传输完成;
对于接受数据包,Host可能会根据USB的可变数据包协议在传输中发送较少的字节数;
端点 Flushing/de-Priming
当接受到USB设备复位, 发生控制传输中断,DCD必须flush位来对一个或多个端点进行卸载, 应用层面的停止传输同理; 实现步骤如下:
- 向usb.ENDPTFLUSH 的通信位写1;
- 等待usb.ENDPTFLUSH所有位为 0; 这个操作比较耗时,不应该放在中断中
- 读取usb.ENDPTSTAT位确保所有通过命令flush的端点的通信位为 0 ; 如果在第二步执行完毕后该位仍旧为1 则flush失败: 重复执行,因为控制器在特定时刻有一个保护;
控制器不自动handle的包错误如下:
文章图片
除上表中同步传输外所有的传输类型的所有错误都由控制器处理(数据缓冲区溢出除外)
- 添加dTD至链表尾部
- 读取usb.ENDPTPRIME的正确装载位 (1 ->Done)
- 设置usb.USBCMD[ATDTW] 位 = 1
- 读取usb.USBPTSTAT的正确状态位 (存储在TMP中,等待)
- 读取usb.USBCMD[ATDTW]位 0->返回第三步 1->继续第6步
- 写入usb.USBCMD[ATDTW] = 0
- 判断第四步的状态值, 1->Done 0->跳转至Link list为空的第一步;
注: 多个dTD可以在单端点完成通知时完成. 完成通知后,DCD必须检索dTD链表并退出所有已完成的dTD(活动位清除). 通过读取已完成dTD的状态字段,DCD可以通过以下状态位判断传输结果:
Active = 0 & Halted = 0 & Transaction Error = 0 & Data Buffer Error = 0
上述结果之外的所有结果均为失败 ,DCD必须进行相应的措施;
除检查状态为之外,DCD必须读取传输传输字节字段来确认实际传输的字节;
传输完成后, 传输的总字节数减去传输的实际字节数;
对于发送数据包,只有实际字节数达到0 后数据包才为传输完成;
对于接受数据包,Host可能会根据USB的可变数据包协议在传输中发送较少的字节数;
端点 Flushing/de-Priming
当接受到USB设备复位, 发生控制传输中断,DCD必须flush位来对一个或多个端点进行卸载, 应用层面的停止传输同理; 实现步骤如下:
- 向usb.ENDPTFLUSH 的通信位写1;
- 等待usb.ENDPTFLUSH所有位为 0; 这个操作比较耗时,不应该放在中断中
- 读取usb.ENDPTSTAT位确保所有通过命令flush的端点的通信位为 0 ; 如果在第二步执行完毕后该位仍旧为1 则flush失败: 重复执行,因为控制器在特定时刻有一个保护;
控制器不自动handle的包错误如下:
[外链图片转存中…(img-zdzCOdQY-1649168263522)]
除上表中同步传输外所有的传输类型的所有错误都由控制器处理(数据缓冲区溢出除外)
推荐阅读
- 嵌入式开发|使用stm32配置自定义的HID设备
- 历史上的今天|【历史上的今天】7 月 31 日(“缸中之脑”的提出者诞生;Wi-Fi 之父出生;USB 3.1 标准发布)
- hi8pro|Hi8 pro加装USB 2.0接口
- 业界资讯|苹果被迫弃用 Lightning(欧盟宣布 2024 年 Type-C 将 “一统天下”)
- 如何使用USB和EFI Shell格式化Windows 10的Medion Akoya S2218笔记本电脑