2025年2月更新,Step to UEFI 文章索引:
【翻译】USB 2.0 简述
本文翻译自 https://embeddedinn.com/articles/tutorial/usb-2-0/#history-of-revisions
USB(Universal Serial Bus,通用串行总线)是一种以主机为中心的 4 线总线协议,旨在提供标准、低成本的接口,具有自识别、动态连接的外围设备,可自动将功能映射到驱动程序和配置,并具有低协议开销、保证带宽和低延迟,适用于电话、音频、视频等要求苛刻的应用。
USB规范由包括惠普、英特尔、LSI、微软、瑞萨和意法爱立信在内的多家主要厂商联合制定。该规范及其认证由USB开发者论坛(USBIF)负责维护。
版本历史

版本 1.0(1996 年 1 月 15 日)
- 低速传输速率为 1.5 Mbps
- 全速传输速率为 12 Mbits/s。
修订版 1.1(1998 年 9 月 23 日)
- 改进了规格,是第一个被广泛使用的USB版本。
修订版 2.0(2000 年 4 月 27 日)
- 高速传输速率为 480 Mbits/s。
修订版 3.0(2008 年 11 月 17 日)
- 超高速 USB(原始数据吞吐量高达 5.0 Gbit/s)
本文将重点介绍高速 USB 协议修订版,俗称 USB 2.0。
基础知识
总线拓扑结构
基本 USB 遵循如下图所示的层级星型拓扑结构。

主机位于层级结构的顶端,所有“功能”最终都连接到主机。“hub”用于扩展“root hub”(主机的最终端点)的连接性。hub是每一层级的中心,每一层级都以hub为中心构建星型拓扑结构。

USB协议中每个操作都有一个最大延时。为此,最大延时限制了层级数量为7层——包括顶层(根/主机)。包含Hub和其他功能的组合称为“复合设备”。由于不允许再增加层级,因此第7层不应包含Hub。
系统组件
USB系统由三个主要部分组成:USB设备、USB主机和USB接口。
USB 设备可以是提供额外 USB 连接点的Hub集线器,也可以是为系统提供额外功能的设备。
任何USB系统中都只有一个主机。与主机系统连接的USB接口称为主机控制器。主机控制器可以用硬件、固件或软件实现。主机系统内部集成了一个根Hub,用于提供一个或多个连接点。
USB接口是总线的物理接口,由总线的电气和机械规范进行描述。
USB互连和信号传输
互连
USB 通过铜线使用 4 线物理接口实现规定的协议速度。该总线还为设备供电。

电缆的最大长度取决于信号延迟和信号完整性。标准电缆符合如图所示的颜色编码。

信号传导
USB协议采用电缆D+和D-线上的差分信号传输。数据使用NRZI协议编码,并以J(电流流入D+线)和K(电流流入D-线)表示。
在NRZI编码中,0流通过每比特时间翻转一次JK键来表示,而1流则保持D+和D-线的先前状态。单端零(SE0)信号通过同时驱动D+和D-线来发出。

主机和设备之间的同步由两端的数字锁相环 (DPLL) 维持。然而,长时间的 1 序列会导致 DPLL 失去同步,因此,每连续 6 个 1 之后会“填充”一个 0。这称为比特填充。
“比特时间”取决于函数运行的速度模式。例如,低速运行的设备的数据速率为 1.5Mbps,因此一个比特时间就是 (1/1.5 微秒)。
速度模式是通过 D+ 和 D- 线中的终端电阻来区分的。
对于低速器件,D- 线末端会连接一个 1.5K 欧姆的上拉电阻;而对于全速/高速器件,D+ 线也会连接类似的上拉电阻。因此,高速器件最初会像全速器件一样工作。该器件会生成一个“high speed chirp”,即一组 15 个 JK 对,用于向主机表明其为高速器件(480Mb/s)。
一旦检测到速度模式,主机便会启动“枚举”过程,这实际上就是配置该功能以供使用。但在深入了解枚举细节之前,我们需要了解一些基本术语。这将在下一节中进行解释。
协议基础知识
基本术语
- 信号模式(Signalling mode),USB2.0 支持下面三种模式
- 低速:1.5Mb/s
- 全速:12Mb/s
- 高速:480Mb/s
- 主机(Host)
是指连接 USB 设备的计算机系统(也可以是嵌入式系统)。主机发起所有通信,并且是总线的主控端。在总线拓扑结构中,只能有一个 USB 主机。 - 设备(Device)
是指连接到主机的 USB 功能设备。一个设备可能包含多种功能,这些功能可能同时可用,也可能不可用。这将在后续章节中详细讨论。 - 设备地址(Device Address)
主机在设备连接时为其分配的唯一 7 位地址。主机使用此地址将所有通信定向到目标设备。设备首次连接到主机时,其地址为 0(默认地址)。 - 端点(End Point)
是设备中主机可以与之通信的最细粒度的分类。端点通常实现为一个缓冲区,主机向该缓冲区发送数据(无论是否与特定协议相关)。
每个 USB 设备都应该有一个默认端点 0 (EP0),主机使用该端点来识别设备的功能并向其发送配置信息。
最多可以有 31 个端点,包括 EP0。除 EP0 外,所有端点均为单向的,每个端点都由一个唯一的 4 位端点编号及其方向标识。端点方向由 8 位端点地址的低半字节表示。因此,EP1 IN 的地址为 0x10,EP1 Out 的地址为 0x18。
- 管道(Pipe)
主机上某一点与设备上某一点之间的逻辑连接。一个设备最多可以有 31 个管道,包括终止于 EP0 的默认管道。
USB 管道分为两种类型:单向流管道(可以传输任何格式的数据)和流管道(可以传输没有指定格式的数据)。
EP0 默认始终是消息管道,而到其他端点的管道都是流管道。

- 接口和配置(Interface and configuration)
接口和配置是功能内部各项能力的两级层次结构。一个功能(设备)可以有多个配置,每个配置又可以关联多个接口。每个接口可以关联多个端点。在任何给定时间点,主机只能加载一个配置。接口对端点进行逻辑分组,从而简化了设备驱动程序的加载。
主机通过设备描述符、接口描述符和端点描述符读取设备的配置和接口功能。这些信息是在主机向设备发出某些标准命令时传递给主机的。
设备运行期间,主机可以加载或卸载特定的接口/配置。

- 设备类别(Device Class)
USB 设备被分为不同的类别,以便于驱动程序的开发和分类。但是,并没有规定设备必须属于某个类别规范。经过认证的设备仍然可以使用完全专有的驱动程序。然而,该设备必须符合 SUB 2.0 规范第 9 章中规定的基本协议行为,并满足电气和机械兼容性要求。 - 帧(Frame)
无论目标设备如何,USB总线上的所有通信都以帧为单位进行分段传输。对于低速/全速设备,帧宽为1毫秒;而对于高速设备,帧宽为125微秒。每个帧都由一个11位帧号标识,该帧号以称为帧起始信息(SOF)的特殊数据包的形式发送。帧内可以包含多个数据包,这些数据包将被发送到不同的设备。数据包的实际传输过程将在以下章节中进行详细说明。


- 挂起(Stall)
当终端设备未准备好发送或接收数据时,它会发送 NAK响应
。而如果终端设备收到错误的命令或由于某些内部错误而无法响应,则设备会发送 STALL 握手响应。收到 STALL 握手响应后,主机必须采取纠正措施来恢复终端设备的功能。
- 超时(Timeout)
连接到拓扑结构最后一层(第 7 层)的高速设备最多需要 736 Bit时间才能响应任何主机请求。如果在 816 bit时间内未检测到信号,主机将超时。超时后,主机将发出重置指令并尝试重新枚举该设备。
USB基本通信流程

