当前位置: 首页 > ai >正文

第二十二章 USB 全速设备接口(USB)

第二十二章 USB 全速设备接口(USB)

目录

第二十二章 USB 全速设备接口(USB)

1 USB 简介

2 USB 主要特征

3 USB 功能描述

3.1 USB 功能模块描述

4 编程中需要考虑的问题

4.1 系统复位和上电复位

4.2 双缓冲端点

4.3 同步传输

4.4 挂起/恢复事件

5 例程设计

5.1 CompositeEquipmentHID&VCP

6 下载验证

6.1 CompositeEquipmentHID&VCP


1 USB 简介

USB 外设实现了 USB2.0 全速总线和 APB1 总线间的接口。

USB 外设支持 USB 挂起/恢复操作,可以停止设备时钟实现低功耗。

2 USB 主要特征

W55MH32的USB接口的主要特征如下:

  • 符合 USB2.0 全速设备的技术规范
  • 可配置 1 到 8 个 USB 端点
  • CRC(循环冗余校验)生成/校验,反向不归零(NRZI)编码/解码和位填充
  • 支持同步传输
  • 支持批量/同步端点的双缓冲区机制
  • 支持 USB 挂起/恢复操作
  • 帧锁定时钟脉冲生成

        注: USB 和 CAN 共用一个专用的 512 字节的 SRAM 存储器用于数据的发送和接收,因此不能同时使用USB 和 CAN(共享的 SRAM 被 USB 和 CAN 模块互斥地访问) 。USB 和 CAN 可以同时用于一个应用中但不能在同一个时间使用。下图是 USB 外设的方框图:

USB 设备框图

3 USB 功能描述

        USB 模块为 PC 主机和微控制器所实现的功能之间提供了符合 USB 规范的通信连接。PC 主机和微控制器之间的数据传输是通过共享一专用的数据缓冲区来完成的,该数据缓冲区能被 USB 外设直接访问。这块专用数据缓冲区的大小由所使用的端点数目和每个端点最大的数据分组大小所决定,每个端点最大可使用 512 字节缓冲区,

        最多可用于 16 个单向或 8 个双向端点。USB 模块同 PC 主机通信,根据 USB规范实现令牌分组的检测,数据发送/接收的处理,和握手分组的处理。整个传输的格式由硬件完成,其中包括 CRC 的生成和校验。每个端点都有一个缓冲区描述块,描述该端点使用的缓冲区地址、大小和需要传输的字节数。当 USB 模块识别出一个有效的功能/端点的令牌分组时,(如果需要传输数据并且端点已配置)随之发生相关的数据传输。

        USB 模块通过一个内部的 16 位寄存器实现端口与专用缓冲区的数据交换。在所有的数据传输完成后,如果需要,则根据传输的方向,发送或接收适当的握手分组。在数据传输结束时,USB 模块将触发与端点相关的中断,通过读状态寄存器和/或者利用不同的中断处理程序,微控制器可以确定:

  • 哪个端点需要得到服务。
  • 产生如位填充、格式、CRC、协议、缺失 ACK、缓冲区溢出/缓冲区未满等错误时,正在进行的是哪种类型的传输。USB 模块对同步传输和高吞吐量的批量传输提供了特殊的双缓冲区机制,在微控制器使用一个缓冲区的时候,该机制保证了 USB 外设总是可以使用另一个缓冲区。

        在任何不需要使用 USB 模块的时候,通过写控制寄存器总可以使 USB 模块置于低功耗模式(SUSPEND 模式)。在这种模式下,不产生任何静态电流消耗,同时 USB 时钟也会减慢或停止。通过对 USB 线上数据传输的检测,可以在低功耗模式下唤醒 USB 模块。也可以将一特定的中断输入源直接连接到唤醒引脚上,以使系统能立即恢复正常的时钟系统,并支持直接启动或停止时钟系统。

3.1 USB 功能模块描述

USB 模块实现了标准 USB 接口的所有特性,它由以下部分组成:

  • 串行接口控制器(SIE):该模块包括的功能有:帧头同步域的识别,位填充,CRC 的产生和校验,PID 的验证/产生,和握手分组处理等。它与 USB 收发器交互,利用分组缓冲接口提供的虚拟缓冲区存储局部数据。它也根据 USB 事件,和类似于传输结束或一个包正确接收等与端点相关事件生成信号,例如帧首(Start of Frame),USB 复位,数据错误等等,这些信号用来产生中断。
  • 定时器:本模块的功能是产生一个与帧开始报文同步的时钟脉冲,并在 3ms 内没有数据传输的状态,检测出(主机的)全局挂起条件。
  • 分组缓冲器接口:此模块管理那些用于发送和接收的临时本地内存单元。它根据 SIE 的要求分配合适的缓冲区,并定位到端点寄存器所指向的存储区地址。它在每个字节传输后,自动递增地址,直到数据分组传输结束。它记录传输的字节数并防止缓冲区溢出。
  • 端点相关寄存器:每个端点都有一个与之相关的寄存器,用于描述端点类型和当前状态。对于单向和单缓冲器端点,一个寄存器就可以用于实现两个不同的端点。一共 8 个寄存器,可以用于实现最多 16 个单向/单缓冲的端点或者 7 个双缓冲的端点或者这些端点的组合。例如,可以同时实现 4 个双缓冲端点和 8 个单缓冲/单向端点。
  • 控制寄存器:这些寄存器包含整个 USB 模块的状态信息,用来触发诸如恢复,低功耗等 USB事件。
  • 中断寄存器:这些寄存器包含中断屏蔽信息和中断事件的记录信息。配置和访问这些寄存器可以获取中断源,中断状态等信息,并能清除待处理中断的状态标志。

