从 SerCx2 托管串行端口读取数据

(或 UART) 串行控制器通常包括接收 FIFO。 此 FIFO 对从连接到串行端口的外围设备接收的数据提供硬件控制缓冲。 若要从接收 FIFO 读取数据,此设备的外围驱动程序会将读取 (IRP_MJ_READ) 请求发送到串行端口。

如果串行端口继续接收数据的速度超过外围驱动程序读取数据的速度,则接收 FIFO 可能会溢出。 为防止因溢出而丢失数据,外围驱动程序通常应将串行端口配置为使用硬件流控制。 使用流控制,当接收 FIFO 几乎已满时,串行控制器硬件会自动向外围设备发出信号以停止发送数据。 通常,由 SerCx2 管理的串行端口应使用硬件流控制。 有关详细信息,请参阅 流控制详细信息

但是,流控制不应用于阻止外围设备发送数据的时间过长,否则设备可能无法继续正常运行。 例如,如果阻止设备将数据从此缓冲区发送到串行端口的时间过长,外围设备可能有一个内部数据缓冲区,该缓冲区可能会溢出。

本页内容

使用异步读取请求

为了避免错误操作和可能的数据丢失,外围驱动程序负责及时从串行控制器的接收 FIFO 读取数据。 通常,在收到数据之前,外围驱动程序会向串行端口发送异步读取请求,以预期将来从外围设备到达数据。 此读取请求在 SerCx2 I/O 队列中保持挂起状态,直到可以从接收 FIFO 读取数据。

在大多数硬件平台上,外围驱动程序不需要一次挂起多个此类读取请求。 在极少数情况下,如果在收到数据后,读取请求需要很长时间才能完成,导致生成的数据备份导致外围设备丢失数据或行为不正确,则驱动程序可能需要具有多个未完成的读取请求。

假设外围驱动程序一次只有一个此类读取请求挂起,则此请求中所需的数据缓冲区大小在很大程度上取决于外围设备的已知行为。 例如,如果驱动程序提前知道设备需要多少字节的数据,则驱动程序会将请求中的缓冲区大小设置为此字节数。 一旦缓冲区中填充了来自接收 FIFO 的数据,读取请求就会完成。 作为响应,驱动程序可以异步发送新的读取请求来等待下一个数据块。

但是,外围驱动程序可能事先不知道预期来自外围设备的数据量。 在这种情况下,驱动程序将读取请求中的数据缓冲区设置为适当的大小,然后依靠间隔超时来标识外围设备中的数据的结尾。 为读取缓冲区选择适当的大小可能需要详细了解外围设备如何运行。 如果读取缓冲区太小,驱动程序必须发送一个或多个额外的读取请求才能完成数据读取。

间隔超时详细信息

若要为读取和写入请求设置超时参数,外围驱动程序可以将 IOCTL_SERIAL_SET_TIMEOUTS 请求发送到串行端口。 读取超时由此请求中的 ReadIntervalTimeoutReadTotalTimeoutMultiplierReadTotalTimeoutConstant 参数值控制。 ReadIntervalTimeout 指定接收事务中允许的两个连续字节之间的最大时间间隔。 如果 ReadTotalTimeoutMultiplierReadTotalTimeoutConstant 均为零,并且读取请求发送到串行端口时串行控制器的接收 FIFO 为空,则此请求不会 (因此在 SerCx2 I/O 队列中保持挂起状态,) 直到端口收到至少一个字节的新数据。 有关详细信息,请参阅 SERIAL_TIMEOUTS

芯片 (SoC) 集成电路上的系统上的串行端口可能能够以每秒几兆位或更高的峰值速率从外围设备接收数据。 此设备的外围驱动程序开发人员可能会尝试将 readIntervalTimeout 参数指定的间隔超时值设置为 () 毫秒或更短,但此值不太可能产生所需的效果。 这是因为用于检测间隔超时的计时器的准确性受系统时钟粒度的限制。

例如,如果系统时钟周期为 15 毫秒,并且驱动程序将 ReadIntervalTimeout 值设置为 1 毫秒,则从 0 到略高于 15 毫秒的任意位置的字节到字节间隔可能会触发超时。有时,此设置可能会导致在从外围设备进行数据传输时发生超时。 若要确保仅在此传输完成后才发生超时,驱动程序可以将 ReadIntervalTimeout 设置为一个略大于 15 毫秒的值。 例如,如果 ReadIntervalTimeout 设置为 20 毫秒,则 30 毫秒的字节到字节间隔可靠地触发超时,而 15 毫秒或更短的间隔不会触发超时。

有关计时器准确度如何取决于系统时钟的详细信息,请参阅 计时器准确性

流控制详细信息

最佳做法是,使用 SerCx2 托管串行端口的外围驱动程序应将这些端口配置为使用硬件流控制,以防止接收 FIFO 溢出。 在没有挂起的读取请求的情况下,SerCx2 不会提供超过接收 FIFO 容量的接收数据的软件缓冲。 如果允许此 FIFO 溢出,则数据丢失。

若要启用硬件流控制,外围驱动程序可能会发送 IOCTL_SERIAL_SET_HANDFLOW 请求来设置串行端口的握手和流控制设置。 或者,驱动程序可能会发送 IOCTL_SERIAL_APPLY_DEFAULT_CONFIGURATION 请求,将串行端口配置为使用包含硬件流控制的默认硬件设置集。 IOCTL_SERIAL_SET_HANDFLOW请求使用SERIAL_HANDFLOW结构来描述流控制设置。 IOCTL_SERIAL_APPLY_DEFAULT_CONFIGURATION请求可能包含供应商指定数据格式的类似信息。

如果外围驱动程序使用 IOCTL_SERIAL_SET_HANDFLOW 请求启用硬件流控制,则驱动程序应在此请求 的SERIAL_HANDFLOW 结构中设置以下标志:

  • 结构的 ControlHandShake 成员中的SERIAL_CTS_HANDSHAKE标志。 此标志使串行端口能够将流控制用于接收操作。
  • FlowReplace 成员中的SERIAL_RTS_CONTROL和SERIAL_RTS_HANDSHAKE标志。 这些标志使串行端口能够将流控制用于传输操作。