USB总线上的所有数据通信都以数据包的形式进行。通信由主机发起,主机向设备和端点发送一个令牌数据包,后续数据包将指向该令牌数据包。令牌数据包包含一个8位数据包标识符(PID),用于标识即将发生的事务类型。

PID 实际上为 4 位宽。低半字节是高半字节的补码,用于进行有效性检查。
令牌包之后会有一个方向与令牌包中指定的方向相同的数据包。对于不同类型的令牌,这是一个可选阶段,相关说明请参见本文档的相应部分。
交易完成后,会向其发送握手包。
主机每毫秒(LS 或 FS 设备)或每 125 微秒( HS 设备)广播帧开始 (SoF) 数据包。
因此,每笔传输(transfer )都包含多笔事务(transactions)。每笔事务分为三个阶段。
- 令牌阶段(token stage:):主机向目标设备发出令牌数据包(token packet),以便进行后续通信。该令牌数据包还指示传输方向。
- 数据阶段(Data Stage):实际数据传输通过数据包(data packet)进行。
- 状态阶段(status stage):数据传输通过握手得到确认。



枚举
识别 USB 设备的功能并将其映射到主机系统中相应的驱动程序的过程称为“枚举”。设备枚举完成后,主机就能了解其速度模式、可用端点数量及其属性和类别等信息。具体步骤如下。
这里我们假设只有一个设备直接插入主机的根集线器。
- 设备插入集线器端口后,总线将复位,SE0(D+ 和 D- 低电平),然后总线上电。
- 接下来,通过数据线上拉电阻检测设备的速度模式。
- 低速器件的 D- 线会连接一个 1.5 K欧姆的电阻,而全速/高速器件的 D+ 线则会连接一个 1.5 K欧姆的电阻。
- 高速设备启动时以全速运行。主机重置总线后,设备会发送一个低频啁啾信号(16个JK对),向主机表明设备已具备高速运行能力。主机会以反向啁啾信号确认此信号。
- 一旦检测到速度模式,主机就会向 EP0 发出名为“GetDescriptor (device)”的“标准请求”,以读取连接设备的功能。

- 描述符的解读是多层次的,因为描述符根据其所传达的信息类型而按层次进行区分,正如上一节所述。
- 首次读取设备描述符后,如果主机支持该设备(由各种因素决定),则总线再次重置,并为该设备提供一个唯一的 7 位地址。
- 将设备置于目标状态后,即可通过其他描述符读取设备的更多详细信息,如下图所示。

- 当读取完设备的所有可用配置后,可以使用设置配置命令。该命令使用索引来指定要选择的设备配置。
- 配置完成后,相应的类驱动程序(稍后会详细介绍类)将被加载,并生成类规范。
设备枚举完毕且端点配置完成后,逻辑通信安排如下图所示。

系统软件主要是根集线器驱动程序,它负责跟踪所有连接到它的设备。任何与配置相关的通信都通过默认管道 EP0 进行。
特定于端点的驱动程序可以通过相应的管道进行通信。




传输模式
如前所述,一个USB设备可以包含多个端点。每个端点可以是输入端点(IN)或输出端点(OUT),具体取决于数据传输方向。另一种分类方法是基于端点上发生的数据传输类型。
USB总线上发生的四种传输类型是:
- 控制权传输(Control Transfer)
- 批量传输(Bulk Transfer)
- 同步传输(Isochronous transfer)
- 中断传输(Interrupt Transfer)
在枚举过程中,处于工作状态的端点(比如,一个USB设备可能总共有16个端点,但是实际只使用了6个端点)将会分配为上面传输类型的一种。比如,端点1 用于 批量传输,端点2使用中断传输。之后的过程中并不会改变传输类型。
控制传输
控制传输用于主机和 EP0 功能(设备)之间的通信。例如,第 9 章中的命令事务,如 SetAddress、Getdescriptor、SetDescriptor 等。
控制传输分三个阶段进行,即
- 建立阶段 setup stage
- 数据阶段 data stage
- 握手阶段handshake stage


建立阶段从主机发送的建立令牌(setup token )开始,然后是包含实际命令信息的数据包,随后是确认阶段。
数据阶段是可选的。接下来会有一个可选的数据阶段,具体取决于所发出的命令类型。例如,`set configuration` 命令将要设置的配置索引嵌入到命令中,因此不需要单独的数据阶段;而 `Getdescriptor` 命令则需要多个数据阶段来传输所有必需的信息。
即使多个设备连接到主机,控制传输始终保证占用总线带宽的 10%。也就是说,在 1 毫秒内(对于高速设备,则为 125 微秒微帧的 20%),始终有 10% 的时间用于控制传输。这是因为如果其他端点出现数据错误,控制传输会用于对这些功能执行纠正措施。
同步传输
这种数据传输模式可以保证访问 USB 总线带宽。
总线带宽
USB 通信以帧的形式进行。每个帧可以包含发往多个设备的传输。带宽是指在 1 毫秒/125 微秒的帧中分配给特定设备的时间。考虑到传输速度模式(1.5/12/480 Mb/s),带宽可以转化为数据量。

中断传输
中断传输提供了一种机制,可以确保设备和主机之间在周期性的时间间隔内进行通信。
当枚举中断端点时,可以指定轮询间隔,范围从每帧一次到每 255 帧一次。
如果在轮询时设备没有数据要传输,则下一次重试将在下一个服务帧中进行。
每个事务的最大数据包大小为 8 字节(LS)、64 字节(FS)或 1024 字节(HS)。

下图显示了光电鼠标中断端点的端点描述符以及端点的周期性轮询。

关于“保持连接”的说明:
所有连接低速设备的集线器端口都必须生成一个低速保活选通信号,该信号在帧的开头生成,包含一个有效的低速 EOP。在接收到 SOF 的每个帧中,该选通信号必须至少生成一次。此选通信号用于防止总线上没有其他低速流量时,低速设备挂起。
批量传输
当需要在终端和主机之间传输大量非时效性数据时,会使用批量传输。使用批量数据传输机制的设备包括闪存盘(大容量存储设备)、打印机、扫描仪等。对于这些设备而言,数据内容的可靠性比数据传输速率更为重要。因此,批量传输的可用带宽会因连接到主机的其他设备的配置而逐帧变化。

USB可靠性
错误 (Errors)
由于各种原因,USB总线通信可能会出现错误。本节简要概述常见错误以及USB框架实现的相应恢复机制。
错误类型(Error Types)
- PID 错误
8 位 PID 实际上由一个 4 位 PID 和一个 4 位 PID 补码构成,如下图所示。如果出现不匹配,设备将不会响应,并且主机端会发生超时(参考:USB 2.0 规范的 8.3.1 节)。
对所有设备进行 PID 完全解码是强制性的。

- PID 之后的CRC 错误
字段用于计算循环冗余码,该码用于验证接收数据的完整性。任何 CRC 校验错误的数据都将返回 NAK(无效确认)。
令牌包和SOF包的CRC校验码为5位,数据包的CRC校验码为16位。握手包没有CRC校验码。

- 无效命令:
当端点收到“完整但逻辑错误”的数据包(例如错误命令)时,或者设备内部出现故障导致端点无法使用时,端点将停止工作,并且任何发送到该端点的请求都会返回 STALL 握手作为响应。
错误处理(Error Handling)
- NAK
- 当主机收到设备返回的NAK时,前三次重试将由硬件触发。之后,将由软件介入。
- STALL
- 当某个端点发生阻塞( STALL)时,主机必须发送一个 ClearFeature 命令,其中包含指向要清除接口的“功能选择器值”。该命令会发送到控制端点 (EP0)。因此,即使某个端点停止工作,ClearFeature 也会应用于该接口下的所有端点。
- Timeout超时
- 当设备在指定的时间间隔内没有向主机发送任何信号时,主机将通过施加复位信号(在数据线上驱动 SE0 超过 2.5us)来复位设备。