注意: 端点 0 总是作为单缓冲模式下的控制端点。

USB 模块通过 APB1 接口部件与 APB1 总线相连,APB1 接口部件包括以下部分:

  • 分组缓冲区:数据分组缓存在分组缓冲区中,它由分组缓冲接口控制并创建数据结构。应用软件可以直接访问该缓冲区。它的大小为 512 字节,由 256 个 16 位的字构成。
  • 仲裁器:该部件负责处理来自 APB1 总线和 USB 接口的存储器请求。它通过向 APB1 提供较高的访问优先权来解决总线的冲突,并且总是保留一半的存储器带宽供 USB 完成传输。它采用时分复用的策略实现了虚拟的双端口 SRAM,即在 USB 传输的同时,允许应用程序访问存储器。此策略也允许任意长度的多字节 APB1 传输。
  • 寄存器映射单元:此部件将 USB 模块的各种字节宽度和位宽度的寄存器映射成能被 APB1 寻址的 16 位宽度的内存集合。
  • APB1 封装:此部件为缓冲区和寄存器提供了到 APB1 的接口,并将整个 USB 模块映射到 APB1地址空间。
  • 中断映射单元:将可能产生中断的 USB 事件映射到三个不同的 NVIC 请求线上:
    • − USB 低优先级中断(通道 20):可由所有 USB 事件触发(正确传输,USB 复位等)。固件在处理中断前应当首先确定中断源。
    • − USB 高优先级中断(通道 19):仅能由同步和双缓冲批量传输的正确传输事件触发,目的是保证最大的传输速率。
    • − USB 唤醒中断(通道 42):由 USB 挂起模式的唤醒事件触发。

4 编程中需要考虑的问题

        在下面的章节中,将介绍 USB 模块和应用程序之间的交互过程,有利于简化应用程序的开发。

4.1 系统复位和上电复位

        发生系统复位或者上电复位时,应用程序首先需要做的是提供 USB 模块所需要的时钟信号,然后清除复位信号,使程序可以访问 USB 模块的寄存器。复位之后的初始化流程如下所述:

首先,由应用程序激活寄存器单元的时钟,再配置设备时钟管理逻辑单元的相关控制位,清除复位信号。

        其次,必须配置 CNTR 寄存器的 PDWN 位用以开启 USB 收发器相关的模拟部分,这点需要特别的处理。此位能打开为端点收发器供电的内部参照电压。由于打开内部电压需要一段启动时间(数据手册中的 tSTARTUP),在此期间内 USB收发器处于不确定状态,所以在设置 CNTR寄存器的 PDWN后必需等待一段时间之后,才能清除 USB 模块的复位信号(清除 CNTR 寄存器上的 FRES 位),和ISTR 寄存器的内容,以便在使能其他任何单元的操作之前清除未处理的假中断标志。

        最后,应用程序需要通过配置设备时钟管理逻辑的相应控制位来为 USB 模块提供标准所定义的48MHz 时钟。

        当系统复位时,应用程序应该初始化所有需要的寄存器和分组缓冲区描述表,使 USB 模块能够产生正常的中断和完成数据传输。所有与端点无关的寄存器需要根据应用的需求进行初始化(比如中断使能的选择,分组缓冲区地址的选择等)。接下来按照 USB 复位处理(参见下段)。

USB 复位(RESET 中断)

        发生 USB 复位时,USB 模块进入前面章节中描述过的系统复位状态:所有端点的通信都被禁止(USB 模块不会响应任何分组)。在 USB 复位后,USB 模块被使能,同时地址为 0 的默认控制端点(端点 0)也需要被使能。这可以通过配置 USB_DADDR 寄存器的 EF 位,EP0R 寄存器和相关的分组缓冲区来实现。

        在 USB 设备的枚举阶段,主机将分配给设备一个唯一的地址,这个地址必须写入USB_DADDR 寄存器的 ADD[6:0]位中,同时配置其他所需的端点。

        当复位中断产生时,应用程序必需在中断产生后的 10ms 之内使能端点 0 的传输。

