赛灵思ZYNQ官方文档UG585自学翻译笔记与代码示例:XILINX UART控制器详解:特性与功能

XILINX UART 控制器

第 19 章

19.1 概述

UART 控制器是一种全双工异步收发器,支持多种可编程波特率和 I/O 信号格式,还可实现自动奇偶校验生成和多主机检测模式。

UART 的操作由配置寄存器和模式寄存器控制,通过状态寄存器、中断状态寄存器和调制解调器状态寄存器可读取 FIFO 状态、调制解调器信号及其他控制器功能的状态。

控制器采用独立的接收(Rx)和发送(Tx)数据路径,每条路径均包含一个 64 字节的 FIFO。控制器对 Tx 和 Rx FIFO 中的数据进行串并转换和并串转换,并包含模式切换功能,支持 RxD 和 TxD 信号的多种环回配置。FIFO 中断状态位支持轮询或中断驱动的处理方式,软件通过 Rx 和 Tx 数据端口寄存器读写数据字节。

当 UART 用于类调制解调器应用时,调制解调器控制模块检测并生成调制解调器握手信号,并根据握手协议控制接收和发送路径。

19.1.1 特性

每个 UART 控制器(UART 0 和 UART 1)具有以下特性:

  • 可编程波特率发生器
  • 64 字节接收和发送 FIFO
  • 可编程协议:
    • 6、7 或 8 个数据位
    • 1、1.5 或 2 个停止位
    • 奇校验、偶校验、空校验、标记校验或无校验
  • 校验错误、帧错误和溢出错误检测
  • 线路中断生成
  • 中断生成
  • RxD 和 TxD 模式:正常 / 回显模式,以及使用模式切换的诊断环回模式
  • UART 0 与 UART 1 环回选项
  • 调制解调器控制信号:CTS、RTS、DSR、DTR、RI 和 DCD 仅在 EMIO 接口可用

19.1.2 系统视角

UART 控制器的系统视角图如图 19-1 所示。

(图 19-1:UART 系统视角,此处省略图表)

slcr 寄存器组(参见 4.3 节 "SLCR 寄存器")包含用于 UART 时钟、复位和 MIO-EMIO 信号映射的控制位。软件通过连接到 PS AXI 互连的 APB 32 位从接口访问 UART 控制器寄存器。每个控制器的 IRQ 连接到 PS 中断控制器并路由到 PL。

19.1.3 注意事项

参考时钟操作限制 两个 UART 控制器共用一个 PS 时钟发生器,送至每个 UART 控制器波特率发生器的参考时钟(UART_Ref_Clk)频率相同,但可单独使能(参见 25.6.3 节 "SDIO、SMC、SPI、Quad-SPI 和 UART 时钟")。控制器始终由内部 PS 时钟发生器提供时钟。

注意:CPU_1x 时钟和 UART_Ref_clk 时钟之间没有频率限制。

7z007s 和 7z010 CLG225 器件 7z007s 单核和 7z010 双核 CLG225 器件支持 32 个 MIO 引脚(如 "MIO 概览表" 第 52 页所示),这限制了 UART 信号在 MIO 引脚上的可用性。如有需要,UART 的 TxD 和 RxD 信号可通过 EMIO 接口路由并传递到 PL 引脚。所有 CLG225 器件的限制列于 1.1.3 节 "注意事项"。

19.2 功能描述

19.2.1 框图

UART 模块的框图如图 19-2 所示。

(图 19-2:UART 框图,此处省略图表)

19.2.2 控制逻辑

控制逻辑包含控制寄存器(Control register)和模式寄存器(Mode register),用于选择 UART 的各种操作模式。

控制寄存器用于使能、禁用接收器和发送器模块,发出软复位,重启接收器超时周期,以及控制发送器中断逻辑。

接收线路中断检测必须由软件实现,当 RxFIFO 中出现帧错误(Frame Error)后跟随一个或多个零字节时,表明检测到线路中断。

模式寄存器选择波特率发生器使用的时钟,选择发送和接收数据的位长、校验位和停止位,还选择 UART 的操作模式(正常 UART 模式、自动回显、本地环回或远程环回)。

19.2.3 波特率发生器

波特率发生器为接收器和发送器提供位周期时钟(即波特率时钟)。波特率时钟通过分配基准时钟 uart_clk 和单周期时钟使能实现,以达到相应的分频效果。波特率生成的有效逻辑如图 19-3 所示。

(图 19-3:UART 波特率发生器,此处省略图表)

波特率发生器可使用主时钟信号 uart_ref_clk 或主时钟除以 8 的信号 uart_ref_clk/8,由模式寄存器(uart.mode_reg0)中的 CLKS 位选择,所选时钟在以下描述中称为 sel_clk。

sel_clk 时钟经过分频生成另外三个时钟:baud_sample、baud_tx_rate 和 baud_rx_rate。baud_tx_rate 是用于发送数据的目标波特率,baud_rx_rate 名义上与 baud_tx_rate 速率相同,但会与输入的接收数据重新同步,baud_sample 以 baud_rx_rate 和 baud_tx_rate 的([BDIV]+1)倍速率运行,用于过采样接收数据。

sel_clk 时钟频率通过波特率发生器寄存器中的 CD 字段值分频生成 baud_sample 时钟使能,该寄存器可编程为 1 至 65535 之间的值。

baud_sample 时钟通过 [BDIV]+1 分频,BDIV 是波特率分频器寄存器中的可编程字段,可编程为 4 至 255 之间的值,复位值为 15,默认情况下 baud_sample 时钟与 baud_tx_clock/baud_rx_rate 的比率为 16:1。

baud_sample 时钟使能的频率如公式 19-1 所示: \(baud\_sample=\frac{sel\_clk}{CD}\quad\text{公式19-1}\)

baud_rx_rate 和 baud_tx_rate 时钟使能的频率如公式 19-2 所示: \(baud\_rate=\frac{sel\_clk}{CD\times(BDIV + 1)}\quad\text{公式19-2}\)