用于同步的标志交替
USB 采用一种称为标志交替的简单机制,以确保主机和设备之间传输的数据同步。
在进行数据传输时,主机使用两种类型的数据令牌,分别是 Data0 和 Data1。初始数据传输使用 Data0 令牌。收到设备的 ACK 确认后,下一条数据将使用 Data1 令牌发送。设备还维护一个序列位,该序列位在成功确认传输后会被翻转。

但是,如果出现问题导致数据不被接受(发送 NAK),则主机和设备会保持序列位状态,并使用前一个数据令牌类型立即进行下一次传输。

假设总线上丢失了 ACK,主机未收到该 ACK,则主机使用相同的令牌(DATA0)重新发送数据。然而,在设备端,由于之前的事务,序列位已被翻转。因此,设备会忽略接收到的数据并发送 ACK。


USB类
枚举完成后,实际的设备通信由主机内部的驱动程序发起,该驱动程序了解设备的行为。USB 协议非常灵活,可以同时使用现有驱动程序和新驱动程序,因此 USB 既可以作为接口,也可以作为通信媒介。这是通过将 USB 设备划分为不同的类,并使用过滤器类型的驱动程序层次结构来实现的。
我们将通过考虑众所周知的存储设备(即 USB 闪存驱动器)的例子来尝试理解 USB 类的概念。
USB闪存盘主要由大容量存储器和连接到USB控制器的存储器控制器组成。

典型的U盘会有一个遵循SCSI协议的内存控制器接口。SCSI协议与USB类似,用于在逻辑块地址级别对内存进行完全控制。因此,枚举完成后,设备(U盘)会作为从设备响应主机发出的SCSI命令。
SCSI 的每笔交易都有 3 个阶段,即
- 命令阶段(Command stage)
- 数据阶段(Data Stage)
- 状态阶段(Status Stage)
文件表和所有逻辑内存处理都由驻留在主机上的 SCSI 驱动程序完成。
SCSI 驱动程序是一个通用驱动程序,与 USB 协议没有任何关系。USB 作为一种总线协议,充当主机和设备之间传输 SCSI 协议数据单元的媒介。这通过在接口级别将设备识别为大容量存储类设备 (MSC 设备) 来实现。一旦设备被识别为具有 MSC 接口,主机就会加载 MSC 驱动程序栈。任何与被指定为 MSC 接口的接口之间的通信都将由 MSC 驱动程序发起,它会向根集线器驱动程序发送请求。根集线器驱动程序 (RHD) 会收集来自不同驱动程序的多个请求并形成帧。
MSC接口驱动程序的主要部分是对实际SCSI驱动程序的封装。SCSI驱动程序会向MSC驱动程序发送请求,这些请求随后由根集线器驱动程序(RHD)通过USB传输。然而,SCSI驱动程序无需了解USB协议或结构。它可以调用MSC驱动程序API,进而向RHD发送请求。另一方面,RHD也无需了解任何SCSI或MSC特有的实现细节。

下图清晰地展示了SCSI命令是如何嵌入到USB传输中的。



因此,基于类的架构使得USB设备能够通过现有的驱动程序进行控制,而该驱动程序的实现与USB协议无关(重用现有驱动程序)。
主机工作流程
到目前为止,我们一直专注于单个设备连接到根中心的情况。然而,该协议的设计能够处理以分层星型拓扑结构连接的多达 126 个设备。在本节中,我们将讨论主机如何调度事务到同时连接到它的多个不同速度模式的设备。

从拓扑图中可以看出,所有设备都通过称为集线器的端口扩展单元连接到根集线器上的一个节点。集线器有一个连接到主机的上游端口和一个下游端口,下游端口为设备提供连接点。
因此,集线器在USB总线拓扑结构中扮演着重要角色,它承担了主机的部分“职责”,例如频繁发送“保持连接”信号。本教程不讨论集线器协议。
一旦多个设备连接到拓扑结构,主机就会给每个设备分配一个唯一的 7 位地址。为此,初始通信将使用设备地址 0(设备在获得实际设备地址之前的默认地址)。主机和集线器之间会协作防止使用地址 0 进行设备寻址。
一旦确定了设备,主机就会根据前面章节中描述的描述符读取设备的“功能”和“要求”,从而对设备进行实际枚举。
如果设备请求的资源超过主机可用资源,则该设备不会被枚举。为了详细说明此用例,假设有三个同步端点(函数)已被枚举,并占用了所有可用带宽。当新连接的设备请求一些不可用的带宽(因为该带宽已被已枚举的设备占用)时,主机将不会枚举该设备。
设备枚举完成后,主机将根据端点类型和从客户端软件收到的请求创建其内部数据结构。以下将对此进行简要说明。
设备枚举完成后,主机上会为该设备生成一个端点数据描述符。这可以看作是链表的头节点,链表中包含要传输到特定设备端点的数据。附加到该端点的是传输描述符,其中包含要发送到端点的数据。客户端软件(设备驱动程序)请求中包含的数据将作为传输描述符附加。
向多个端点发送传输请求的调度是基于帧号进行的。例如,一个中断端点可以请求每 10 帧轮询一次,那么主机就会调度每 10 帧发送一次相应的传输描述符。如图所示,传输描述符可以包含一个 IN 令牌。


本文数据取自Ellisys USB 分析工具和 USB 2.0 规范本身提供的插图。
可编程降压芯片MP8869S测试
降压芯片/方案能够帮助我们将一个高电压的 DC 降低成合适的低电压。市面上也有很多降压模块可供选择,通常上面有一个可调电阻,通过旋转调整电阻实现期望的输出电压:

但是能够实现可编程的降压模块非常罕见。这次基于 MP8869 来制作一个可编程降压模块。
MP8869是一款集成I2C接口的高频同步降压转换器,主要特性如下:
核心参数
- 输入电压:2.85-18V
- 输出电流:12A连续/15A峰值
- 输出电压:0.6- 5.5V
- 封装:QFN-14(3mm×4mm)
首先进行电路图设计:

电路图中需要注意的位置有:
1.L1 的选择,如果你有大电流的需求,那么需要特别注意 L1 的参数是否能够承载你的要求,这里选择的是 14A 的
2.R1 和 R2 决定芯片开始工作后的电压,公式如下:

当前使用 R1=82K,R2=75K, 默认 Vref 是 0.72V, 上电后的输出电压为 0.72*(82+75)/75=1.5072V
3.编程控制 Vref 的输出,从上面的公式可以看到 R1 R2 是固定的, Vref 决定最终的输出
4.RA0_UP 和 RA0_DOWN 决定芯片的 I2C 地址,默认不上件地址为 0x61

5.Vout 是通过SW Pin输出的
6.EN 拉高开始工作,实际使用时可以将这个引脚直接连接到 Vin 这样上电即可工作
PCB 设计如下:

最终成品如下:

下面就可以进行测试了。
编写一个库,提供如下功能:
- 输出当前芯片版本
- 输出当前电流和电压
- 设置输出电压
工作的测试视频,测试中 R1=75K R2=82K ,此外,还测试了 R1=39K,R2=82K 的情况。根据公式可以得知这两种组合提供的电压范围不同。
最后芯片还提供了编程控制 EN 功能,电压斜率控制,过流保护,软停止,最大电流限制,过流指示,温度超限提示等功能,有需要的朋友可以继续研究。
特别注意:这次使用的是 MP8869S 型号,此外还有一款MP8869(不带后缀),最大的却别在于后者的参考电压调节范围为 0.6V 至 1.87V, 这样的话,可以直接覆盖 0.6×3=1.8V 到 1.87×3=5.61V。
电路图和PCB下载(立创EDA):
Arduino 库下载:
特别注意:在测试中发生了芯片烧毁的问题,猜测可能是因为测试时有过一次Vin先断电的情况,这样会导致 Arduino 从 I2C 灌入5V 电流导致的。
【翻译】USB线缆的最大长度
USB线缆的最大长度
USB 线缆的长度不仅仅关乎便利性,它还会直接影响线缆的性能。负责制定和维护 USB 标准的 USB-IF(USB 开发者论坛)制定了相关指南,以确保最佳功能和信号完整性。然而,这些建议会因 USB 版本的不同而有所差异。
早期 USB 版本 – 定义长度
对于早期的 USB 标准,USB-IF 设定了特定的最大长度,以确保可靠的性能:
USB 1.0:最大长度为 3 米(约 10 英尺)
USB 2.0:最大长度为 5 米(约 16 英尺)
选择这些长度是为了最大限度地减少长距离传输过程中信号丢失和延迟等问题。
USB 3.x 及更高版本——聚焦性能标准
随着 USB 3.0(现也称为 USB 3.2 Gen 1)及后续版本的推出,USB-IF 改变了其策略。该组织不再规定最大线缆长度,而是强调性能标准,例如:
信号传播延迟(信号沿电缆传输所需的时间)
衰减(信号强度随距离的损失)
因此,USB线缆的实际最大长度取决于其满足这些性能要求的能力。以下是现代USB标准典型长度的细分:
USB 3.2 Gen 1(USB 3.0、USB 3.1 Gen 1):最远可达 2 米(约 6 英尺)
USB 3.2 Gen 2(USB 3.1 Gen 2):最远可达 1 米(约 3 英尺)
USB 3.2 Gen 2×2:最远可达 1 米(约 3 英尺)
USB4:最大传输距离限制为0.8米(约2.6英尺)
为什么新标准需要更短的电缆?
较新的USB标准线缆长度更短,这反映了其更高的数据传输速率和更严格的性能要求。例如:
USB 2.0:支持高达 480 Mbps 的传输速度,允许使用更长的电缆而不会出现明显的信号衰减。
USB 3.2 Gen 2 和 USB4:运行速度更快(USB4 最高可达 40 Gbps),因此长距离传输时的信号丢失和干扰是一个关键问题。
为了克服这些限制,用户可以选择有源USB线缆或带有信号放大器的USB集线器来延长传输距离。这些设备可以放大信号,从而实现更远距离的连接,且不会影响性能。
确保USB线缆的兼容性和性能
为确保 USB 线缆可靠运行,请选择 USB-IF 认证的线缆,因为它可以保证符合性能和质量标准。认证线缆经过兼容性测试,让您安心使用;而未经认证的线缆则可能导致性能不稳定或故障。此外,选择与 USB 版本相匹配的线缆对于实现最佳功能也至关重要。
【翻译】解码 USB:型号和版本
原文在 https://www.tomshardware.com/features/usb-decoded-all-the-specs-and-version-numbers
从USB Hub到充电器、个人电脑、家用电器和树莓派,通用串行总线 (USB) 的应用可谓无处不在,名副其实。但由于 USB 拥有十多种不同的版本、大量的接口以及各种传输速率和充电功能,因此它也是一套庞大的标准,如果您不清楚自己的需求,很容易感到困惑。
如果你查看一款顶级游戏笔记本电脑或游戏台式机的规格表,可能会看到它配备一个 USB 4 接口、一个 USB 3.2 Gen 2 接口和两个 USB 2 接口。但这些接口到底是什么意思?它们各自又能提供哪些功能?这里为你准备了答案,帮助你了解每种 USB 接口的功能。
USB 版本、版本名称和速度
如果您使用 USB 接口传输数据而非仅充电,那么最重要的是了解连接的最高速度。因为要以高达 10 Gbps 的速度将文件复制到外部 SSD,您需要确保连接链上的每个环节都支持该速度:主机、数据线和硬盘本身。
如果每个 USB 端口和产品都能在其上或至少在规格表上标明最高传输速度,那就太好了。事实上,USB-IF(USB 开发者论坛)——USB 标准的维护者——也希望如此。该组织最近推出了一种新的命名规则,将所有速度达到或超过 5 Gbps 的端口分别命名为 USB 5 Gbps、USB 10 Gbps、USB 20 Gbps 或 USB 40 Gbps,不再使用版本号。获得 USB-IF 认证的 USB 产品制造商可以获得带有 USB 传输速度标识的徽标,并将其用于产品包装上。

(图片来源:USB.org)
然而,大多数USB设备并未经过官方认证流程。即使某款产品通过了认证,您仍然很可能会看到它以数字版本号(例如USB 3.2)而非速度标识进行宣传。您可能还会看到USB产品被标注为高速USB、超高速USB、超高速USB 10 Gbps或超高速USB 20 Gbps。虽然“超高速”名称已被弃用,但仍出现在一些包装和营销材料中。
| 版本 | 工作速度 | SuperSpeed Name | Speed Name | 接口形式 |
| 1.1 / 1.0 | 12 Mbps | – | – | Type-A, Type-B |
| 2.0 | 480 Mbps | Hi-Speed USB | – | Type-A, Type-B, Type-C,Mini, Micro |
| 3.0 / 3.1 Gen 1 / 3.2 Gen 1 | 5 Gbps | SuperSpeed USB | USB 5 Gpbs | Type-A, Type-B, Type-C,Micro |
| 3.1 Gen 2 / 3.2 Gen 2 | 10 Gbps | SuperSpeed USB 10 Gbps | USB 10 Gbps | Type-A, Type-C |
| 3.2 Gen 2×2 | 20 Gbps | SuperSpeed USB 20 Gbps | USB 20 Gbps | Type-C |
| USB4 | 20 / 40 Gbps | USB 20 Gbps / USB 40 Gbps | Type-C | |
| USB4 Version 2 | 80 Gbps / 120 Gbps (asymmetric) | Type-C |
USB 3.x 的版本众多,我们专门制作了一篇关于USB 3.2 和 USB 3.1 的详细解释文章,帮助您更好地了解它们。不过,需要注意的是,USB 3、3.1 和 3.2 都提供 5 Gbps 的连接速度,版本号后带有“Gen 2”表示速度提升至 10 Gbps,而带有“Gen 2×2”则表示速度提升至 20 Gbps。
USB接口
你可能会在设备上看到六种以上的常见USB接口。其中一些接口在特定类型的设备上更为常见。