分组缓冲区的结构和用途

        每个双向端点都可以接收或发送数据。接收到的数据存储在该端点指定的专用缓冲区内,而另一个缓冲区则用于存放待发送的数据。对这些缓冲区的访问由分组缓冲区接口模块实现,它提出缓冲区访问请求,并等待确认信息后返回。

        为防止产生微控制器与 USB 模块对缓冲区的访问冲突,缓冲区接口模块使用仲裁制,使 APB1 总线的一半周期用于微控制器的访问,另一半保证 USB模块的访问。这样,微控制器和 USB 模块对分组缓冲区的访问如同对一个双端口 SRAM 的访问,即使微控制器连续访问缓冲区,也不会产生访问冲突。USB 模块使用固定的时钟,按照 USB 标准,此时钟频率被固定为 48MHz。APB1 总线的时钟可以大于或者小于这个频率。

        注意: 为满足 USB 数据传输率和分组缓冲区接口的系统需求,APB1 总线时钟的频率必须大于 8MHz,以避免数据缓冲区溢出或不满每个端点对应于两个分组缓冲区(一般一个用于发送,另一个用于接收)。这些缓冲区可以位于整个分组存储区的任意位置,因为它们的地址和长度都定义在缓冲区描述表中,而缓冲区描述表也同样位于分组缓冲区中,其地址由 USB_BTABLE 寄存器确定。缓冲区描述表的每个表项都关联到一个端点寄存器,它由 4 个 16 位的字组成,因此缓冲区描述表的起始地址按 8 字节对齐(寄存器的最低 3 位总是'000')。第 21.5.3 节详细介绍缓冲区描述表表项。如果是非同步非双缓冲的单向端点,只需要一个分组缓冲区(即发送方向上的分组缓冲区)。其他未用到的端点或某个未使用的方向上的缓冲区描述表项可以用于其他用途。

分组缓冲区对应的缓冲区描述表项定位

        不管是接收还是发送,分组缓冲区都是从底部开始使用的。USB 模块不会改变超出当前分配到的缓冲区区域以外的其他缓冲区的内容。如果缓冲区收到一个比自己大的数据分组,它只会接收最大为自身大小的数据,其他的丢掉,即发生了所谓的缓冲区溢出异常。

端点初始化

        初始化端点的第一步是把适当的值写到 ADDRn_TX 或 ADDRn_RX 寄存器中,以便 USB 模块能找到要传输的数据或准备好接收数据的缓冲区。USB_EPnR 寄存器的 EP_TYPE 位确定端点的基本类型,EP_KIND 位确定端点的特殊特性。作为发送方,需要设置 USB_EPnR 寄存器的 STAT_TX 位来使能端点,并配置 COUNTn_TX 位决定发送长度。作为接收方,需要设置 STAT_RX 位来使能端点,并且设置 BL_SIZE 和 NUM_BLOCK 位,确定接收缓冲区的大小,以检测缓冲区溢出的异常。

        对于非同步非双缓冲批量传输的单向端点,只需要设置一个传输方向上的寄存器。一旦端点被使能,应用程序就不能再修改 USB_EPnR 寄存器的值和 ADDRn_TX/ADDRn_RX,COUNTn_TX/COUNTn_RX 所在的位置,因为这些值会被硬件实时修改。当数据传输完成时,CTR 中断会产生,此时上述寄存器可以被访问,并重新使能新的传输。

IN 分组(用于数据发送)

        当接收到一 IN 令牌分组时,如果接收到的地址和一个配置好的端点地址相符合的话,USB 模块将会根据缓冲区描述表的表项,访问相应的 ADDRn_TX 和 COUNTn_TX 寄存器,并将这些寄存器中的数值存储到内部的 16 位寄存器 ADDR 和 COUNT(应用程序无法访问)中。此时,USB 模块开始根据 DTOG_TX 位发送 DATA0 或 DATA1 分组,并访问缓冲区(请参考'分组缓冲区的结构和用途'段落)。

        在 IN 分组传输完毕之后,从缓冲区读到的第一个字节将被装载到输出移位寄存器中,并开始发送。最后一个数据字节发送完成之后,计算好的 CRC 将被发送。如果收到的分组所对应的端点是无效的,将根据 USB_EPnR 寄存器上的 STAT_TX 位发送 NAK 或 STALL 握手分组而不发送数据。

        ADDR 内部寄存器被用作当前缓冲区的指针,COUNT 寄存器用于记录剩下未传输的字节数。USB总线使用低字节在先的方式传输从缓冲区中读出的数据。数据从 ADDRn_TX 指向的数据分组缓冲区开始读取,长度为 COUNTn_TX/2 个字。如果发送的数据分组为奇数个字节,则只使用最后一个字的低 8 位。

        在接收到主机响应的 ACK 后,USB_EPnR 寄存器的值有以下更新:DTOG_TX 位被翻转,STAT_TX位为'10',使端点无效,CTR_TX 位被置位。应用程序需要通过 USB_ISTR 寄存器的 EP_ID 和 DIR 位识别产生中断的 USB 端点。CTR_TX 事件的中断服务程序需要首先清除中断标志位,然后准备好需要发送的数据缓冲区,更新 COUNTn_TX 为下次需要传输的字节数,最后再设置 STAT_TX 位为'11'(端点有效),再次使能数据传输。

        当 STAT_TX 位为'10'时(端点为 NAK 状态),任何发送到该端点的 IN 请求都会被 NAK,USB 主机会重发 IN 请求直到该端点确认请求有效。上述操作过程是必需遵守的,以避免丢失紧随上一次 CTR 中断请求的下一个 IN 传输请求。

OUT 分组和 SETUP 分组(用于数据接收)

        USB 模块对这两种分组的处理方式基本相同;对 SETUP 分组的特殊处理将在下面关于控制传输部分详细说明。当接收到一个 OUT 或 SETUP 分组时,如果地址和某个有效端点的地址相匹配,USB模块将访问缓冲区描述表,找到与该端点相关的 ADDRn_RX 和 COUNTn_RX 寄存器,并将ADDRn_RX寄存器的值保存在内部 ADDR 寄存器中。

        同时,COUNT 会被被复位,从 COUNTn_RX中读出的 BL_SIZE 和 NUM_BLOCK 的值用于初始化内部 16 位寄存器 BUF_COUNT,该寄存器用于检测缓冲区溢出(所有的内部寄存器都不能被应用程序访问)。USB 模块将随后收到的数据按字方式组织(先收到的为低字节),并存储到 ADDR 指向的分组缓冲区中。同时,BUF_COUNT 值自动递减,COUNT 值自动递增。当检测到数据分组的结束信号时,USB 模块校验收到 CRC 的正确性。如果传输中没有任何错误发生,则发送 ACK握手分组到主机。即使发生 CRC错误或者其他类型的错误(位填充,帧错误等),数据还是会被保存到分组缓冲区中,至少会保存到发生错误的数据点,只是不会发送 ACK 分组,并且 USB_ISTR 寄存器的 ERR 位将会置位。在这种情况下,应用程序通常不需要干涉处理,USB 模块将从传输错误中自动恢复,并为下一次传输做好准备。如果收到的分组所对应的端点没有准备好,USB 模块将根据 USB_EPnR 寄存器的 STAT_RX 位发送 NAK 或 STALL 分组,数据将不会被写入接收缓冲区。

        ADDRn_RX 的值决定接收缓冲区的起始地址,长度由包含 CRC 的数据分组的长度(即有效数据长度+2)决定,但不能超过 BL_SIZE 和 NUM_BLOCK 所定义的缓冲区的长度。如果接收到的数据分组的长度超出了缓冲区的范围,超过范围的数据不会被写入缓冲区,USB 模块将报告缓冲区发生溢出,并向主机发送 STALL 握手分组,通知此次传输失败,也不产生中断。

如果传输正确完成,USB 模块将发送 ACK 握手分组,内部的 COUNT 寄存器的值会被复制到相应的COUNTn_RX 寄存器中,BL_SIZE 和 NUM_BLOCK 的值保持不变,也不需要重写。USB_EPnR 寄存器按下列方式更新:DTOG_RX 位翻转,STAT_RX=10(NAK)使端点无效,CTR_RX 位置位(如果 CTR中断已使能,将触发中断)。如果传输过程中发生了错误或者缓冲区溢出,前面所列出的动作都不会发生。

        CRT 中断发生时,应用程序需要首先根据 USB_ISTR 寄存器的 EP_ID 和 DIR 位识别是哪个端点的中断请求。在处理 CTR_RX 中断事件时,应用程序首先要确定传输的类型(根据 USB_EPnR寄存器的 SETUP 位),同时清除中断标志位,然后读相关的缓冲区描述表表项指向的 COUNTn_RX寄存器,获得此次传输的总字节数。处理完接收到的数据后,应用程序需要将 USB_EPnR 中的STAT_RX位置成'11',使能下一次的的传输。当 STAT_RX位为'10'时(NAK),任何一个发送到端点上的 OUT 请求都会被 NAK,PC 主机将不断重发被 NAK 的分组,直到收到端点的 ACK 握手分组。以上描述的操作次序是必需遵守的,以避免丢失紧随上一个 CTR 中断的另一个 OUT 分组请求。

控制传输

        控制传输由 3 个阶段组成,首先是主机发送 SETUP 分组的 SETUP 阶段,然后是主机发送零个或多个数据的数据阶段,最后是状态阶段,由与数据阶段方向相反的数据分组构成。SETUP 传输只发生在控制端点,它非常类似于 OUT 分组的传输过程。使能 SETUP 传输除了需要分别初始化DTOG_TX 位为'1',DTOG_RX 位为'0'外,还需要设置 STAT_TX 位和 STAT_RX 位为 10(NAK),由应用程序根据 SETUP 分组的相应字段决定后面的传输是 IN 还是 OUT。

        控制端点在每次发生CTR_RX中断时,都必须检查USB_EPnR寄存器的SETUP位,以识别是普通的OUT分组还是SETUP分组。USB 设备应该能够通过 SETUP 分组中的相应数据决定数据阶段传输的字节数和方向,并且能在发生错误的情况下发送 STALL 分组,拒绝数据的传输。因此在数据阶段,未被使用到的方向都应该被设置成 STALL,并且在开始传输数据阶段的最后一个数据分组时,其反方向的传输仍设成 NAK 状态,这样,即使主机立刻改变了传输方向(进入状态阶段),仍然可以保持为等待控制传输结束的状态。在控制传输成功结束后,应用程序可以把 NAK 变为 VALD,如果控制传输出错,就改为 STALL。

        此时,如果状态分组是由主机发送给设备的,那么 STATUS_OUT 位(USB_EPnR 寄存器中的 EP_KIND)应该被置位,只有这样,在状态传输过程中收到了非零长度的数据分组,才会产生传输错误。在完成状态传输阶段后,应用程序应该清除 STATUS_OUT 位,并且将 STAT_RX 设为 VALID 表示已准备好接收一个新的命令请求,STAT_TX 则设为 NAK,表示在下一个 SETUP 分组传输完成前,不接受数据传输的请求。

        USB 规范定义 SETUP 分组不能以非 ACK 握手分组来响应,如果 SETUP 分组传输失败,则会引发下一个 SETUP 分组。因此,以 NAK 或 STALL 分组响应主机的 SETUP 分组是被禁止的。当 STAT_RX 位被设置为'01'(STALL)或'10'(NAK)时,如果收到 SETUP 分组,USB 模块会接收分组,开始分组所要求的数据传输,并回送 ACK 握手分组。如果应用程序在处理前一个 CTR_RX 事件时USB 模块又收到了 SETUP 分组(即 CTR_RX 仍然保持置位),USB 模块会丢掉收到的 SETUP 分组,并且不回答任何握手分组,以此来模拟一个接收错误,迫使主机再次发送 SETUP 分组。这样做是为了避免丢失紧随一次 CTR_RX 中断之后的又一个 SETUP 分组传输。

