当前位置:网站首页 > R语言数据分析 > 正文

ldrsb指令(ldrh指令)



来,我们直接切入正题,何谓USB数据传输?

其实,USB数据传输分别要经过三个阶段:

        

这个状态通常由查看USB硬件的相关寄存器来实现

以沁恒微(一家非常牛逼的usb接口芯片公司)CH554为例:

对于软件来说,首先是进行usb初始化,主要是InitUSB_Host(),DisableRootHubPort() 这两个函数,代码如下:

 
  

InitUSB_Host()实际是对USB主机进行初始化,包括设置usb控制寄存器模式,设备usb设备地址(为枚举阶段准备),启用usb的主机传输和接受端点,设置DMA缓冲区,清空根HUB端口的状态等。

注意这两行代码

USB_CTRL = bUC_HOST_MODE;  // 设置USB控制寄存器为主机模式

USB_DEV_AD = 0x00; // USB主机控制器的设备地址寄存器,设置当前通信的从设备地址。

tips:为什么首先要将USB设置为主机模式?为什么初始化要设置usb设备地址为0x00?下面介绍原理的时候会说到

DisableRootHubPort() 是关闭HUB端口, 代码详解:

#ifdef FOR_ROOT_UDISK_ONLY

    // 如果仅支持根USB设备(例如U盘),则设置根设备状态为断开连接

    CH554DiskStatus = DISK_DISCONNECT;

#endif

#ifndef DISK_BASE_BUF_LEN

    // 如果没有定义DISK_BASE_BUF_LEN(磁盘缓冲区长度),则

    // 设置当前USB设备的状态为ROOT_DEV_DISCONNECT=0表示没有连接任何设备

    // 并将设备地址设置为0x00,表示设备未连接

    ThisUsbDev.DeviceStatus  = ROOT_DEV_DISCONNECT;

    ThisUsbDev.DeviceAddress = 0x00;

#endif

可以看到,这个函数作用是初始化设备状态:无设备;初始化设备被分配的USB地址,在枚举阶段中,地址必须为0x00(后面会讲到为什么是0x00)。

ThisUsbDev.DeviceAddress的作用为在主机模式下,DeviceAddress存储的是与当前主机连接的从设备的地址。主机通过枚举过程分配地址给每个连接的设备。假设主机分配了地址0x01给某个从设备,主机会将 DeviceAddress设置为0x01,并与该设备进行数据交换。

初始化后,开始对设备进行连接与检测。

说到设备,USB又分为低速,全速和高速设备,因此在连接与检测阶段主要判断是哪种设备类型

低速设备:传输速率最多 1.5 Mbps,适用于对带宽要求较低的设备(如鼠标、键盘等)

全速设备:传输速率最多 12 Mbps,适用于一般数据传输需求的设备(如打印机、扫描仪)。

高速设备:传输速率最多 480 Mbps,适用于需要高速数据传输的设备(音频设备、摄像头)。

以四针USB通讯接口为例:

 

低速设备:

特征:

1.低速USB从设备在 D-上连有1.5kΩ的电阻到 3.0V-3.6V电压

全速设备:

特征:

1.全速USB从设备在 D+上连有1.5kΩ的电阻到 3.0V-3.6V电压

高速设备:

高速设备就比较复杂了

高速设备检测连接方式主要通过 D+D- 信号线路上的电平变化,以及通过与主机的握手过程来确定连接模式。以下是高速设备在连接时如何检测连接方式的过程:

1.初始连接(全速模式)
  • 当高速设备最初连接到主机时,设备会默认工作在全速模式下(12 Mbps)。在此时,设备端的 D+ 信号线会通过一个上拉电阻(通常为 1.5kΩ)拉高到 3.3V,而 D- 线会处于低电平(0V)。
  • 这是全速设备和主机之间最初的通信模式。
2.主机检测设备并发送复位信号
  • 主机会检测到设备连接,并发送一个复位信号到设备。复位信号会使设备重新初始化并准备进入其实际工作模式。(什么是复位信号后面会说)