USB Type-A
USB-A接口的历史可以追溯到20世纪90年代,它是最早的USB接口,至今仍是应用最广泛的USB接口。它呈矩形扁平状,只能以一个方向插入电脑。大多数外设和电脑都配备USB Type-A接口,只有一些超极本由于追求厚度而无法使用这种接口。USB Type-A接口可能支持USB 1.1、USB 2或USB 3.x,传输速度可以是5Gbps或10Gbps,但这取决于设备或线缆的具体支持情况。USB 3.x接口有时是蓝色的,而支持10Gbps传输速度的接口有时是红色的。
USB Type-B
USB-B 主要用于打印机等体积较大的外设。它也常见于 USB 集线器或内置 USB 集线器的显示器上,不过 B 型端口始终是连接集线器/显示器和电脑的线缆的一部分。【LABZ: 这种接口最大的特点是足够牢固,因此很多测试设备也会使用这种形式的接口】
Mini USB (迷你 USB)
Mini USB接口最早出现于世纪之交,与USB 2.0规范一同问世,如今已基本被Micro USB取代,成为历史。不过,你或许还能在一些老式游戏手柄或数码相机上看到迷你USB接口。严格来说,Mini USB既有A型也有B型,但市面上常见的通常只有B型。
Micro USB(微型USB)
虽然 USB-C 是一种更新、更好的接口,尺寸也差不多,但你仍然会在许多设备上看到 micro USB 接口,从入门级安卓平板电脑到树莓派、微控制器、数码相机、移动电源和智能家居设备,不一而足。严格来说,micro USB 同时存在 A 型和 B 型,但你通常只会看到 B 型。
USB Type-C
如今市面上大多数新电脑都至少配备一个 USB-C 接口(有些甚至更多)。这些线缆的插头呈长方形,与其他 USB 接口不同,正反面都可以插入使用。
USB-C 线缆可以传输数据、视频和电力(最高可达 240 瓦),但并非所有线缆都支持所有这些功能,因此您需要查看规格说明。许多新款键盘、鼠标以及几乎所有新款智能手机和平板电脑都配备了 USB-C 接口。
USB电源标准
除了苹果的iPhone之外,几乎所有移动设备都可以通过USB充电。你也可以通过USB连接为任何一款顶级超极本或便携式显示器供电。但并非所有USB端口和线缆都有相同的供电能力。
| 标准 | 接口类型 | 最大功率 | 最大工作电流 | 伏特 |
| USB 3.2 / 3.1 / 3.0 | USB-A、USB-B | 4.5瓦 | 900ma | 5伏 |
| USB 电源传输 (PD) | 仅限 USB-C | 240瓦 | 5A | 5V、9V、15V、20V、28V、36V、48V |
| USB电池充电(BC) | USB-A、USB-C | 7.5瓦 | 1.5A | 5伏 |
| USB-C(非PD) | USB-C | 15瓦 | 3A | 5伏 |
| USB 2.0 | USB-A、USB-B、micro USB | 2.5瓦 | 500ma | 5伏 |
一些最新的USB设备包装上可能会印有输出功率的标识,但这种情况目前并不常见。大多数现代手机充电器和所有笔记本电脑充电器都使用某种USB PD协议,但并非所有USB PD设备的最大功率都相同,因此务必检查充电器和线缆的功率。对于笔记本电脑而言,60W是最常见的最低功率,而超过100W的则较为少见,因为这是一个较新的标准。
通过 USB 传输视频
DisplayPort 替代模式(Alt Mode)是简化现代 PC(尤其是笔记本电脑)线缆连接的另一种方式。借助 DisplayPort 替代模式,USB-C 线缆可以传输非 USB 信号。也就是说,计算机可以通过 USB-C 线缆传输 DisplayPort 信号。
虽然这对于台式机来说可能算不上什么问题,但对于笔记本电脑来说却是一大优势。USB-C 接口的物理尺寸比 HDMI 或 DisplayPort 接口要小,因此能够在保持笔记本电脑尺寸小巧的同时传输 DisplayPort 信号,对 PC 厂商来说无疑是一大福音。
遗憾的是,通常无法仅凭外观判断笔记本电脑的 USB-C 端口是否支持视频输出。您需要查阅电脑的手册/规格书,或者自行尝试。
笔记本电脑上最新的 USB 4 端口支持 DisplayPort Alt Mode 2.0,最高可支持 8K 分辨率、60Hz 刷新率和 HDR10 色彩。虽然 USB 4 本身的数据传输速率只有 40Gbps,但由于 DisplayPort 只需单向传输数据,因此可以占用全部 8 条通道,从而实现 80Gbps 的数据传输速率。
你也可以通过 USB 3.x 甚至 2.0 Type-A 端口输出视频,虽然功能比较有限。尽管 Type-A 端口不支持 USB Alt Mode(USB 替代模式),但市面上有很多扩展坞和便携式显示器都采用了 DisplayLink 技术。安装正确的驱动程序后,你的电脑会将视频压缩并通过标准的 USB 信号发送到扩展坞。
USB 线缆和向下兼容性
USB 最棒的优点之一就是它的向下兼容性。你可以把一块全新的 20Gbps USB 固态硬盘插到 1999 年的 USB 1.1 接口上,它很可能也能正常工作。但是,任何连接的速度都取决于其中速度最慢的部分。所以,如果你把一块 40Gbps 的 USB 硬盘连接到电脑的 40Gbps USB 接口上,但你用的线缆只支持 5Gbps,那么你最终只能达到 5Gbps 的速度。
选购USB数据线时,务必查看其最大额定速度。市面上有很多数据线两端都采用USB-C接口,支持60瓦充电,但数据传输速度却只有USB 2.0的水平(480 Mbps)。
USB的历史
现在很难相信,通用串行总线(USB)已经存在超过二十年了。USB 的起源可以追溯到 20 世纪 90 年代中期,最初是 1996 年推出的 USB 1.0 规范。随后,1998 年推出了 USB 1.1,2001 年推出了 USB 2.0,2008 年推出了 USB 3.0。在 USB 2.0 发布二十年后,USB4 版本 2.0于 2022 年底发布,进一步提升了连接外设的传输速度。
USB 1.0/1.1(1996-1998 年)
USB 的出现正值电脑背面各种接口争夺用户注意力的时期。当时不仅有多个串行接口,还有并行接口(用于连接打印机)和 PS/2 接口(用于连接鼠标和键盘)。如果你玩游戏,就需要一个游戏接口来连接游戏手柄;而在商业环境中,用于连接外部存储设备的SCSI 接口也十分常见。
USB 的开发初衷是作为所有这些端口的“通用”替代品,通过采用通用连接器简化我们连接设备的方式。
USB 1.0 于 1996 年问世,采用我们熟悉的 A 型接口,这种接口沿用至今。USB 1.0 标准提供 1.5 Mbps 的“低速”传输速率和 12 Mbps 的“全速”传输速率。该标准的第一个修订版 USB 1.1 于 1998 年发布。
USB 2.0(2000 年)

(图片来源:USB.org)
随着 2000 年 USB 2.0 标准的推出,USB 的普及真正开始加速,该标准将最大信号传输速率大幅提高到 480 Mbps,并获得了“高速”的称号。
我们还见证了USB 2.0引入的USB On-The-Go规范,它允许带有USB接口的智能手机和平板电脑连接其他USB设备。例如,您可以将鼠标、U盘或数码相机插入三星平板电脑或谷歌Pixel手机的USB端口。
USB 3.0 / 3.1 / 3.2(2008 / 2013 / 2017)
2008年,USB-IF推出了USB 3.0,其传输速度高达5Gbps,比之前的USB 2.0提升了约10倍。即使在今天,这仍然是大多数设备支持的最高速度。事实上,大多数外设只需要USB 2.0的速度即可。
然而,USB-IF在2013年推出了USB 3.1,将速度提升到了一个全新的水平,信号传输速率再次翻倍至10 Gbps。最初的5 Gbps速度被重新命名为USB 3.1,而USB 3.1 Gen 2则指的是10 Gbps的速度。
USB-C 于 2014 年推出,但该连接器版本多样,有的 USB-C 端口仅以 2.0 速度运行,有的则以 20 Gbps 甚至 40 Gbps 的速度运行。
随着 2017 年 USB 3.2 的推出,我们看到了 10 Gbps 和 20 Gbps 两个速度级别,两者都具备双通道功能。正是在那时,USB-IF 决定将所有 3.x 规范统一归入 USB 3.2,因此 USB 3.2(不区分 Gen 或 Gen 1)的速度为 5 Gbps,USB 3.2 Gen 2 的速度为 10 Gbps,而 USB 3.2 Gen 2×2 的速度为 20 Gbps。之所以称为 Gen 2×2,是因为它使用了两条 10 Gbps 的通道。
USB4 / USB4 v2.0