重要提示:向波特率发生器寄存器(uart.Baud_rate_gen_reg0)或波特率分频器寄存器(uart.Baud_rate_divider_reg0)写入数据前,必须禁用发送器和接收器,重新使能前需对发送器和接收器执行软复位。

表 19-1 展示了 uart_ref_clk 时钟、波特率、时钟分频器(CD 和 BDIV)之间的关系及误差率示例,高亮条目显示 CD 和 BDIV 的默认复位值。示例中假设系统时钟频率为 UART_Ref_Clk=50 MHz,Uart_ref_clk/8=6.25 MHz。可通过改变 UART 参考时钟频率获得更精确的波特率(详见第 25 章 "时钟" 中 UART_Ref_Clk 的编程)。

表 19-1:UART 参数值示例

时钟 波特率 计算 CD 值 实际 CD 值 BDIV 实际波特率 误差(BPS) 误差百分比
UART 参考时钟 600 10416.667 10417 7 599.980 0.020 -0.003
UART 参考时钟 / 8 9,600 81.380 81 7 9,645.061 45.061 0.469
UART 参考时钟 9,600 651.041 651 7 9,600.614 0.614 0.006
UART 参考时钟 28,800 347.222 347 4 28,818.44 18.44 0.064
UART 参考时钟 115,200 62.004 62 6 115,207.37 7.373 0.0064
UART 参考时钟 230,400 31.002 31 6 230,414.75 14.75 0.006
UART 参考时钟 460,800 27.127 9 11 462,962.96 2,162.96 0.469
UART 参考时钟 921,600 9.042 9 5 925,925.92 4,325.93 0.469

19.2.4 发送 FIFO(TxFIFO)

发送 FIFO(TxFIFO)存储从 APB 接口写入的数据,直到发送模块将其取出并加载到移位寄存器中。TxFIFO 的最大数据宽度为 8 位,通过写入 TxFIFO 寄存器向其加载数据。

当数据加载到 TxFIFO 后,TxFIFO 空标志被清除,直到 TxFIFO 中的最后一个字被取出并加载到发送器移位寄存器后才保持低电平。这意味着主机软件在需要下一个数据前有一个完整的串行字时间,可在空标志置位时做出反应,向 TxFIFO 写入另一个字而不影响传输时间。

TxFIFO 满中断状态(TFULL)表明 TxFIFO 已完全满,防止更多数据加载到 TxFIFO。若此时向 TxFIFO 执行 APB 写入,会触发溢出,且写入数据不会加载到 TxFIFO。发送 FIFO 近满标志(TNFULL)表明 FIFO 中没有足够的空闲空间容纳另一个按模式寄存器 WSIZE 位编程大小的写入。

TxFIFO 近满标志(TNFULL)表明 TxFIFO 中仅剩 1 字节空闲空间。

可在 TxFIFO 填充水平上设置阈值触发(TTRIG),使用发送器触发寄存器设置该值,当 TxFIFO 填充水平达到编程值时触发。

19.2.5 发送器数据流

发送模块从 TxFIFO 中取出并行数据并加载到发送器移位寄存器中进行串行化。

发送模块将起始位、数据位、校验位和停止位作为串行数据流移出,数据以最低有效位优先,在发送波特率时钟使能(baud_tx_rate)的下降沿传输。典型的发送数据流如图 19-4 所示。

(图 19-4:发送数据流,此处省略图表)

uart.mode_reg0 [CHRL] 寄存器位选择字符长度(数据位数),uart.mode_reg0 [NBSTOP] 寄存器位选择要发送的停止位数。

19.2.6 接收 FIFO(RxFIFO)

RxFIFO 存储由接收器串行移位寄存器接收的数据,最大数据宽度为 8 位。

当数据加载到 RxFIFO 后,RxFIFO 空标志被清除,直到 RxFIFO 中的所有数据通过 APB 接口传输后才保持低电平。从空的 RxFIFO 读取数据返回零。

RxFIFO 满状态(Chnl_int_sts_reg0 [RFUL] 和 Channel_sts_reg0 [RFUL] 位)表明 RxFIFO 已满,防止更多数据加载到 RxFIFO。当 RxFIFO 中有空间时,接收器中存储的任何字符都将被加载。

可在 RxFIFO 填充水平上设置阈值触发(RTRIG),使用接收器触发电平寄存器(Rcvr_FIFO_trigger_level0)设置该值,当 RxFIFO 填充水平超过编程值时触发,范围为 1 至 63。

19.2.7 接收器数据捕获

UART 使用 UARTx REF_CLK 和时钟使能(baud_sample)对 UARTx_RxD 信号进行连续过采样。当采样检测到向低电平的跳变时,可能表明起始位开始。当 UART 检测到 UART_RxD 输入为低电平时,等待 BDIV 波特率时钟周期的一半计数,然后再采样三次。如果这三个位仍为低电平,接收器认为这是有效的起始位(默认 BDIV 为 15 的情况如图 19-5 所示)。

(图 19-5:默认 BDIV 的接收器数据流,此处省略图表)

当识别到有效的起始位后,接收器波特率时钟使能(baud_rx_rate)重新同步,以便在每个位的理论中点附近对输入的 UART RxD 信号进行进一步采样(如图 19-6 所示)。

(图 19-6:重新同步的接收器数据流,此处省略图表)

当重新同步的 baud_rx_rate 为高电平时,比较最后三次采样的位,通过多数表决确定逻辑值(两个相同的采样值定义数据位的值)。当确定串行数据位的值后,将其移位到接收移位寄存器中。当组装完一个完整的字符后,寄存器内容被推入 RxFIFO。

接收器校验错误 每次接收一个字符时,接收器根据 uart.mode_reg0 [PAR] 位域计算接收数据位的校验值,并与接收的校验位进行比较。若检测到差异,校验错误位被置为 1(uart.Chnl_int_sts_reg0 [PARE]),若使能则生成中断。

接收器帧错误 当接收器在一帧结束时未检测到有效的停止位,帧错误位被置为 1(uart.Chnl_int_sts_reg0 [FRAME]),若使能则生成中断。

接收器溢出错误 当接收一个字符时,控制器检查 RxFIFO 是否有空间,若有则将字符写入 RxFIFO;若 RxFIFO 已满,控制器等待。若检测到 RxD 上的后续起始位且 RxFIFO 仍满,则数据丢失,控制器设置 Rx 溢出中断位(uart.Chnl_int_sts_reg0 [ROVR] = 1),若使能则生成中断。

接收器超时机制 接收器超时机制使接收器能够检测到不活动的 RxD 信号(持续高电平)。超时周期通过写入 uart.Rcvr_timeout_reg0 [RTO] 位域编程,超时机制使用 10 位递减计数器。每当在 RxD 信号上接收到新的起始位,或软件向 uart.Control_reg0 [RSTTO] 写入 1(无论之前的 [RSTTO] 值如何)时,计数器重新加载并开始递减计数。

若 1023 个位周期内未发生起始位或复位超时,将发生超时,中断状态寄存器中的接收器超时错误位 [TIMEOUT] 将被置位,应向控制寄存器的 [RSTTO] 位写入 1 以重启超时计数器,加载新编程的超时值。

计数器的高 8 位从 [RTO] 位域的值重新加载,低 2 位初始化为零,计数器由 UART 位时钟驱动。例如,若 [RTO] = 0xFF,则超时周期为 1023 位时钟(256×4 减 1)。若向 [RTO] 位写入 0,超时机制被禁用。

当递减计数器达到 0 时,发生接收器超时,控制器设置超时中断状态位(uart.Chnl_int_sts_reg0 [TIMEOUT] = 1)。若中断使能(uart.Intrpt_mask_reg0 [TIMEOUT] = 1),则向 PS 中断控制器断言 IRQ 信号。

每当发生超时中断时,通过向 Chnl_int_sts_reg0 [TIMEOUT] 位写回 1 清除该中断。软件必须设置 uart.Control_reg0 [RSTTO] = 1 才能生成进一步的接收超时中断。

19.2.8 I/O 模式切换

模式切换控制控制器内 RxD 和 TxD 信号的路由(如图 19-7 所示),无论 UARTx TxD/RxD I/O 信号的 MIO-EMIO 路由如何,使用模式切换的环回都会发生。有四种操作模式(如图 19-7 所示),由 uart.mode_reg0 [CHMODE] 寄存器位域控制:正常模式、自动回显模式、本地环回模式和远程环回模式。

(图 19-7:TxD 和 RxD 的 UART 模式切换,此处省略图表)

正常模式 用于标准 UART 操作。

自动回显模式 在 RxD 上接收数据,模式切换将数据路由到接收器和 TxD 引脚,发送器的数据无法从控制器发送出去。

本地环回模式 不连接到 RxD 或 TxD 引脚,而是将发送的数据环回至接收器。

远程环回模式 将 RxD 信号连接到 TxD 信号,此模式下控制器不能在 TxD 上发送任何内容,也不能在 RxD 上接收任何内容。

19.2.9 UART0 与 UART1 连接

PS 中的两个 UART 控制器的 I/O 信号可连接在一起,通过设置 slcr.LOOP [UA0_LOOP_UA1] 位 = 1,一个控制器的 RxD 和 CTS 输入信号连接到另一个 UART 控制器的 TxD 和 RTS 输出信号,其他流控制信号不连接。无论 MIO-EMIO 编程如何,这种 UART 到 UART 的连接都会发生。

19.2.10 状态和中断

中断和状态寄存器 软件可读取两个状态寄存器,均显示原始状态。Chnl_int_sts_reg0 寄存器可读取状态并生成中断,Channel_sts_reg0 寄存器仅可读取状态。

Chnl_int_sts_reg0 寄存器是粘性的,一旦某位置位,保持置位状态直到软件清除(向该位写入 1)。该寄存器与 Intrpt_mask_reg0 掩码寄存器进行按位与运算,若任何按位与运算结果为 1,则向 PS 中断控制器断言 UART 中断。

  • Channel_sts_reg0:只读原始状态,写入被忽略。

各种 FIFO 和系统指示器路由到 uart.Channel_sts_reg0 寄存器和 / 或 uart.Chnl_int_sts_reg0 寄存器(如图 19-8 所示)。

(图 19-8:中断和状态信号,此处省略图表)

中断寄存器和位域汇总于表 19-2。

表 19-2:UART 中断状态位

(此处省略表格具体位分配,保留核心内容)

中断掩码寄存器 Intrpt_mask_reg0 是只读中断掩码 / 使能寄存器,用于屏蔽 Chnl_int_sts_reg0 寄存器中的各个原始中断:

  • 若掩码位 = 0,中断被屏蔽;
  • 若掩码位 = 1,中断使能。

此掩码由只写的 Intrpt_en_reg0 和 Intrpt_dis_reg0 寄存器控制,每个相关的使能 / 禁用中断位应互斥设置(例如,要使能中断,向 Intrpt_en_reg0 [x] 写入 1,向 Intrpt_dis_reg0 [x] 写入 0)。

通道状态 这些状态位位于 Channel_sts_reg0 寄存器中:

  • TACTIVE:发送器状态机活动状态,若为活动状态,发送器当前正在移出字符;
  • RACTIVE:接收器状态机活动状态,若为活动状态,接收器已检测到起始位且正在移入字符;
  • FDELT:接收器流延迟触发连续状态,用于监控 RxFIFO 电平与流延迟触发电平的比较结果。

非 FIFO 中断 这些中断状态位位于 Chnl_int_sts_reg0 寄存器中:

  • TIMEOUT:接收器超时错误中断状态,当接收器超时计数器因长时间空闲状态而到期时触发;
  • PARE:接收器校验错误中断状态,当接收的校验位与预期值不匹配时触发;
  • FRAME:接收器帧错误中断状态,当接收器未检测到有效停止位时触发(参见 19.2.7 节 "接收器数据捕获");
  • DMSI:指示 DCD、DSR、RI 或 CTS 调制解调器流控制信号的逻辑电平变化,包括这些信号的高到低和低到高逻辑跳变。

FIFO 中断 表 19-2 中列出的 FIFO 中断状态位如图 19-9 所示,这些中断状态位位于通道状态(uart.Channel_sts_reg0)和通道中断状态(uart.Chnl_int_sts_reg0)寄存器中,例外的是 [TOVR] 和 [ROVR] 位不属于 uart.Channel_sts_reg0 寄存器。

(图 19-9:UART RxFIFO 和 TxFIFO 中断,此处省略图表)

FIFO 触发电平由以下位域控制:

  • uart.Rcvr_FIFO_trigger_level0 [RTRIG],6 位字段;
  • uart.Tx_FIFO_trigger_level0 [TTRIG],6 位字段。

19.2.11 调制解调器控制

调制解调器控制模块便于调制解调器与 UART 之间的通信控制,包含调制解调器状态寄存器、调制解调器控制寄存器、中断状态寄存器中的 DMSI 位以及通道状态寄存器中的 FDELT。当调制解调器状态寄存器中的 DCTS、DDSR、TERI 或 DDCD 置位时,触发该事件。

只读的调制解调器状态寄存器用于读取清除发送(CTS)、数据载波检测(DCD)、数据设备就绪(DSR)和振铃指示(RI)调制解调器输入的值,还报告这些输入的变化,并指示当前是否启用自动流控制模式。调制解调器状态寄存器中的位通过向特定位写入 1 清除。

可读写的调制解调器控制寄存器用于设置数据终端就绪(DTR)和请求发送(RTS)输出,以及启用自动流控制模式寄存器。

默认情况下,自动流控制模式禁用,调制解调器输入和输出完全由软件控制。当通过设置调制解调器控制寄存器中的 FCM 位启用自动流控制模式时,UART 的发送和接收状态通过调制解调器握手输入和输出自动控制。

在自动流控制模式下,请求发送输出根据接收器 FIFO 的当前填充水平断言和撤销,导致远端发送器暂停传输,防止 UART 接收器 FIFO 溢出。流延迟寄存器(Flow_delay_reg0)中的 FDEL 字段用于设置接收器 FIFO 的触发电平,导致请求发送撤销,直到 FIFO 电平降至 FDEL 以下 4 个字节时才重新断言。

此外,在自动流控制模式下,UART 仅在清除发送输入断言时发送。当清除发送撤销时,UART 在下一个字符边界暂停传输。

若选择自动流控制,必须编程流延迟寄存器以控制数据流入(通过撤销 RTS 信号),该值对应 RTS 信号将被撤销时的 RxFIFO 电平,当 RxFIFO 电平降至流延迟寄存器中编程值以下 4 个字节时,RTS 信号重新断言。

uart.Channel_sts_reg0 [FDELT] 寄存器位用于监控 RxFIFO 电平与流延迟触发电平的比较结果,当 RxFIFO 电平大于或等于流延迟寄存器中编程的触发电平时,[FDELT] 位置位。

流延迟寄存器中编程的触发电平与 Rx 触发电平寄存器无关,仅用于通过 RTS 调制解调器信号控制数据流入。

CPU 仅在收到 Rx 触发中断时被接收数据中断,根据 Rx 触发电平寄存器中编程的触发电平检索数据。

可编程参数 UART 流控制信号 DTR 和 RTS 由 UART 控制器生成:

  • RTS 流控制信号用于向连接的终端发送 Rx(准备发送信号);
  • DTR 流控制信号指示 UART 控制器的状态(数据终端就绪)。

DTR 和 RTS 可由软件手动控制或由控制器自动控制:

  • 自动模式下,调制解调器控制单元断言和撤销 RTS 和 DTR 信号;
  • 手动模式下,软件使用 uart.Modem_ctrl_reg0 控制 RTS 和 DTR 信号。

uart.Modem_ctrl_reg0:

  • DTR\]:数据终端就绪输出信号;

  • FCM\]:选择自动或手动流控制。

  • DCTS\]:清除发送(输入)变化状态;

  • TERI\]:振铃指示(输入)后沿状态;

选择以下操作选项之一:

示例:自动流控制

  1. 设置 RTS 触发电平,写入 uart.Flow_Delay_reg0 寄存器(撤销调制解调器信号 RTS 的触发电平);
  2. 选择自动流控制,向 uart.Modem_ctrl_reg0 [FCM] 写入 1;
  3. 验证模式更改为自动,读取 uart.Modem_sts_reg0 [FCMS] 直到其等于 1。

当软件向 uart.Modem_ctrl_reg0 [FCM] 写入 1 时,调制解调器切换到自动模式,通过读取调制解调器状态寄存器中的 FCMS 状态位验证从手动到自动的模式变化。

示例:手动流控制

  1. 选择手动流控制,向 uart.Modem_ctrl_reg0 [FCM] 写入 0;
    • 选项 a:使用 uart.Modem_ctrl_reg0 [DTR] 控制 DTR 输出信号;
    • 选项 b:使用 uart.Modem_ctrl_reg0 [RTS] 控制 RTS 输出信号。

示例:监控 DCD、DSR、RI、CTS 流控制信号的变化 控制器检测 DCD、DSR、RI、CTS 流控制信号的逻辑电平变化,当检测到逻辑电平变化时,硬件设置 uart.Chnl_int_sts_reg0 [DMSI] 位,此变化或通道状态可选择性地生成中断。

  1. 检查流控制信号状态,uart.Modem_sts_reg0 寄存器报告调制解调器状态。

在中断模式下,当调制解调器线路状态变化导致 DMSI 中断发生时,ISR 可运行。

19.3 编程指南

19.3.1 启动序列

主要示例:启动序列

  1. 复位控制器:复位编程模型参见 19.4.2 节 "复位";
  2. 配置 I/O 信号路由:Rx/Tx 可路由到 MIO 或 EMIO,调制解调器控制信号仅在 EMIO 接口可用(参见 19.5.1 节 "MIO 编程");
  3. 配置 UART_Ref_Clk:UART 时钟架构和编程模型参见 19.4.1 节 "时钟";
  4. 配置控制器功能:使用 uart.Control_reg0 和 uart.mode_reg0 寄存器编程 I/O 信号特性和控制器功能(示例见 19.3.2 节 "配置控制器功能");
  5. 配置中断:所有模式下均使用中断管理 Rx/Tx FIFO(参见 19.2.10 节 "状态和中断" 及 19.3.5 节 "RxFIFO 触发电平中断" 中的程序示例);
  6. 配置调制解调器控制(可选):支持轮询和中断驱动选项(参见 19.2.11 节 "调制解调器控制");
  7. 管理发送和接收数据:支持轮询和中断驱动处理程序(参见 19.3.3 节 "发送数据" 和 19.3.4 节 "接收数据")。

19.3.2 配置控制器功能

示例:配置控制器功能 本示例配置字符帧、波特率、FIFO 触发电平、Rx 超时机制并使能控制器。复位后需要执行所有这些步骤,控制器使能和禁用之间无需重复。

  1. 配置 UART 字符帧,向 uart.mode_reg0 写入 0x0000_0020: a. 禁用时钟预分频器 UART_REF_CLK/8:[CLKS] = 0; b. 选择 8 位字符长度:[CHRL] = 00; c. 选择无校验:[PAR] = 100; d. 选择 1 个停止位:[NBSTOP] = 00; e. 选择正常通道模式(模式切换):[CHMODE] = 00;
  2. 配置波特率,写入三个寄存器:uart.Control_reg0、uart.Baud_rate_gen_reg0 和 uart.Baud_rate_divider_reg0(计算的 CD 和 BDIV 值示例见表 19-1 第 587 页,波特率发生器参见 19.2.3 节 "波特率发生器"): a. 禁用 Rx 路径:设置 uart.Control_reg0 [RXEN] = 0,[RXDIS] = 1; b. 禁用 Tx 路径:设置 uart.Control_reg0 [TXEN] = 0,[TXDIS] = 1; c. 向 uart.Baud_rate_gen_reg0 [CD] 位域写入计算的 CD 值; d. 向 uart.Baud_rate_divider_reg0 [BDIV] 位值写入计算的 BDIV 值; e. 复位 Tx 和 Rx 路径:uart.Control_reg0 [TXRST] 和 [RXRST] = 1(这些位自清除); f. 使能 Rx 路径:设置 [RXEN] = 1,[RXDIS] = 0; g. 使能 Tx 路径:设置 [TXEN] = 1,[TXDIS] = 0;
  3. 设置 RxFIFO 触发电平,向 uart.Rcvr_FIFO_trigger_level0 寄存器写入触发电平:
    • 选项 a:使能 Rx 触发电平,向 [RTRIG] 位域写入 1 至 63;
    • 选项 b:禁用 Rx 触发电平,向 [RTRIG] 位域写入 0;
  4. 使能控制器,向 uart.Control_reg0 寄存器写入 0x0000_0117: a. 复位 Tx 和 Rx 路径:uart.Control_reg0 [TXRST] 和 [RXRST] = 1(这些位自清除); b. 使能 Rx 路径:[RXEN] = 1,[RXDIS] = 0; c. 使能 Tx 路径:[TXEN] = 1,[TXDIS] = 0; d. 重启接收器超时计数器:[RSTTO] = 1; e. 不开始发送中断:[STTBRK] = 0; f. 停止中断发送器:[STPBRK] = 1;
  5. 编程接收器超时机制,向 uart.Rcvr_timeout_reg0 寄存器写入超时值(参见第 589 页 "接收器超时机制"): a. 要使能超时机制,向 [RSTTO] 位域写入 1 至 255; b. 要禁用超时机制,向 [RSTTO] 位域写入 0。

19.3.3 发送数据

软件可使用轮询或中断控制数据流向 TxFIFO 和 RxFIFO。

注意:当 TxFIFO 空状态为真时,软件可写入 64 字节(TxFIFO 的大小)而无需检查 TxFIFO 状态。实际上,当发送器活动时,软件可写入超过 64 字节,因为软件向 TxFIFO 写入数据时,控制器正在取出数据并将其串行化到 TxD 信号上。

示例:使用轮询方法发送数据 本示例中,软件可选择填充 TxFIFO 直到满状态位置位,或等待 TxFIFO 为空(并写入最多 64 字节),当 TxFIFO 近满时,软件始终可写入一个字节。

  1. 检查 TxFIFO 是否为空,等待直到 uart.Channel_sts_reg0 [TEMPTY] = 1;
  2. 向 TxFIFO 填充数据,向 uart.TX_RX_FIFO0 寄存器写入 64 字节数据;
  3. 向 TxFIFO 写入更多数据,有两种方法:
    • 选项 A:检查 TxFIFO 是否有空间容纳另一个字节(即 TxFIFO 未满),读取 uart.Channel_sts_reg0 [TFUL] 直到其等于 0,当 [TFUL] = 0 时,向 TxFIFO 写入一个字节,然后再次读取 [TFUL];
    • 选项 B:等待 TxFIFO 为空,读取 uart.Channel_sts_reg0 [TEMPTY] 直到其等于 1,然后转到步骤 2 填充 64 字节数据。

示例:使用中断方法发送数据 本示例最初以与轮询方法类似的方式填充 TxFIFO,然后软件使能 TxFIFO 空中断,以提醒软件再次填充 TxFIFO。

  1. 禁用 TxFIFO 空中断,向 uart.Intrpt_dis_reg0 [TEMPTY] 写入 1;
  2. 向 TxFIFO 填充数据,向 uart.TX_RX_FIFO0 寄存器写入 64 字节数据;
  3. 检查 TxFIFO 是否有空间容纳另一个字节(即 TxFIFO 未满),读取 uart.Channel_sts_reg0 [TFUL] 直到其等于 0,当 [TFUL] = 0 时,向 TxFIFO 写入一个字节,然后再次读取 [TFUL];
  4. 重复步骤 2 和 3,直到 uart.Channel_sts_reg0 [TFUL] 未置位;
  5. 使能中断,向 uart.Intrpt_en_reg0 [TEMPTY] 写入 1 使能中断;
  6. 等待 TxFIFO 为空,当 uart.Channel_int_sts_reg0 [TEMPTY] 置为 1 时从步骤 1 重复。

19.3.4 接收数据

示例:使用轮询方法接收数据

  1. 等待 RxFIFO 填充到触发电平,检查 uart.Channel_sts_reg0 [RTRIG] = 1 或 uart.Chnl_int_sts_reg0 [TIMEOUT] = 1;
  2. 从 RxFIFO 读取数据,从 uart.TX_RX_FIFO0 寄存器读取数据;
  3. 重复步骤 2 直到 FIFO 为空,检查 uart.Channel_sts_reg0 [REMPTY] = 1;
  4. 若 Rx 超时中断状态位置位则清除,向 Chnl_int_sts_reg0 [TIMEOUT] 写入 1。

示例:使用中断方法接收数据

  1. 使能中断,向 uart.Intrpt_en_reg0 [TIMEOUT] 和 uart.Intrpt_en_reg0 [RTRIG] 写入 1;
  2. 等待 RxFIFO 填充到触发电平或 Rx 超时,检查 uart.Chnl_int_sts_reg0 [RTRIG] = 1 或 uart.Chnl_int_sts_reg0 [TIMEOUT] = 1;
  3. 从 RxFIFO 读取数据,从 uart.TX_RX_FIFO0 寄存器读取数据;
  4. 重复步骤 2 和 3 直到 FIFO 为空,检查 uart.Channel_sts_reg0 [REMPTY] = 1;
  5. 若中断状态位置位则清除,向 Chnl_int_sts_reg0 [TIMEOUT] 或 Chnl_int_sts_reg0 [RTRIG] 写入 1。

19.3.5 RxFIFO 触发电平中断

示例:设置 RxFIFO 触发电平并使能中断 Intrpt_en_reg0 寄存器有位用于使能中断掩码,Intrpt_dis_reg0 有位用于强制禁用中断,每对位应互斥设置(即一个寄存器的位为 1,另一个寄存器的位为 0):

  • Intrpt_en_reg0:只写,使能中断位;
  • Intrpt_dis_reg0:只写,强制禁用中断位。
  1. 编程触发电平,向 6 位字段 uart.Rcvr_FIFO_trigger_level0 [RTRIG] 写入;
  2. 使能 RTRIG 中断,设置使能位,清除禁用位,并验证掩码值: a. 设置 uart.Intrpt_en_reg0 [RTRIG] = 1; b. 清除 uart.Intrpt_dis_reg0 [RTRIG] = 0; c. 读取 uart.intrpt_mask_reg0 [RTRIG] = 1(中断使能);
  3. 禁用 RTRIG 中断,设置禁用位,清除使能位,并验证掩码值: a. 设置 uart.Intrpt_dis_reg0 [RTRIG] = 1; b. 清除 uart.Intrp_en_reg0 [RTRIG] = 0; c. 读取 uart.intrpt_mask_reg0 [RTRIG] = 0(中断禁用);
  4. 清除 RTRIG 中断,向 uart.Intrpt_dis_reg0 [RTRIG] 位域写入 1。

当一个中断的使能位和禁用位都置位时,中断被禁用。

通过读取 uart.Intrpt_mask_reg0 寄存器可确定中断使能 / 禁用机制的状态,若掩码位 = 1,则中断使能。

19.3.6 寄存器概述

UART 寄存器概述如表 19-3 所示,详情见附录 B "寄存器详情"。

表 19-3:UART 寄存器概述

功能 uart. 寄存器名称 概述
配置 Control_reg0、mode_reg0、Baud_rate_gen_reg0、Baud_rate_divider_reg0 配置模式和波特率
中断处理 Intrpt_en_reg0、Intrpt_dis_reg0、Intrpt_mask_reg0、Chnl_int_sts_reg0、Channel_sts_reg0 使能 / 禁用中断掩码、通道中断状态、通道状态
Rx 和 Tx 数据 TX_RX_FIFO0 读取接收数据,写入要发送的数据
接收器 Rcvr_timeout_reg0、Rcvr_FIFO_trigger_level0 配置接收器超时和 RxFIFO 触发电平值
发送器 Tx_FIFO_trigger_level0 配置 TxFIFO 触发电平值
调制解调器 Modem_ctrl_reg0、Modem_sts_reg0、Flow_delay_reg0 配置类调制解调器应用

19.4 系统功能

19.4.1 时钟

控制器和 I/O 接口由参考时钟(UART_REF_CLK)驱动,控制器的互连还需要 APB 接口时钟(CPU_1x),这两个时钟均来自 PS 时钟子系统。

CPU_1x 时钟 通用时钟编程信息参见 25.2 节 "CPU 时钟",CPU_1x 时钟与 UART 参考时钟异步运行。

参考时钟 PS 时钟子系统中参考时钟的生成由 slcr.UART_CLK_CTRL 寄存器控制,该寄存器可选择时钟源自的 PLL 并设置分频频率,还控制每个 UART 控制器的时钟使能。UART 参考时钟的生成参见 25.6.3 节 "SDIO、SMC、SPI、Quad-SPI 和 UART 时钟"。

操作限制 注意:时钟操作限制参见 19.1.3 节 "注意事项"。

示例:配置参考时钟 时钟可基于 PS 时钟子系统中的任何 PLL,本示例中使用 I/O PLL(1000 MHz 时钟),时钟分频器为 0x14,为 UART 控制器生成 50 MHz 时钟。

  1. 编程 UART 参考时钟,向 slcr.UART_CLK_CTRL 寄存器写入 0x0000_1401: a. 时钟分频器 slcr.UART_CLK_CTRL [DIVISOR] = 0x14; b. 选择 IO PLL,slcr.UART_CLK_CTRL [SRCSEL] = 0; c. 使能 UART 0 参考时钟,slcr.UART_CLK_CTRL [CLKACT0] = 1; d. 禁用 UART 1 参考时钟,slcr.UART_CLK_CTRL [CLKACT1] 位 = 0。

19.4.2 复位

控制器复位位由 PS 生成(参见第 26 章 "复位系统")。

示例:控制器复位

  • 选项 1:断言控制器复位,设置 slcr.UART_RST_CTRL [UARTx_REF_RST, UARTx_CPU1X_RST] 位 = 1;
  • 选项 2:撤销控制器复位,清除 slcr.UART_RST_CTRL [UARTx_REF_RST, UARTx_CPU1X_RST] 位 = 0。

19.5 I/O 接口

19.5.1 MIO 编程

UART RxD 和 TxD 信号可路由到多组 MIO 引脚之一或 EMIO 接口,所有调制解调器流控制信号始终路由到 EMIO 接口,不在 MIO 引脚上可用。所有 UART 信号列于表 19-4,RxD 和 TxD 信号的路由参见 2.4 节 "PS--PL 电压电平转换器使能"。

示例:将 UART 0 RxD/TxD 信号路由到 MIO 引脚 46、47 本示例中,UART 0 RxD 和 TxD 信号通过 MIO 引脚 46 和 47 路由,还有许多其他引脚选项。

  1. 配置 MIO 引脚 46 为 RxD 信号,向 slcr.MIO_PIN_46 寄存器写入 0x0000_12E1: a. 将 UART 0 RxD 信号路由到引脚 46; b. 输出禁用(设置 TRI_ENABLE = 1); c. LVCMOS18(其他电压选项参见寄存器定义); d. 慢 CMOS 边沿(温和设置); e. 使能内部上拉电阻; f. 禁用 HSTL 接收器;
  2. 配置 MIO 引脚 47 为 TxD 信号,向 slcr.MIO_PIN_47 寄存器写入 0x0000_12E0: a. 将 UART 0 TxD 信号路由到引脚 47; b. 三态由 UART 控制(TRI_ENABLE = 0); c. LVCMOS18(其他电压选项参见寄存器定义); d. 慢 CMOS 驱动边沿; e. 使能内部上拉电阻; f. 禁用 HSTL 接收器。

19.5.2 MIO -- EMIO 信号

UART I/O 信号如表 19-4 所示,MIO 引脚及基于器件版本的限制见 2.5.4 节 "MIO 概览表"。

以下是基于文档中 UART 控制器相关内容整理的完整编程实例(含代码及注释),涵盖初始化、数据收发、中断处理等核心场景:

一、UART 启动序列初始化(基础配置)

c

运行

cpp 复制代码
/* 参考文档19.3.1节启动序列:至 */
void uart_init() {
    // 1. 复位控制器(参考19.4.2节复位:至)
    slcr.UART_RST_CTRL = (1 << UARTx_REF_RST) | (1 << UARTx_CPU1X_RST); // 断言复位
    slcr.UART_RST_CTRL = 0; // 撤销复位

    // 2. 配置MIO引脚(将UART0 RxD/TxD路由到MIO46/47:至)
    slcr.MIO_PIN_46 = 0x000012E1; // RxD:上拉、LVCMOS18、输入使能
    slcr.MIO_PIN_47 = 0x000012E0; // TxD:上拉、LVCMOS18、输出使能

    // 3. 配置UART参考时钟(50MHz,源I/O PLL 1000MHz,分频20:至)
    slcr.UART_CLK_CTRL = 0x00001401; // DIVISOR=0x14,SRCSEL=IO PLL,使能UART0

    // 4. 配置控制器功能(字符帧、波特率等:至)
    // 4.1 配置字符帧:8位数据、无校验、1停止位、正常模式
    uart.mode_reg0 = 0x00000020; 
    // [CLKS]=0(不用分频),[CHRL]=00(8位),[PAR]=100(无校验),[NBSTOP]=00(1停止位)

    // 4.2 配置波特率(以115200为例,参考表19-1:)
    uart.Control_reg0 &= ~((1 << RXEN) | (1 << TXEN)); // 禁用Rx/Tx
    uart.Control_reg0 |= ((1 << RXDIS) | (1 << TXDIS)); 
    uart.Baud_rate_gen_reg0 = 62; // CD=62(计算值)
    uart.Baud_rate_divider_reg0 = 6; // BDIV=6(计算值)
    uart.Control_reg0 |= ((1 << TXRST) | (1 << RXRST)); // 软复位Rx/Tx(自清除)
    uart.Control_reg0 &= ~((1 << RXDIS) | (1 << TXDIS)); // 启用Rx/Tx
    uart.Control_reg0 |= ((1 << RXEN) | (1 << TXEN));

    // 4.3 设置RxFIFO触发级别(16字节)和超时机制(使能,超时值0xFF)
    uart.Rcvr_FIFO_trigger_level0 = 16; // [RTRIG]=16
    uart.Rcvr_timeout_reg0 = 0xFF; // 使能超时,1023位周期

    // 4.4 使能控制器
    uart.Control_reg0 = 0x00000117; 
    // 复位Rx/Tx、启用收发、重启超时计数器、停止中断发送

    // 5. 配置中断(使能RTRIG和TIMEOUT中断:至)
    uart.Intrpt_en_reg0 = (1 << RTRIG) | (1 << TIMEOUT);
    uart.Intrpt_dis_reg0 = 0; // 清除禁用位
}

二、数据发送(轮询方式)

c

运行

cpp 复制代码
/* 参考19.3.3节轮询发送:至 */
void uart_send_polling(uint8_t *data, uint32_t len) {
    uint32_t i = 0;
    // 等待TxFIFO为空
    while (!(uart.Channel_sts_reg0 & (1 << TEMPTY)));

    // 填充数据至TxFIFO
    while (i < len) {
        // 检查TxFIFO是否未满
        if (!(uart.Channel_sts_reg0 & (1 << TFUL))) {
            uart.TX_RX_FIFO0 = data[i++]; // 写入1字节
        }
    }
}

三、数据发送(中断方式)

c

运行

cpp 复制代码
/* 参考19.3.3节中断发送:至 */
uint8_t tx_buf[128];
uint32_t tx_idx = 0;
uint32_t tx_len = 0;

// 初始化发送缓冲区并启动传输
void uart_send_interrupt(uint8_t *data, uint32_t len) {
    tx_idx = 0;
    tx_len = len;
    memcpy(tx_buf, data, len);

    // 禁用TEMPTY中断,填充初始数据
    uart.Intrpt_dis_reg0 = (1 << TEMPTY);
    while (tx_idx < tx_len && !(uart.Channel_sts_reg0 & (1 << TFUL))) {
        uart.TX_RX_FIFO0 = tx_buf[tx_idx++];
    }
    // 使能TEMPTY中断
    uart.Intrpt_en_reg0 = (1 << TEMPTY);
}

// TEMPTY中断服务程序(ISR)
void uart_tx_isr() {
    // 检查中断源
    if (uart.Chnl_int_sts_reg0 & (1 << TEMPTY)) {
        // 继续填充数据
        while (tx_idx < tx_len && !(uart.Channel_sts_reg0 & (1 << TFUL))) {
            uart.TX_RX_FIFO0 = tx_buf[tx_idx++];
        }
        // 发送完成后禁用中断
        if (tx_idx >= tx_len) {
            uart.Intrpt_dis_reg0 = (1 << TEMPTY);
        }
        uart.Chnl_int_sts_reg0 = (1 << TEMPTY); // 清除中断
    }
}

四、数据接收(轮询方式)

c

运行

cpp 复制代码
/* 参考19.3.4节轮询接收:至 */
void uart_recv_polling(uint8_t *buf, uint32_t max_len, uint32_t *recv_len) {
    *recv_len = 0;
    // 等待RxFIFO达到触发级别或超时
    while (!(uart.Channel_sts_reg0 & (1 << RTRIG)) && 
           !(uart.Chnl_int_sts_reg0 & (1 << TIMEOUT)));

    // 读取数据直到FIFO为空
    while (*recv_len < max_len && !(uart.Channel_sts_reg0 & (1 << REMPTY))) {
        buf[*recv_len] = uart.TX_RX_FIFO0;
        (*recv_len)++;
    }

    // 清除超时中断(若有)
    if (uart.Chnl_int_sts_reg0 & (1 << TIMEOUT)) {
        uart.Chnl_int_sts_reg0 = (1 << TIMEOUT);
    }
}

五、数据接收(中断方式)

c

运行

cpp 复制代码
/* 参考19.3.4节中断接收:至 */
uint8_t rx_buf[128];
uint32_t rx_idx = 0;

// 中断服务程序(ISR)
void uart_rx_isr() {
    // 处理RTRIG中断(FIFO达到触发级别)
    if (uart.Chnl_int_sts_reg0 & (1 << RTRIG)) {
        while (!(uart.Channel_sts_reg0 & (1 << REMPTY)) && rx_idx < 128) {
            rx_buf[rx_idx++] = uart.TX_RX_FIFO0;
        }
        uart.Chnl_int_sts_reg0 = (1 << RTRIG); // 清除中断
    }

    // 处理超时中断
    if (uart.Chnl_int_sts_reg0 & (1 << TIMEOUT)) {
        while (!(uart.Channel_sts_reg0 & (1 << REMPTY)) && rx_idx < 128) {
            rx_buf[rx_idx++] = uart.TX_RX_FIFO0;
        }
        uart.Chnl_int_sts_reg0 = (1 << TIMEOUT); // 清除中断
        uart.Control_reg0 |= (1 << RSTTO); // 重启超时计数器
    }
}

六、RxFIFO 触发中断配置

c

运行

cpp 复制代码
/* 参考19.3.5节触发中断配置:至 */
void uart_config_rtrig_interrupt(uint8_t trigger_level) {
    // 1. 设置触发级别(1-63)
    uart.Rcvr_FIFO_trigger_level0 = trigger_level;

    // 2. 使能RTRIG中断
    uart.Intrpt_en_reg0 = (1 << RTRIG); // 使能
    uart.Intrpt_dis_reg0 = 0; // 清除禁用
    // 验证:uart.Intrpt_mask_reg0[RTRIG]应返回1

    // (可选)禁用RTRIG中断示例
    // uart.Intrpt_dis_reg0 = (1 << RTRIG);
    // uart.Intrpt_en_reg0 = 0;
}

七、自动流控制配置

c

运行

cpp 复制代码
/* 参考19.2.11节自动流控制:至 */
void uart_enable_auto_flow_control() {
    // 1. 设置RTS触发级别(RxFIFO达到32字节时撤销RTS)
    uart.Flow_delay_reg0 = 32; // FDEL=32

    // 2. 使能自动流控制
    uart.Modem_ctrl_reg0 |= (1 << FCM); // [FCM]=1

    // 3. 等待模式切换完成
    while (!(uart.Modem_sts_reg0 & (1 << FCMS))); // 等待FCMS=1
}

代码说明

  1. 寄存器命名 :代码中寄存器(如uart.mode_reg0slcr.UART_CLK_CTRL)及位域(如RXENRTRIG)均来自文档 19.3.6 节寄存器概述(至)。
  2. 波特率计算 :115200 波特率的CD=62BDIV=6参考表 19-1 中 "115200" 行(),计算公式见 19.2.3 节(至)。
  3. 中断处理 :中断使能 / 禁用通过Intrpt_en_reg0/Intrpt_dis_reg0实现,符合文档中 "互斥设置" 要求(至)。
  4. 流控制:自动模式下 RTS 信号根据 RxFIFO 电平自动控制,参考 19.2.11 节(至)。

可根据实际硬件需求调整触发级别、波特率等参数,确保与外部设备匹配。