3. 设备通过 ChipK 信号表明其身份
  • 在复位期间,设备会通过是否能生成 ChipK 信号 来表明自己是否是一个支持高速模式的设备。如果设备是 高速设备,它会发出 ChipK 信号来通知主机它可以进入高速模式。如果设备不支持高速模式,它将保持在全速模式。
  • ChipK 信号:这是 USB 高速设备用于指示自己支持高速模式的信号。如果设备支持高速模式,它会在复位后通过电平变化将该信号反馈给主机。(什么是 ChipK 信号后面会说)
4. 主机的 KJ 序列响应
  • 之后,主机会检测设备的 ChipK 信号,主机是否发生KJ序列来表明高速主机身份或者是全速主机身份:
    • 如果主机支持 高速模式,主机会发送一个 KJ 序列(由 K 状态和 J 状态构成的信号序列)。这个信号表示主机在高速模式下的身份。
    • 如果主机不支持高速模式,主机会响应设备并继续保持在 全速模式
5. 切换到高速模式
  • 一旦主机和设备完成 KJ 序列 握手并确认可以工作在高速模式下,设备将执行以下操作
    • 设备断开 D+ 线上的 1.5kΩ 上拉电阻,这是为了停止设备以全速模式的身份工作。
    • 设备在 D+ 和 D- 线路上连接 高速终端电阻(45Ω),这表明设备已经切换到 高速模式(480 Mbps)。
  • 设备和主机此时都进入 默认的高速状态,并开始以高速模式进行数据传输。
6. 如果未能进入高速模式,则继续全速模式
  • 如果 ChipK 信号 未成功被设备发送(例如,设备不支持高速模式),或者主机未能正确响应 KJ 序列(例如主机不支持高速模式),则设备和主机都会继续以 全速模式(12 Mbps)进行通信。

关于复位信号,ChipK 信号,K状态,J状态:

复位信号:总线维持SE0状态>10ms

K状态:对于要进行高速模式和全速模式的设备来说,D+为低电平0V,D-为高电平3V(也说3.6V)

J状态:对于要进行高速模式和全速模式的设备来说,D+为高电平3V(3.6V),D-为低电平0V

ChipK 信号:ChirpK 信号 是在高速 USB 设备接收到总线复位信号后,通过向 D- 线 提供电流生成的电压信号,通常为 800mV。该信号的持续时间为 1ms 至 7ms,用于告知主机设备是否支持 高速模式(480 Mbps)

介绍完理论,下面让我们看看软件是怎么实现的。

以USB键盘为例,只需判断低速和全速设备,代码如下:

 
  

sfr USB_MIS_ST = 0xDA; // ReadOnly: USB miscellaneous status。可以看到USB_MIS_ST 为USB 相关的只读杂项状态寄存器,

#define bUMS_DEV_ATTACH  0x01 // ReadOnly: indicate device attached status on USB host。这个宏定义一个常量 bUMS_DEV_ATTACH ,其值为 0x01 ,表示设备连接状态的指示位。

如果设备已连接,USB_MIS_ST &bUMS_DEV_ATTACH 的结果为非零值

if ((UHOST_CTRL & bUH_PORT_EN) == 0x00)//保证在端口为启用的情况下,对速度进行设置。

#define bUMS_DM_LEVEL  0x02  // ReadOnly: indicate UDM level saved at device attached to USB host。bUMS_DM_LEVEL  是与 USB_MIS_ST 寄存器相关的一个标志位,它用于指示设备的连接速度(低速或全速)。具体来说为获取USB设备的信号线(Data+)电平,用于指示设备的连接速度。

USB_MIS_ST bUMS_DM_LEVEL  ?  0:1;这是一个条件表达式。若 bUMS_DM_LEVEL  为 1,说明设备为全速;若为 0,说明设备为低速。因此:

  • 表示设备为低速。
  • 表示设备为全速。

if (ThisUsbDev.DeviceSpeed == 0)
    UHOST_CTRL |= bUH_LOW_SPEED; 

若设备为低速(DeviceSpeed == 0),将 UHOST_CTRL 寄存器中的 bUH_LOW_SPEED位置 1,使主机端口支持低速通信。

通过查看USB硬件相关寄存器来判断低速还是全速设备。

以上为检测连接从设备的过程,当然,连接阶段也主要通过USB硬件的相关寄存器来实现,这里就不列举代码了。