4.2 双缓冲端点

        USB 标准不仅为不同的传输模式定义了不同的端点类型,而且对这些数据传输所需要的系统要求做了描述。其中,批量端点适用于在主机 PC 和 USB 设备之间传输大批量的数据,因为主机可以在一帧内利用尽可能多的带宽批量传输数据,使传输效率得到提高。然而,当 USB 设备处理前一次的数据传输时,又收到新的数据分组,它将回应 NAK 分组,使 PC 主机不断重发同样的数据分组,直到设备在可以处理数据时回应 ACK 分组。这样的重传占用了很多带宽,影响了批量传输的速率,因此引入了批量端点的双缓冲机制,提高数据传输率。

        使用双缓冲机制时,单向端点的数据传输将使用到该端点的接收和发送两块数据缓冲区。数据翻转位用来选择当前使用到两块缓冲区中的哪一块,使应用程序可以在 USB 模块访问其中一块缓冲区的同时,对另一块缓冲区进行操作。例如,对一个双缓冲批量端点进行 OUT 分组传输时,USB模块将来自 PC 主机的数据保存到一个缓冲区,同时应用程序可以对另一个缓冲区中的数据进行处理(对于 IN 分组来说,情况是一样的)。因为切换缓冲区的管理机制需要用到所有 4 个缓冲区描述表的表项,分别用来表示每个方向上的两个缓冲区的地址指针和缓冲区大小,因此用来实现双缓冲批量端点的 USB_EPnR 寄存器必需配置为单向。所以只需要设定 STAT_RX 位(作为双缓冲批量接收端点)或者 STAT_TX 位(作为双缓冲批量发送端点)。

        如果需要一个双向的双缓冲批量端点,则须使用两个 USB_EPnR 寄存器。为尽可能利用双缓冲的优势,达到较高的传输速率,双缓冲批量端点的流量控制流程与其他端点的稍有不同。它只在缓冲区发生访问冲突时才会设置端点为 NAK 状态,而不是在每次传输成功后都将端点设为 NAK 状态。

        DTOG 位用来标识 USB 模块当前所使用的储存缓冲区。双缓冲批量端点接收方向的缓冲区由DTOG_RX(USB_EPnR 寄存器的第 14 位)标识,而双缓冲批量端点发送方向的缓冲区由DTOG_TX(USB_EPnR 寄存器的第 6 位)标识。同时,USB 模块也需要知道当前哪个缓冲区正在被应用程序使用,以避免发生冲突。由于 USB_EPnR 寄存器中有 2 个 DTOG 位,而 USB 模块只使用其中的一位来标识硬件所使用的缓冲区,因此,应用程序可使用另一位来标识当前正在使用哪个缓冲区,这个新的标识被称为 SW_BUF 位。下表列出了双缓冲批量端点在实现发送和接收操作时,USB_EPNR 寄存器的 DTOG 位和 SW_BUF 位之间的关系。

双缓冲批量端点缓冲区标识定义

缓冲区标识位

作为发送端点

作为接收端点

DTOG

DTOG_TX (USB_EPnR 寄存器的第 6 位)

DTOG_RX (USB_EPnR 寄存器的第 14 位)

SW_BUF

USB_EPnR 寄存器的第 14 位

USB_EPnR 寄存器的第 6 位

        USB 模块当前使用的缓冲区由 DTOG 位标识,而应用程序所使用的缓冲区由 SW_BUF 位标识,这两个位的标识方式相同,下表描述了这种标识方式。

双缓冲批量端点的缓冲区使用标识

端点类型

DTOG 位

SW_BUF 位

USB 模块使用的缓冲区

应用程序使用的缓冲区

IN 端点

0

1

ADDRn_TX_0/COUNTn_TX_0

ADDRn_TX_1/COUNTn_TX_1

OUT 端点

1

0

ADDRn_RX_1/COUNTn_RX_1

ADDRn_RX_0/COUNTn_RX_0

OUT 端点

0

0

无 (1)

ADDRn_RX_0/COUNTn_RX_0

OUT 端点

1

1

无 (1)

ADDRn_RX_0/COUNTn_RX_0

1.端点处于 NAK 状态

可以通过以下方式设置一个双缓冲批量端点:

  • 将 USB_EPnR 寄存器的 EP_TYPE 位设为'00',定义端点为批量端点
  • 将 USB_EPnR 寄存器的 EP_KIND 位设为'1',定义端点为双缓冲端点

        应用程序根据传输开始时用到的缓冲区来初始化 DTOG 和 SW_BUF 位;这需要考虑到这两位的数据翻转特性。设置好 DBL_BUF 位之后,每完成一次传输后,USB 模块将根据双缓冲批量端点的流量控制操作,并且持续到 DBL_BUF 变为无效为止。

        每次传输结束,根据端点的传输方向,CTR_RX 位或 CTR_TX 位将会置为'1'。与此同时,硬件将设置相应的 DTOG 位,完全独立于软件来实现缓冲区交换机制。DBL_BUF 位设置后,每次传输结束时,双缓冲批量端点的 STAT 位的取值不会像其他类型端点一样受到传输过程的影响,而是一直保持为'11'(有效)。但是,如果在收到新的数据分组的传输请求时,USB 模块和应用程序发生了缓冲区访问冲突(即 DTOG 和 SW_BUF 为相同的值,),状态位将会被置为'10'(NAK)。应用程序响应 CTR 中断时,首先要清除中断标志,然后再处理传输完成的数据。

        应用程序访问缓冲区之后,需要翻转 SW_BUF 位,以通知 USB模块该块缓冲区已变为可用状态。由此,双缓冲批量传输的 NAK 分组的数目只由应用程序处理一次数据传输的快慢所决定:如果数据处理的时间小于 USB 总线上完成一次数据传输的时间,则不会发生重传,此时,数据的传输率仅受限于 USB 主机。

        应用程序也可以不考虑双缓冲批量端点的特殊控制流程,直接在相应 USB_EPnR 寄存器的 STAT 位写入非'11'的任何状态,在这种情况下,USB 模块将按照写入的状态执行流程而忽略缓冲器实际的使用情况。

4.3 同步传输

        USB 标准定义了一种全速的需要保持固定和精确的数据传输率的传输方式:同步传输。同步传输一般用于传输音频流、压缩的视频流等对数据传输率有严格要求的数据。一个端点如果在枚举时被定义为“同步端点”,USB 主机则会为每个帧分配固定的带宽,并且保证每个帧正好传送一个IN 分组或者 OUT 分组(由端点传输方向确定分组类型)。为了满足带宽要求,同步传输中没有出错重传;这也就意味着,同步传输在发送或接收数据分组之后,无握手协议,即不会发送 ACK 分组。同样,同步传输只传送 PID(分组 ID)为 DATA0 的数据包,而不会用到数据翻转机制。

        通过设置 USB_EPnR 寄存器 EP_TYPE 为'10',可以使其成为同步端点。同步端点没有握手机制,根据 USB 标准中的说明,USB_EPnR 寄存器的 STAT_RX 位和 STAT_TX 位分别只能设成'00'(禁止)和'11'(有效)。同步传输通过实现双缓冲机制来简化软件应用程序开发,它同样使用两个缓冲区,以确保在 USB 模块使用其中一块缓冲区时,应用程序可以访问另外一块缓冲区。USB 模块使用的缓冲区根据不同的传输方向,由不同的 DTOG 位来标识。(同一寄存器中的DTOG_RX 位用来标识接收同步端点,DTOG_TX 位用来标识发送同步端点),见下表。

步端点的缓冲区使用标识同

端点类型

USB 模块使用的缓冲区

应用程序使用的缓冲区

IN 端点

0

ADDRn_TX_0/COUNTn_TX_0

ADDRn_TX_1/COUNTn_TX_1

IN 端点

1

ADDRn_TX_1/COUNTn_TX_1

ADDRn_TX_0/COUNTn_TX_0

OUT 端点

0

ADDRn_RX_0/COUNTn_RX_0

ADDRn_RX_1/COUNTn_RX_1

OUT 端点

1

ADDRn_RX_1/COUNTn_RX_1

ADDRn_RX_0/COUNTn_RX_0

        与双缓冲批量端点一样,一个 USB_EPnR 寄存器只能处理同步端点单方向的数据传输,如果要求同步端点在两个传输方向上都有效,则需要使用两个 USB_EPnR 寄存器。应用程序需要根据首次传输的数据分组来初始化 DTOG 位;它的取值还需要考虑到 DTOG_RX 或DTOG_TX 两位的数据翻转特性。每次传输完成时,USB_EPnR 寄存器的 CTR_RX 位或 CTR_TX 位置位。与此同时,相关的 DTOG 位由硬件翻转,从而使得交换缓冲区的操作完全独立于应用程序。传输结束时,STAT_RX 或 STAT_TX 位不会发生变化,因为同步传输没有握手机制,所以不需要任何流量控制,而一直设为'11'(有效)。同步传输中,即使 OUT 分组发生 CRC 错误或者缓冲区溢出,本次传输仍被看作是正确的,并且可以触发 CTR_RX 中断事件;但是,发生 CRC 错误时硬件会设置 USB_ISTR 寄存器的 ERR 位,提醒应用程序数据可能损坏。

4.4 挂起/恢复事件

        USB 标准中定义了一种特殊的设备状态,即挂起状态,在这种状态下 USB 总线上的平均电流消耗不超过 500uA。这种电流限制对于由总线供电的 USB 设备至关重要,而自供电的设备则不需要严格遵守这样的电流消耗限制。USB 主机以 3 毫秒内不发送任何信号标志进入挂起状态。通常情况下 USB 主机每毫秒会发送一个 SOF,当 USB 模块检测到 3 个连续的 SOF 分组丢失事件即可判定主机发出了挂起请求,接着它会置位 SB_ISTR 寄存器的 SUSP 位,以触发挂起中断。USB 设备进入挂起状态之后,将由“唤醒”序列唤醒。所谓的“唤醒”序列,可以由 USB 主机发起,也可以由 USB设备本身触发;但是,只有 USB 主机可以结束“唤醒”序列。

        被挂起的 USB 模块必须至少还具备检测 RESET 信号的功能,它会将其当作一次正常的复位操作来执行。实际的挂起操作过程对于不同的 USB 设备来说是不同的,因为需要不同的操作来降低电源消耗。下面描述了一起典型的挂起操作,重点介绍应用程序如何响应 USB 模块的 SUSP 信号。

  1. 将 USB_CNTR 寄存器的 FSUSP 置为'1',这将使 USB 模块进入挂起状态。USB 模块一旦进入挂起状态,对 SOF 的检测立刻停止,以避免在 USB 挂起时又发生新的 SUSP 事件。
  2. 消除或减少 USB 模块以外的其他模块的静态电流消耗。
  3. 将 USB_CNTR 寄存器的 LP_MODE 位置为'1',这将消除模拟 USB 收发器的静态电流消耗,但仍能检测到唤醒信号。

        可以选择关闭外部振荡器和设备的 PLL,以停止设备内部的任何活动。当设备处于挂起状态时发生 USB 事件,该设备会被唤醒,并需要调用“唤醒”例程来恢复系统时钟,和 USB 数据传输。如果唤醒设备的是 USB 复位操作,则应该保证唤醒的过程不要超过 10 毫秒(参见“USB 协议规范”)。USB 模块处于挂起状态时,唤醒或复位事件需要清除 USB_CNTR 寄存器的 LP_MODE 位。

        即使唤醒事件可以立刻触发一个 WKUP 中断事件,但由于恢复系统时钟需要比较长的延迟时间,处理 WKUP 中断的中断服务程序必须非常小心;为了减短系统唤醒的时间,建议将唤醒代码直接写在挂起代码后面,这样就可以在系统时钟重启后迅速进入唤醒代码中执行。为防止或减少 ESD 等干扰意外地唤醒系统(从挂起模式退出是一个异步事件),在挂起过程中数据线被过滤,滤波宽度大约为 70nS。下面是唤醒操作的过程:

  1. 启动外部振荡器和设备的 PLL(此项可选)。
  2. 清零 USB_CNTR 寄存器的 FSUSP 位。
  3. USB_FNR 寄存器的 RXDP 和 RXDM 位可以用来判断是什么触发了唤醒事件,如表 124 所示,它还同时列出了各种情况软件应该采取的操作。如果需要的话,可以通过检测这两位变成'10'(代表空闲总线状态)的时间来知道唤醒或复位事件的结束。此外,在复位事件结束时,USB_ISTR 寄存器的 RESET 位被置为'1',如果 RESET 中断被使能,就会产生中断。此中断应该按正常的复位操作处理。

唤醒事件检测

[RXDP, RXDM] 的状态

唤醒事件

应用程序应执行的操作

00

复位

10

无 (总线干扰)

恢复到挂起状态

01

恢复挂起

11

未定义的值 (总线干扰)

恢复到挂起状态

        设备可能不是被与 USB 模块相关的事件唤醒的(例如一个鼠标的移动可唤醒整个系统)。在这种情况下,先将 USB_CNTR 寄存器的 RESUME 位置为'1',然后在 1ms-15ms 之间再把它清为 0 可以启动唤醒序列(这个间隔可以用 ESOF 中断来实现,该中断在内核正常运行时每 1ms 发生一次)。RESUME 位被清零后,唤醒过程将由主机 PC 完成,可以利用 USB_FNR 寄存器的 RXDP 和 RXDM 位来判断唤醒是否完成。

        注意:只有在 USB 模块被设置为挂起状态时(设置 USB_CNTR 寄存器的 FSUSP 位为'1'),才可以设置 RESUME 位。

5 例程设计

5.1 CompositeEquipmentHID&VCP

        该程序是一个基于W55MH32微控制器的USB复合设备固件,结合了虚拟串口(VCP)和HID功能,并通过USART输出调试信息。以下是程序设计的总结:

1. 系统初始化

时钟配置:使用外部高速时钟(HSE)作为PLL输入,倍频至目标频率(如HSE 8MHz ×27 = 216MHz)。配置AHB、APB1、APB2总线时钟分频,优化外设时钟。启用内部低速(LSI)和高速(HSI)时钟源,可能供其他外设使用。

USART初始化:配置USART1(PA9-TX, PA10-RX),波特率115200,用于调试信息输出。重定向printf至USART,便于通过串口打印系统状态。

2. USB功能配置

USB设备初始化:设置USB时钟(Set_USBClock)和中断(USB_Interrupts_Config)。初始化USB协议栈(USB_Init),使能DP上拉电阻(DP_PUUP=1)以宣告设备连接。

复合设备处理:主循环监控USB连接状态(bDeviceState),状态变化时通过串口通知用户。

        当USB配置成功(CONFIGURED状态)时,检测接收缓冲区(Receive_Buffer_port)是否有数据,并通过CDC接口回传数据(CDC_Send_DATA)。

3.数据通信流程

// 主循环中的数据通信处理
while (1)
{// 当USB设备处于已配置状态(与主机建立连接)if (bDeviceState == CONFIGURED){// 检查接收缓冲区是否有数据且上次发送已完成if (Receive_length_port != 0 && packet_sent == 1){// 通过USB CDC(虚拟串口)发送数据CDC_Send_DATA((unsigned char *)Receive_Buffer_port, Receive_length_port);// 重置接收缓冲区状态Receive_length_port = 0;// 重新使能端点接收数据(准备下一次接收)SetEPRxValid(ENDP7);}}// 检测USB连接状态变化if (usbstatus != bDeviceState){usbstatus = bDeviceState;  // 更新状态// 打印连接状态变化信息(调试用)if (usbstatus == CONFIGURED){printf("USB connection successful\n");}else{printf("USB disconnected\n");}}
}// USB中断服务函数(示例,通常在其他文件中实现)
void USB_LP_CAN1_RX0_IRQHandler(void)
{USB_Istr();  // USB中断处理主函数
}// 端点数据接收回调函数(示例)
void EP7_IN_Callback(void)
{packet_sent = 1;  // 标记发送完成
}void EP6_OUT_Callback(void)
{// 从端点缓冲区读取数据到应用缓冲区Receive_length_port = USB_SIL_Read(EP6, Receive_Buffer_port);// 标记接收到新数据new_data_received = 1;
}

CDC数据传输:接收数据通过USB端点中断填充至缓冲区,主循环检测到数据后发送。使用SetEPRxValid(ENDP7)重新使能接收端点,准备下一次数据传输。

调试输出:系统启动时通过USART输出时钟配置信息(SYSCLK、HCLK等)。USB连接状态变化时打印提示信息,便于调试设备状态。

4. 关键代码设计

时钟配置函数(RCC_ClkConfiguration):通过HSE和PLL提供高精度系统时钟,确保USB和USART稳定工作。

USART重定向:SER_PutChar和fputc实现字符发送,支持printf格式化输出。

USB中断与轮询结合:中断处理底层数据传输,主循环轮询状态及处理应用层逻辑。

6 下载验证

6.1 CompositeEquipmentHID&VCP

现象描述:

  • 上电后,USART1立即输出系统时钟信息,包括SYSCLK(如216MHz)HCLK、PCLK1/2等。
  • 插入USB线后,主机识别到复合设备(VCP + HID),设备管理器中显示虚拟串口(如“USB Serial Device (COMx)”)和HID设备。
  • USART打印“USB connection successful”。
  • 通过串口工具(如PuTTY)向虚拟串口发送数据,设备立即回显相同数据。
  • USB断开时,USART打印“USB disconnected”。

http://www.xdnf.cn/news/13253.html

相关文章:

  • P4 QT项目----串口助手(4.2)
  • 力扣HOT100之堆:215. 数组中的第K个最大元素
  • crackme008
  • 7zip超详细安装教程(含最新版本)压缩软件使用全解析
  • 【LangChain】1 模型,提示和输出解释器
  • STM32外部中断(寄存器和hal库实现)
  • 机房断电后 etcd 启动失败的排查与快速恢复实录
  • YOLOv11 | 注意力机制篇 | EMAttention与C2PSA机制的协同优化
  • 从0到1:HBase安装与操作指南
  • 3.vue3核心语法
  • 中马泰语言电商系统:打开东南亚电商市场的多语言钥匙
  • 【第二十三章 IAP】
  • Vim 替换命令完整学习笔记
  • 一次消谐器:高效抑制铁磁谐振
  • 对DOM操作 与 jQuery的简单理解(通俗
  • DeepSeek生成流程图
  • 6.10 Mysql 事务 锁 面试题
  • 【Dv3Admin】系统视图角色管理API文件解析
  • 2025蓝奏云软件库合集分享链接汇总:极刻云搜 - 一站式获取海量资源
  • Linux下V2Ray安装配置指南
  • axios访问后台时,返回404
  • chrome插件中如何使用midscene.js
  • Leetcode 3577. Count the Number of Computer Unlocking Permutations
  • LeetCode 240 搜索二维矩阵 II
  • MySQL中的隐式主键和隐藏列
  • Go 语言接口详解
  • 架空线路图像视频监测装置
  • SkyWalking 10.2.0 SWCK 配置过程
  • 『uniapp』url拦截屏蔽 避免webview中打开淘宝店铺自动跳转淘宝
  • 腾讯开源 AniPortrait:音频驱动的逼真肖像动画生成革命