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\]:振铃指示(输入)后沿状态;
选择以下操作选项之一:
示例:自动流控制
- 设置 RTS 触发电平,写入 uart.Flow_Delay_reg0 寄存器(撤销调制解调器信号 RTS 的触发电平);
- 选择自动流控制,向 uart.Modem_ctrl_reg0 [FCM] 写入 1;
- 验证模式更改为自动,读取 uart.Modem_sts_reg0 [FCMS] 直到其等于 1。
当软件向 uart.Modem_ctrl_reg0 [FCM] 写入 1 时,调制解调器切换到自动模式,通过读取调制解调器状态寄存器中的 FCMS 状态位验证从手动到自动的模式变化。
示例:手动流控制
- 选择手动流控制,向 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] 位,此变化或通道状态可选择性地生成中断。
- 检查流控制信号状态,uart.Modem_sts_reg0 寄存器报告调制解调器状态。
在中断模式下,当调制解调器线路状态变化导致 DMSI 中断发生时,ISR 可运行。
19.3 编程指南
19.3.1 启动序列
主要示例:启动序列
- 复位控制器:复位编程模型参见 19.4.2 节 "复位";
- 配置 I/O 信号路由:Rx/Tx 可路由到 MIO 或 EMIO,调制解调器控制信号仅在 EMIO 接口可用(参见 19.5.1 节 "MIO 编程");
- 配置 UART_Ref_Clk:UART 时钟架构和编程模型参见 19.4.1 节 "时钟";
- 配置控制器功能:使用 uart.Control_reg0 和 uart.mode_reg0 寄存器编程 I/O 信号特性和控制器功能(示例见 19.3.2 节 "配置控制器功能");
- 配置中断:所有模式下均使用中断管理 Rx/Tx FIFO(参见 19.2.10 节 "状态和中断" 及 19.3.5 节 "RxFIFO 触发电平中断" 中的程序示例);
- 配置调制解调器控制(可选):支持轮询和中断驱动选项(参见 19.2.11 节 "调制解调器控制");
- 管理发送和接收数据:支持轮询和中断驱动处理程序(参见 19.3.3 节 "发送数据" 和 19.3.4 节 "接收数据")。
19.3.2 配置控制器功能
示例:配置控制器功能 本示例配置字符帧、波特率、FIFO 触发电平、Rx 超时机制并使能控制器。复位后需要执行所有这些步骤,控制器使能和禁用之间无需重复。
- 配置 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;
- 配置波特率,写入三个寄存器: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;
- 设置 RxFIFO 触发电平,向 uart.Rcvr_FIFO_trigger_level0 寄存器写入触发电平:
- 选项 a:使能 Rx 触发电平,向 [RTRIG] 位域写入 1 至 63;
- 选项 b:禁用 Rx 触发电平,向 [RTRIG] 位域写入 0;
- 使能控制器,向 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;
- 编程接收器超时机制,向 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 近满时,软件始终可写入一个字节。
- 检查 TxFIFO 是否为空,等待直到 uart.Channel_sts_reg0 [TEMPTY] = 1;
- 向 TxFIFO 填充数据,向 uart.TX_RX_FIFO0 寄存器写入 64 字节数据;
- 向 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。
- 禁用 TxFIFO 空中断,向 uart.Intrpt_dis_reg0 [TEMPTY] 写入 1;
- 向 TxFIFO 填充数据,向 uart.TX_RX_FIFO0 寄存器写入 64 字节数据;
- 检查 TxFIFO 是否有空间容纳另一个字节(即 TxFIFO 未满),读取 uart.Channel_sts_reg0 [TFUL] 直到其等于 0,当 [TFUL] = 0 时,向 TxFIFO 写入一个字节,然后再次读取 [TFUL];
- 重复步骤 2 和 3,直到 uart.Channel_sts_reg0 [TFUL] 未置位;
- 使能中断,向 uart.Intrpt_en_reg0 [TEMPTY] 写入 1 使能中断;
- 等待 TxFIFO 为空,当 uart.Channel_int_sts_reg0 [TEMPTY] 置为 1 时从步骤 1 重复。
19.3.4 接收数据
示例:使用轮询方法接收数据
- 等待 RxFIFO 填充到触发电平,检查 uart.Channel_sts_reg0 [RTRIG] = 1 或 uart.Chnl_int_sts_reg0 [TIMEOUT] = 1;
- 从 RxFIFO 读取数据,从 uart.TX_RX_FIFO0 寄存器读取数据;
- 重复步骤 2 直到 FIFO 为空,检查 uart.Channel_sts_reg0 [REMPTY] = 1;
- 若 Rx 超时中断状态位置位则清除,向 Chnl_int_sts_reg0 [TIMEOUT] 写入 1。
示例:使用中断方法接收数据
- 使能中断,向 uart.Intrpt_en_reg0 [TIMEOUT] 和 uart.Intrpt_en_reg0 [RTRIG] 写入 1;
- 等待 RxFIFO 填充到触发电平或 Rx 超时,检查 uart.Chnl_int_sts_reg0 [RTRIG] = 1 或 uart.Chnl_int_sts_reg0 [TIMEOUT] = 1;
- 从 RxFIFO 读取数据,从 uart.TX_RX_FIFO0 寄存器读取数据;
- 重复步骤 2 和 3 直到 FIFO 为空,检查 uart.Channel_sts_reg0 [REMPTY] = 1;
- 若中断状态位置位则清除,向 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:只写,强制禁用中断位。
- 编程触发电平,向 6 位字段 uart.Rcvr_FIFO_trigger_level0 [RTRIG] 写入;
- 使能 RTRIG 中断,设置使能位,清除禁用位,并验证掩码值: a. 设置 uart.Intrpt_en_reg0 [RTRIG] = 1; b. 清除 uart.Intrpt_dis_reg0 [RTRIG] = 0; c. 读取 uart.intrpt_mask_reg0 [RTRIG] = 1(中断使能);
- 禁用 RTRIG 中断,设置禁用位,清除使能位,并验证掩码值: a. 设置 uart.Intrpt_dis_reg0 [RTRIG] = 1; b. 清除 uart.Intrp_en_reg0 [RTRIG] = 0; c. 读取 uart.intrpt_mask_reg0 [RTRIG] = 0(中断禁用);
- 清除 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 时钟。
- 编程 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 路由,还有许多其他引脚选项。
- 配置 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 接收器;
- 配置 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
}
代码说明
- 寄存器命名 :代码中寄存器(如
uart.mode_reg0
、slcr.UART_CLK_CTRL
)及位域(如RXEN
、RTRIG
)均来自文档 19.3.6 节寄存器概述(至)。 - 波特率计算 :115200 波特率的
CD=62
、BDIV=6
参考表 19-1 中 "115200" 行(),计算公式见 19.2.3 节(至)。 - 中断处理 :中断使能 / 禁用通过
Intrpt_en_reg0
/Intrpt_dis_reg0
实现,符合文档中 "互斥设置" 要求(至)。 - 流控制:自动模式下 RTS 信号根据 RxFIFO 电平自动控制,参考 19.2.11 节(至)。
可根据实际硬件需求调整触发级别、波特率等参数,确保与外部设备匹配。