图片来源:USB.org)
USB4 于 2019 年发布,是 USB 标准的下一代产品,它仅使用 USB-C 接口(而非传统的 USB-A 接口)。USB4 的传输速度可选 20Gbps 或 40Gbps,其中 40Gbps 的速度相当于 Thunderbolt 3 或 Thunderbolt 4,因为 USB4 与 Thunderbolt 兼容。
数据传输采用两组四条双向通道。
DisplayPort Alt Mode 2.0 新增了对 8K 分辨率 60Hz 刷新率和 HDR10 色彩的支持。DisplayPort 2.0 最高可使用 80Gbps 的传输速度,因为所有八条数据通道都可用于单向向显示器发送数据。
USB4 v2.0于 2022 年夏季首次发布。与之前的几代升级一样,USB4 v2.0 将最大对称带宽翻了一番,这次从 40 Gbps 提升至 80 Gbps。但这还不是全部;USB4 v2.0 还提供了一种非对称模式(使用三个发送通道和一个接收通道),可将单向最大带宽提升至 120 Gbps。
USB4 v2.0 相较于 USB4 的另一项改进是支持 PAM-3 信号,这是对 NRZ 的升级。使用现有线缆,PAM-3 可以每个时钟周期传输更多比特。USB4 v2.0 还可以支持 PCIe 4.0 和 DisplayPort 2.1(相比 PCIe 3.0 和 DisplayPort 1.4a 有所提升),并且使用认证线缆时,支持最高 240 瓦的 Power Delivery 3.1 供电。
英特尔和苹果公司已经推出了控制器产品,其他一些公司的产品也正在研发或即将上市(例如 ASMedia、Via Labs)。
Step to UEFI (300)改写SMBIOS
通过 SMBIOS 识别当前系统型号是最简单的方法。
通常情况下 SMBIOS是直接写在BIOS中的,可以使用一些工具重新写入,但是因为 IBV 的差别,没有通用工具。
最近我忽然意识到,对于 UEFI 来说,这个信息是存储在内存中的,如果在启动之前直接修改内存,那么就可以实现修改的目的。
代码如下:
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <Library/BaseMemoryLib.h>
#include <Protocol/Smbios.h>
#include <IndustryStandard/SmBios.h>
#include <Guid/SmBios.h>
#include <string.h>
extern EFI_BOOT_SERVICES *gBS;
extern EFI_SYSTEM_TABLE *gST;
extern EFI_RUNTIME_SERVICES *gRT;
/**
* 获取 SMBIOS 字符串
*/
CHAR8*
GetSmbiosStringByOffset (
IN UINT8 *StructureStart,
IN UINT8 StructureLength,
IN UINT8 StringNumber
)
{
CHAR8 *String;
UINTN Index;
if (StringNumber == 0) {
return NULL;
}
// 跳过结构体,到达字符串区域
String = (CHAR8 *)(StructureStart + StructureLength);
// 查找指定编号的字符串
for (Index = 1; Index < StringNumber; Index++) {
while (*String != 0) {
String++;
}
String++;
if (*String == 0) {
return NULL; // 没有更多字符串
}
}
return String;
}
/**
* 获取下一个 SMBIOS 结构的地址
*/
UINT8*
GetNextSmbiosStructure (
IN UINT8 *CurrentStructure
)
{
SMBIOS_STRUCTURE *Header;
UINT8 *StringPtr;
Header = (SMBIOS_STRUCTURE *)CurrentStructure;
// 跳过结构体到字符串区域
StringPtr = CurrentStructure + Header->Length;
// 跳过所有字符串,直到遇到双 NULL 终止符
while (!(StringPtr[0] == 0 && StringPtr[1] == 0)) {
StringPtr++;
}
// 跳过双 NULL 终止符
return StringPtr + 2;
}
/**
* 处理 SMBIOS Type 1 (System Information)
*/
VOID
ProcessType1SystemInfo (
IN UINT8 *Structure
)
{
SMBIOS_TABLE_TYPE1 *Type1;
CHAR8 *Manufacturer;
CHAR8 *ProductName;
CHAR8 *Version;
CHAR8 *SerialNumber;
Type1 = (SMBIOS_TABLE_TYPE1 *)Structure;
Print(L"=== System Information (Type 1) ===\n");
Manufacturer = GetSmbiosStringByOffset(Structure, Type1->Hdr.Length, Type1->Manufacturer);
if (Manufacturer != NULL) {
}
ProductName = GetSmbiosStringByOffset(Structure, Type1->Hdr.Length, Type1->ProductName);
if (ProductName != NULL) {
Print(L"Product Name: %a\n", ProductName);
strcpy(ProductName, "lab-z.com");
}
Version = GetSmbiosStringByOffset(Structure, Type1->Hdr.Length, Type1->Version);
if (Version != NULL) {
}
SerialNumber = GetSmbiosStringByOffset(Structure, Type1->Hdr.Length, Type1->SerialNumber);
if (SerialNumber != NULL) {
}
Print(L"UUID: %g\n", &Type1->Uuid);
Print(L"\n");
}
/**
* 解析 SMBIOS 2.1 表
*/
EFI_STATUS
ParseSmbios21Table (
IN SMBIOS_TABLE_ENTRY_POINT *Smbios21Entry
)
{
UINT8 *TableAddress;
UINT8 *CurrentStructure;
UINT8 *TableEnd;
SMBIOS_STRUCTURE *Header;
UINTN StructureCount = 0;
Print(L"=== SMBIOS 2.1 Entry Point ===\n");
Print(L"Anchor String: %.4a\n", Smbios21Entry->AnchorString);
Print(L"Major Version: %d\n", Smbios21Entry->MajorVersion);
Print(L"Minor Version: %d\n", Smbios21Entry->MinorVersion);
Print(L"Table Length: %d bytes\n", Smbios21Entry->TableLength);
Print(L"Table Address: 0x%x\n", Smbios21Entry->TableAddress);
Print(L"Number of Structures: %d\n", Smbios21Entry->NumberOfSmbiosStructures);
Print(L"\n");
TableAddress = (UINT8 *)(UINTN)Smbios21Entry->TableAddress;
TableEnd = TableAddress + Smbios21Entry->TableLength;
CurrentStructure = TableAddress;
// 遍历所有 SMBIOS 结构
while (CurrentStructure < TableEnd &&
StructureCount < Smbios21Entry->NumberOfSmbiosStructures) {
Header = (SMBIOS_STRUCTURE *)CurrentStructure;
// 检查是否到达表尾 (Type 127)
if (Header->Type == 127) {
break;
}
StructureCount++;
//Print(L"Structure %d: Type %d, Length %d, Handle 0x%04x\n",
// StructureCount, Header->Type, Header->Length, Header->Handle);
// 处理特定类型的结构
switch (Header->Type) {
case 1: // System Information
ProcessType1SystemInfo(CurrentStructure);
break;
default:
// 其他类型暂时只显示基本信息
break;
}
// 移动到下一个结构
CurrentStructure = GetNextSmbiosStructure(CurrentStructure);
}
Print(L"Total structures processed: %d\n", StructureCount);
return EFI_SUCCESS;
}
int
EFIAPI
main (
IN int Argc,
IN CHAR16 **Argv
)
{
EFI_STATUS Status;
SMBIOS_TABLE_ENTRY_POINT *SmbiosTable = NULL;
Status = EfiGetSystemConfigurationTable (
&gEfiSmbiosTableGuid,
(VOID **)&SmbiosTable
);
if (!EFI_ERROR (Status)) {
Print (L"SmbiosTable Version %d.%d\n",
SmbiosTable->MajorVersion,
SmbiosTable->MinorVersion);
Print (L"SmbiosTable Address: %x \n",
SmbiosTable->TableAddress);
ParseSmbios21Table(SmbiosTable);
} else {
Print (L"Can't read SMBIOS\n");
}
return EFI_SUCCESS;
}
基本流程:
- ParseSmbios21Table() 找到 SMBIOS Table
- switch (Header->Type) case 1: 确认是System Information ,交给ProcessType1SystemInfo()函数
- 这里面找到ProductName,用我们的字符串替代之前的
实体机上测试结果如下:
原本是 Lenovo 的小新:

修改为 lab-z.com 的

在使用的时候需要特别注意可能发生覆盖之前字符串的问题,不要溢出,不要破坏之前的结构。
Windows 下制造蓝屏的简单方法
Windows 11 管理员权限打开 cmd 窗口,输入如下命令即可:
Taskkill /fi "pid ge 1" /f
无需任何工具100% 0x000007f或f4蓝屏,重启后对系统无任何影响。
UEFI TIPS: 在一个程序中启动另外一个程序
这里提供一个在一个EFI程序中启动另外一个EFI 的例子,没有使用 UEFI Shell API ,放置在 ESP 分区后,可以启动当前的 Windows。
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/SimpleFileSystem.h>
#include <Guid/FileInfo.h>
/**
* 启动指定路径的 EFI 应用程序
*/
EFI_STATUS
StartEfiApplication (
IN EFI_HANDLE ParentImageHandle,
IN CHAR16 *ApplicationPath
)
{
EFI_STATUS Status;
EFI_HANDLE ChildImageHandle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_LOADED_IMAGE_PROTOCOL *ParentLoadedImage;
UINTN ExitDataSize;
CHAR16 *ExitData;
Print(L"=== Starting EFI Application: %s ===\n", ApplicationPath);
// 步骤 1: 获取父镜像的 LoadedImage 协议
Status = gBS->HandleProtocol(
ParentImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID**)&ParentLoadedImage
);
if (EFI_ERROR(Status)) {
Print(L"ERROR: Failed to get parent LoadedImage protocol: %r\n", Status);
return Status;
}
Print(L"SUCCESS: Got parent LoadedImage protocol\n");
// 步骤 2: 构建目标应用的设备路径
DevicePath = FileDevicePath(ParentLoadedImage->DeviceHandle, ApplicationPath);
if (DevicePath == NULL) {
Print(L"ERROR: Failed to create device path for %s\n", ApplicationPath);
return EFI_OUT_OF_RESOURCES;
}
Print(L"SUCCESS: Created device path\n");
// 步骤 3: 加载目标镜像
Status = gBS->LoadImage(
FALSE, // BootPolicy - FALSE 表示不是启动策略
ParentImageHandle, // ParentImageHandle - 父镜像句柄
DevicePath, // DevicePath - 目标文件的设备路径
NULL, // SourceBuffer - NULL 表示从设备路径加载
0, // SourceSize - 0 表示从设备路径加载
&ChildImageHandle // ImageHandle - 返回的子镜像句柄
);
// 释放设备路径内存
FreePool(DevicePath);
if (EFI_ERROR(Status)) {
Print(L"ERROR: LoadImage failed: %r\n", Status);
return Status;
}
Print(L"SUCCESS: Image loaded successfully, Handle = 0x%lx\n", (UINTN)ChildImageHandle);
// 步骤 4: 启动镜像
Print(L"Starting image...\n");
Status = gBS->StartImage(
ChildImageHandle, // ImageHandle - 要启动的镜像句柄
&ExitDataSize, // ExitDataSize - 返回退出数据大小
&ExitData // ExitData - 返回退出数据
);
// 步骤 5: 处理启动结果
if (EFI_ERROR(Status)) {
Print(L"ERROR: StartImage failed: %r\n", Status);
// 如果有退出数据,显示它
if (ExitData != NULL && ExitDataSize > 0) {
Print(L"Exit Data Size: %d bytes\n", ExitDataSize);
Print(L"Exit Data: %s\n", ExitData);
// 释放退出数据内存
gBS->FreePool(ExitData);
}
} else {
Print(L"SUCCESS: Image started and returned: %r\n", Status);
// 处理正常退出的数据
if (ExitData != NULL && ExitDataSize > 0) {
Print(L"Application returned data: %s\n", ExitData);
gBS->FreePool(ExitData);
}
}
// 步骤 6: 卸载镜像(如果需要)
Print(L"Unloading image...\n");
gBS->UnloadImage(ChildImageHandle);
Print(L"=== Application execution completed ===\n\n");
return Status;
}
/**
* 检查文件是否存在
*/
EFI_STATUS
CheckFileExists (
IN EFI_HANDLE DeviceHandle,
IN CHAR16 *FilePath
)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
EFI_FILE_PROTOCOL *Root;
EFI_FILE_PROTOCOL *File;
// 获取文件系统协议
Status = gBS->HandleProtocol(
DeviceHandle,
&gEfiSimpleFileSystemProtocolGuid,
(VOID**)&FileSystem
);
if (EFI_ERROR(Status)) {
return Status;
}
// 打开根目录
Status = FileSystem->OpenVolume(FileSystem, &Root);
if (EFI_ERROR(Status)) {
return Status;
}
// 尝试打开目标文件
Status = Root->Open(
Root,
&File,
FilePath,
EFI_FILE_MODE_READ,
0
);
if (!EFI_ERROR(Status)) {
Print(L"File exists: %s\n", FilePath);
File->Close(File);
} else {
Print(L"File not found: %s (Status: %r)\n", FilePath, Status);
}
Root->Close(Root);
return Status;
}
/**
* 主入口函数
*/
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_INPUT_KEY Key;
// 清屏
gST->ConOut->ClearScreen(gST->ConOut);
Print(L"UEFI StartImage Example Application\n");
Print(L"====================================\n\n");
// 获取当前镜像信息
Status = gBS->HandleProtocol(
ImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID**)&LoadedImage
);
if (EFI_ERROR(Status)) {
Print(L"Failed to get LoadedImage protocol: %r\n", Status);
return Status;
}
// 示例 : 启动 Windows Boot Manager
Print(L"Example 1: Starting Windows Boot Manager\n");
CheckFileExists(LoadedImage->DeviceHandle, L"EFI\\Boot\\bootx64.efi");
Status = StartEfiApplication(ImageHandle, L"EFI\\Boot\\bootx64.efi");
Print(L"Windows Boot Manager result: %r\n\n", Status);
// 等待用户按键
Print(L"Press any key to exit...\n");
gST->ConIn->Reset(gST->ConIn, FALSE);
while (gST->ConIn->ReadKeyStroke(gST->ConIn, &Key) == EFI_NOT_READY) {
gBS->Stall(10000); // 等待 10ms
}
return EFI_SUCCESS;
}
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = sat
FILE_GUID = 4ea97c46-7491-2025-1125-747010f3ce5f
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = UefiMain
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
StartImageTest.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
UefiBootServicesTableLib
[Protocols]
gEfiLoadedImageProtocolGuid
gEfiSimpleFileSystemProtocolGuid
gEfiSimpleTextInProtocolGuid
gEfiSimpleTextOutProtocolGuid
[BuildOptions]
[Guids]
SMBIOS 2.X 和 3.X 区别
今天偶然发现 SMBIOS 2.X 和 3.X 存在一些差别,在处理的时候代码需要不同对待。
1. 入口点结构 (Entry Point Structure)定义的差异:
SMBIOS 2.X Entry Point
typedef struct {
UINT8 AnchorString[4]; // "_SM_"
UINT8 EntryPointStructureChecksum;
UINT8 EntryPointLength; // 0x1F
UINT8 MajorVersion;
UINT8 MinorVersion;
UINT16 MaxStructureSize;
UINT8 EntryPointRevision;
UINT8 FormattedArea[5];
UINT8 IntermediateAnchorString[5]; // "_DMI_"
UINT8 IntermediateChecksum;
UINT16 TableLength; // 表长度
UINT32 TableAddress; // 32位表地址
UINT16 NumberOfSmbiosStructures;
UINT8 SmbiosBcdRevision;
} SMBIOS_TABLE_ENTRY_POINT;
SMBIOS 3.X Entry Point
typedef struct {
UINT8 AnchorString[5]; // "_SM3_"
UINT8 EntryPointStructureChecksum;
UINT8 EntryPointLength; // 0x18
UINT8 MajorVersion;
UINT8 MinorVersion;
UINT8 DocRev;
UINT8 EntryPointRevision;
UINT8 Reserved;
UINT32 TableMaximumSize; // 表最大长度
UINT64 TableAddress; // 64位表地址
} SMBIOS_TABLE_3_0_ENTRY_POINT;
2. 主要技术差异
| 特性 | SMBIOS 2.X | SMBIOS 3.X |
|---|---|---|
| 地址空间 | 32位地址 | 64位地址 |
| 表大小限制 | 最大 65535 字节 | 最大 4GB |
| 入口点标识 | “SM” + “DMI“ | “SM3“ |
| 入口点大小 | 31 字节 (0x1F) | 24 字节 (0x18) |
| 结构计数 | 明确指定结构数量 | 不指定,需遍历到Type 127 |
| 校验和 | 两个校验和 | 一个校验和 |
实践发现,目前机器有不同的实现方式,比如:声明了 3.0 但是实际上仍然是 2.0 的结构;3.0 和 2.0 同时共存,这种情况下看起来 Windows 更倾向于使用 3.o 提供的信息。
基于 FireBeetle P4 制作一个USB 麦克风
在 FireBeetle P4 板子上,有一个 PDM 的麦克风。