在连接检测阶段,涉入USB还浅,见USB通信协议如井底之蛙抬头见月;倘若到了第二阶段枚举阶段,初步涉及到数据传输,就会见USB通信协议如一粒蜉蝣见青天。USB通信是一个比较复杂的通信协议,我们所做的一直都是站在巨人的肩膀上,去不断学习,深入。

枚举:主机向从设备获取各种描述符,了解设备属性的过程。

那么主机是怎么从从设备获取描述符的呢?这里就涉及到USB传输的一个重要概念:控制传输!

USB数据传输分别有四种传输方式,分别是:

控制传输:用于配置设备,获取设备信息。

中断传输:数据量较小,低延迟的传输,如键盘、鼠标。

批量传输:大数据量的非实时传输,如U盘。

等时传输:实时数据传输,如USB摄像头。

说到控制传输,我们先要理解USB传输结构的基本构成

在USB传输中,是数据包的基本组成单元,每个域(如同步域、地址域等)承担特定的功能,确保数据的准确识别与传递。多个域组合成,不同类型的包(如令牌包、数据包、握手包)携带控制信息、数据内容和确认状态。包之间的序列构成一个事务,事务是一次完整的数据传递动作,通常包含请求和响应。多个事务组成传输,传输是实现设备间数据交换的完整过程。这种层级关系确保了USB协议的高效和稳定,使得数据在主机和设备之间得以可靠传输。

以控制传输为例,控制传输由三个事务构成,他们分别是SETUP事务,IN事务和OUT事务。

控制传输可以分为三种结构,分别是控制写,控制读和无数据控制。每种结构由多种事务构成。

控制写由建立阶段(SETUP事务),数据阶段(OUT事务)和状态阶段(IN事务)构成

控制读由建立阶段(SETUP事务),数据阶段(IN事务)和状态阶段(OUT事务)构成

无数据控制由建立阶段(SETUP事务)和状态阶段(IN事务)构成

需要注意的是,在SETUP事务中,数据包固定为8字节数据结构。

现在看可能有点抽象,就拿控制写来说,抓包数据为:

建立阶段:SETUP事务,其中SETUP 事务由SETUP令牌包,DATA0数据包和ACK握手包构成。

数据阶段:OUT事务(主机发送),其中OUT事务由OUT令牌包,DATA1数据包和ACK握手包构成。

状态阶段:IN事务(从机上传),其中IN事务由IN令牌包,DATA1数据包和ACK握手包构成。

tips1.数据包包含DATA0包和DATA1包

        2.SETUP事务中数据包一定是DATA0包

        3.在数据阶段,一定是DATA1和DATA0,0和1之间交替翻转(懂我意思吧),目的是为了检查传输过程中是否出错,比如连续收到了两个DATA0包,或者是DATA1包,就表面传输过程中出错

        4.在状态阶段,数据包一定是DATA1

        5.控制写为主机发送请求,控制读为从机上传数据内容

下面再列举一个控制读捕获的数据包:

可以看到控制读结构的数据阶段由一系列的IN事务组成,其中DATA1和DATA0之间交替翻转。

下面是一个无数据的控制传输:

这是一个设置地址的控制传输,只由建立阶段和状态阶段构成,至于建立阶段8字节分别代表什么含义,我们下面会说到。

控制传输中建立阶段,SETUP事务主机发出8字节 命令请求,格式如下:

第一个字段bRequestType请求特性字段,占1字节。第7位表示传输方向,第5~6位表示请求类型(标准请求,类请求等),第0~4位表示传输对象(针对USB设备,特定的接口,端点等)

第二个字段bRequest请求码字段,占1字节。请求码与请求特性中定义的请求类型相适配。

所以对于控制写的SETUP数据包21 09 00 02 00 00 01 00 来说:

第一字段0x21二进制为0010 0001,因此第7位(方向):表示主机向设备(Host to Device)第6-5位(类型):表示类请求(Class request)第4-0位(接收者):00001表示接口(Interface)

因此,bRequestType值 0x21表示主机向设备发送一个类请求,目标是接口

第二字段0x09表示请求码SET_Report,这是HID类请求,通常用于向设备发送报告(Report)。

第三字段00 02表示Report类型和Report ID

第四字段 00 00 表示接口0。

第五字段 01 00表示接下来的数据阶段需要传输的字节数(长度为1字节)。

  表示主机向接口0发送一个HID类请求(SET_REPORT),要求设置一个Output Report(ID为0),并在数据阶段发送1字节的数据。

 对于控制读数据包SETUP数据包80 06 00 01 00 00 12 00:

第一字段0x80,二进制为1000 0000,第7位(方向):1表示设备向主机(Device to Host),第6-5位(类型):表示标准请求(Standard request),第4-0位(接收者):表示设(Device) bRequestType值 表示设备向主机发送一个标准请求,目标是设备。

第二字段 表示请求码 ,这是USB标准请求,表示获取设备描述符(Device Descriptor)。

第三字段 00 01:0x0100,高字节 表示获取设备描述符(Device Descriptor),低字节 表示请求的是设备描述符。

第四字段 00 00 表示端点0.

第五字段 12 00: 0x0012 表示主机期望接收的数据长度为 字节,即18字节。设备描述符通常是18字节长。

表示主机向设备发送一个标准请求 ,请求获取设备描述符(Device Descriptor),设备将返回18字节的数据。

对于设置地址的无数据控制传输00 05 03 00 00 00 00 00:

第一字段 表示这是一个主机向设备发送的标准请求,目标是设备

第二字段 表示请求码 ,这是USB标准请求,用于设置设备地址。

第三字段03 00: 表示要设置的设备地址值为 。这意味着主机要求设备将其地址设置为 。

第四字段 00 00: 对于 请求来说没有意义,通常保留为 。

第五字段 00 00: 表示没有数据阶段,因为 请求只需发送SETUP包,无需数据传输

  表示主机发送一个标准请求 ,要求设备将其地址设置为 。

弄清楚USB传输的结构,组成后,在通晓了数据传输的基础上,我们来看看USB的枚举过程。

枚举过程分为六个阶段:

缺省地址:

指向USB从机设备的最初地址,通常为0。这也是为什么,在上面的小tips里提到初始化要设置usb设备地址为0x00。每个USB设备在连接到主机时,最初会被分配一个缺省地址。

用于:1.主机使用缺省地址与设备进行初始通信,以识别和配置设备。

        2.设备枚举:当设备连接时,主机会通过缺省地址发送请求,获取设备描述符。

        3.地址分配:在设备成功枚举后,主机会为其分配一个唯一的地址,供后续通信使用。

可以看到,枚举阶段都跟各种描述符有关,以HID设备为例

HID设备类描述符结构:

设备描述符:固定18字节。包含设备类型、支持的 USB 版本、设备类别、厂商和产品 ID、最大数据包大小等关键字段。主机通过读取设备描述符来识别和配置设备,确保设备能够与主机正确通信。用于设备初始化阶段

 
  

设备描述符举例:

 
  

配置描述符:配置描述符:描述了设备特定的配置,提供了当前配置下设备的功能接口,供电方式,耗电等信息。是一个配置的集合,集合长度不固定,包含了配置描述符、接口描述符、类定义描述符、端点描述。

若有多个接口,继续添加 接口+类+端点 描述符

接口:表明设备具体功能(接口描述符)。

端点:提供物理传输的数据通道(端点描述符)。

配置描述符举例:

 
  

可以看到,若有多个接口,继续添加 接口+类+端点  描述符。这里为 键盘接口,HID类,键盘端点 + 鼠标接口,HID类,鼠标端点。 

报表描述符:描述HID设备的数据格式,确保主机能够正确处理和解析设备发送的数据。

 
  

介绍完USB描述符后,我们来看看枚举阶段到底是怎么实现的。

枚举阶段涉及到一个重要的通信步骤,那就是控制传输:

控制传输代码:
 
  

需要注意的是:

r = USB_INT_ST & MASK_UIS_H_RES;这行代码的作用是从 USB 中断状态寄存器 USB_INT_ST 中提取出高位的 USB 主机状态,包含 USB 传输应答状态的信息,比如STALL,ACK,NAK等。可以看到,底层主要是通过查看USB相关硬件寄存器来实现

HostCtrlTransfer函数用于执行 USB 主机的控制传输,包括 SETUP、DATA(IN 或 OUT)以及 STATUS 三个阶段。

 
  

以USB键盘为例,在数据传输过程中,主要涉及中断传输,

中断传输:

 中断传输流程:

主机发出请求(Token Packet):

1.主机会发出一个 IN 令牌或 OUT 令牌。
IN 令牌表示主机请求设备发送数据。
OUT 令牌表示主机将数据发送给设备。
2.设备响应请求(Data Packet 或握手包):







对于 IN 令牌:

一次传输完成后,主机和设备会进入空闲状态,等待下一次传输请求。

 代码:

 
  
控制传输:

控制传输在枚举阶段已经介绍,这里就不再赘述,简单的说明控制传输的逻辑

1.令牌阶段(Setup Stage)
控制传输以一个 SETUP 包开始,这是一个 8 字节的固定长度数据包,包含了请求类型、请求编号、数据长度等信息。
主机会发送 SETUP 包到设备,表明即将进行一个控制传输。
该阶段不区分数据传输方向,始终由主机发送 SETUP 包,设备进行响应。
2. 数据阶段(Data Stage,非必须)
如果控制请求包含数据传输(即 wLength 字段不为 0),则会进入数据阶段。否则跳过此阶段,直接进入状态阶段。
数据阶段的传输方向由 SETUP 包中的 bmRequestType 字段决定:
IN 数据传输:设备向主机发送数据,主机发送 IN 令牌,设备发送 DATA0 或 DATA1 数据包。
OUT 数据传输:主机向设备发送数据,主机发送 OUT 令牌,设备接收 DATA0 或 DATA1 数据包。
数据包交替使用 DATA0 和 DATA1,以确保数据包的正确性和同步性。
如果需要多次传输数据,数据阶段可以包含多个数据包,直到传输完所需的数据量。
3. 状态阶段(Status Stage)
状态阶段用于确认控制传输是否成功完成。
如果是 IN 数据传输,状态阶段的方向为 OUT,主机发送 OUT 包并接收设备的 ACK。
如果是 OUT 数据传输,状态阶段的方向为 IN,主机发送 IN 包并接收设备的 ACK。
状态阶段没有数据,只有 ACK 包来确认传输的成功。
状态阶段结束后,控制传输完成,设备和主机恢复到空闲状态。














































批量传输:

批量传输流程:

1. 令牌阶段
主机发送 IN 或 OUT 令牌。
IN 令牌:主机请求从设备读取数据。
OUT 令牌:主机向设备发送数据。
2. 数据阶段
主机或设备根据令牌类型发送 DATA 数据包。













如果设备出现错误,设备可以返回 STALL 包,表示传输遇到不可恢复的错误。

3. 握手阶段
设备收到 DATA 包后会回复握手包,主要有三种类型:
ACK:表示数据接收成功。
NAK:表示暂时无法接收数据,主机可以稍后再试。
STALL:表示发生了不可恢复的错误。










等时传输:

1.空闲(Idle)状态:

4无握手阶段:

数据阶段结束后,USB 总线恢复到空闲状态,准备下一次传输。

到此这篇ldrsb指令(ldrh指令)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • c++ ifstream头文件(c语言fstream头文件的作用)2026-05-23 20:36:07
  • aurocean怎么读(aurora怎么读)2026-05-23 20:36:07
  • spring入门视频(spring入门教程)2026-05-23 20:36:07
  • top18女rapper歌词(rapper 女)2026-05-23 20:36:07
  • 双系统卸载后开机grub(双系统删除后出现grub)2026-05-23 20:36:07
  • 文件比较工具 beyond compare使用(beyond compare比较文件夹内容)2026-05-23 20:36:07
  • rediscli连接集群(redis cli连接集群)2026-05-23 20:36:07
  • rbac权限模型表设计(acl权限模型)2026-05-23 20:36:07
  • none是什么意思?(fear none是什么意思)2026-05-23 20:36:07
  • swagger-ui访问不到(swagger不能访问)2026-05-23 20:36:07
  • 全屏图片