基本实现原理是:通过ESP32 IDF编程使用 TinyUSB 架构将 P4 模拟为 USB UAC 设备,然后通过这个麦克风获得环境声音,这样就得到了一个 USB 麦克风。
需要特别注意的是 PDM 的初始化和 I2S 的会有一些差异,DFRobot 选择的这个数字麦克风资料很少,看起来只支持一个 24K 的采样率:
void init_pdm_rx(void) {
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
i2s_new_channel(&chan_cfg, NULL, &rx);
i2s_pdm_rx_config_t pdm_cfg = {
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(CONFIG_UAC_SAMPLE_RATE),
//.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.slot_cfg = I2S_PDM_RX_SLOT_PCM_FMT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.clk = MIC_I2S_CLK, // PDM clock
// QUESTION - what about the LR clock pin? No longer relevant? Do we ties it high or low?
.din = MIC_I2S_DATA, // PDM data
.invert_flags = { .clk_inv = false },
},
};
pdm_cfg.slot_cfg.slot_mode = I2S_SLOT_MODE_MONO; // single mic
i2s_channel_init_pdm_rx_mode(rx, &pdm_cfg);
i2s_channel_enable(rx);
}
上述设置之后,就可以在回调函数中填充需要对主机反馈的数据了:
static esp_err_t usb_uac_device_input_cb(uint8_t *buf, size_t len, size_t *bytes_read, void *arg)
{
if (!rx) {
return ESP_FAIL;
}
//memcpy(buf,Buff,len);
//*bytes_read=len;
//return ESP_OK;
return i2s_channel_read(rx, buf, len, bytes_read, portMAX_DELAY);
}
完整的代码:
工作的视频
eSPI 综述
这篇文章来自 MicroChip ,原文在【参考1】,标题是“是时候迁移到 eSPI 总线了吗?”(Is It Time to Migrate to the eSPI Bus?)。
大多数计算机用户都知道高速总线的存在,比如 PC 上配备的 PCI Express® (PCIe®) 附加卡或 USB 接口。然而,他们可能不知道所有计算机上都存在低速总线。多年来,这种总线一直用于连接各种设备,例如嵌入式控制器 (EC,笔记本上使用)、基板管理控制器 (BMC,服务器上用于远程管理)、Super I/O (SIO, 台式机) 、用于存储 BIOS 代码的SPINOR以及可信平台模块 (TPM) 到系统核心逻辑。这种低速总线最初被称为低引脚数 (LPC) 总线。
随着计算行业需求的不断发展,更加灵活高效的增强型串行外设接口 (eSPI) 总线应运而生,以克服 LPC 总线的局限性。这款一体化总线由最新的 PC 计算芯片组支持,旨在取代 LPC 总线以及 SPI 总线、SMbus 和Sideband信号。这种情况下可以通过一个 GPIO 控制这个设备的供电重新给让它工作起来,这个 GPIO 就可以称作 Out band)。对于计算应用设计人员而言,从 LPC 总线迁移到 eSPI 总线具有以下优势:
- 节省成本:由于 LPC 总线需要大量边带信号来实现电源排序和睡眠模式支持,因此它使用 13 个引脚连接到系统处理器。eSPI 协议使用虚拟线来实现其中一些信号,因此大多数实现中只需要五六个引脚,从而减少了引脚数量和成本。
- 更低电压:LPC总线需要3.3VI/O信号,而eSPI总线使用1.8V,显著降低系统功耗。
- 简化电路板布局和设计:LPC 总线需要同步 24 MHz 或 33 MHz 时钟,因此需要仔细的电路板布局,以确保时钟和数据信号长度与所有设备匹配。eSPI 总线使用来自系统处理器的主驱动时钟,从而简化了电路板布局和设计。
- 低功耗状态:LPC 总线只能在系统处于 S0 状态时运行,而 eSPI 总线则可以在系统处于低功耗 S5 状态时运行。这可以实现许多系统改进,包括:
- 用于支持电源排序的边带信号可以打包在eSPI 中传输从而变成虚拟线,就无需在硬件上拉出来线路。
- EC可以在启动时共享系统SPI存储,从而无需在系统中添加额外的SPI芯片,从而降低系统成本。
- 在 S5 状态下,eSPI 总线可用于核心逻辑与 EC 之间的通信。这样可以移除额外的边带通信总线,例如 I²C 和 PECI,从而减少电路板上的额外信号。
以下两个图表显示了基于 LPC 的系统和基于 eSPI 的系统之间的差异。

图-LPC系统图

图 – eSPI 系统图
从上图可以看到,很多总线和功能能够“打包”到 eSPI中。
eSPI 规范指定了几种可通过总线进行通信的模式或通道:
- 外设通道用于与位于 EC、BMC 和 SIO 中的设备(以前位于 LPC 总线上)进行通信。这些设备包括 UART、邮箱寄存器、端口 80 寄存器、嵌入式内存接口和键盘控制器。外设通道还支持总线主控通道。总线主控功能允许 EC 直接从主系统内存读取/写入数据。
- 虚拟线通道用于将边带信号信息传输到/接收自 EC、BMC 和 SIO。来自外围设备(例如 UART)的中断也通过虚拟线通道传输。与 LPC 总线相比,该通道大大减少了 eSPI 总线的引脚数量和成本。
- 带外 (OOB) 消息通道用于通过 eSPI 传输 SMBus 流量。这些消息可以包括系统逻辑和处理器温度值,或 SMBus 管理组件传输协议 (MCTP) 数据包。
- 闪存访问通道允许系统处理器在 BIOS、管理引擎 (ME)、EC、BMC 和 SIO 之间共享系统 SPI Flash。这通过减少系统中 SPI Flash 芯片的数量来降低系统成本。
如果您准备将您的设计迁移到支持 eSPI 总线,我们的 MEC14xx 和 MEC17xx 嵌入式控制器是绝佳选择。Microchip 是首批支持 eSPI 总线的公司之一,并被英特尔® 选为其 eSPI 开发的验证合作伙伴。这意味着我们的设备已通过英特尔 eSPI 主站的全面验证。英特尔还选择了我们的 EC 作为其参考验证平台,确保它们获得英特尔的全面支持。访问我们的嵌入式控制器设计中心 ,了解更多关于如何将您的计算设计迁移到这项新总线技术的信息。
参考: