UART 16550 IP核使用详解

AXI UART 16550是Xilinx FPGA中提供的一个UART IP核,它允许通过AXI接口与UART设备进行通信。本文描述了如何使用Xilinx的Vivado Design Suite环境中的工具来定制和生成 UART 16550 IP核,以及如何配置和使用该IP核。

1 UART 16550 IP核的使用

以下是针对如何定制IP核的步骤的简要概述:

(1)打开或新建一个工程。

(2)如下图所示,找到UART 16550 IP核。

(3) 双击IP,或从工具栏或右键菜单中选择"Customize IP"命令,打开该IP核的配置页。

在AXI UART 16550 Vivado IDE中,以下是默认选项的描述:

AXI CLK Frequency (AXI时钟频率)

这是驱动AXI UART 16550外设的系统时钟频率(以MHz为单位)。

注意:当IP与IP Integrator一起使用时,此参数会自动更新。

UART Mode (UART模式)

选择UART的模式,具体是16550模式还是16450模式。这两种模式代表了不同的UART版本和功能集。通常,16550模式提供更多的功能和更好的性能。

Use External CLK for BAUD Rate (使用外部时钟计算波特率)

勾选此选项后,AXI UART 16550会使用外部时钟来计算波特率。此时,xin端口会被外部驱动。

不勾选此选项时,UART可能会使用内部的时钟分频器来生成波特率时钟。

Enable External Receiver CLK (启用外部接收器时钟)

勾选此选项后,rclk(接收器时钟)将由外部驱动。这通常用于同步接收操作,确保数据在正确的时钟边界上被采样。

(4)时钟

系统时钟(System Clock)

AXI UART 16550 IP核的异步微处理器接口是与UART的系统时钟输入同步的。这意味着UART的所有内部操作,如数据发送、接收、波特率生成等,都是基于这个系统时钟来进行的。系统时钟(通常标记为S_AXI_ACLK或类似的名称)的频率是UART操作的基础。

XIN时钟(XIN Clock)

如下图所示,在选择了Use External CLK for BAUD Rate选项时,IP核会出现Xin时钟引脚。

如果xin输入被外部驱动(即使用外部时钟源),那么这个外部时钟(XIN时钟)必须满足特定的要求。特别是,它必须小于或等于系统时钟的一半(即 xin ≤ (S_AXI_ACLK/2))。这个要求是AXI UART 16550 IP核正确运行的必要条件。

这个限制的原因是UART内部的一些操作(如波特率生成器)需要在一个时钟周期内完成特定的任务。如果XIN时钟太快(即超过系统时钟的一半),UART可能无法在一个时钟周期内完成这些任务,从而导致数据丢失或错误。

(5)复位

AXI UART 16550 IP核使用s_axi_aresetn信号进行复位操作,并且该信号是低电平有效的。

2 编程序列

以下是使用AXI UART 16550 IP核时配置为16550模式的一般步骤:

(1)指定异步数据通信交换的格式

例如:写入线控制寄存器来设置数据位(5、6、7或8)、打开奇偶校验并选择偶校验或奇校验、设置传输的停止位数。

通过编程线控制寄存器(Line Control Register)来设置除数锁存访问位(Divisor latch access bit)。

(2)激活中断

向中断使能寄存器(Interrupt Enable register)写入值,以允许特定的中断条件(如数据接收、发送缓冲区空等)生成中断。

(3)配置FIFO

写FIFO控制寄存器(FIFO Control register)以启用FIFOs、清除FIFOs和设置接收FIFO(RCVR FIFO)的触发级别。

(4)设置UART波特率

写除数锁存(Divisor Latch),首先写入最低有效字节,然后写入最高有效字节,以正确设置UART的波特率。

(5)处理中断

当AXI UART 16550触发中断时,您的软件必须读取相关的寄存器(如接收缓冲区寄存器),处理数据,并清除中断标志。

3.1 16550模式下的编程序列

设置目标:

波特率:56kbps

系统时钟:100Mhz

使能FIFO接收缓冲区FIFO

异步数据传输格式:8数据位(data bits)、偶校验(Even parity)和2停止位(stop bits)

设置流程

(1)写0x0000_0080到线控制寄存器

设置DLAB(Divisor Latch Access Bit)位为1,允许写入Divisor Latch的值。

//假设UART的LCR寄存器地址是0x<some_address> 

uint16_t lcr_value = 0x0080; // 设置DLAB位为1

write_to_register(0x<some_address> , lcr_value); // 写入线控制寄存器
(2)写Divisor Latch以配置波特率

根据计算出的分频值设置Divisor Latch的最低有效字节(LSB)和最高有效字节(MSB)。分频器的值是通过AXI时钟频率和期望的波特率计算得出的。
divisor = (AXI CLK frequency/(16 × Baud Rate))
代码实现为:

// 假设UART的 Divisor Latch LSB和MSB的地址分别是0x<lsb_address>和0x<msb_address> 
uint8_t divisor_lsb = 0x6F; // 分频器锁存器最低有效字节 
uint8_t divisor_msb = 0x00; // 分频器锁存器最高有效字节(对于56 Kbps,可能不需要这个字节,取决于UART的具体实现) 


write_to_register(0x<lsb_address>, divisor_lsb); // 写入分频器锁存器最低有效字节 
write_to_register(0x<msb_address>, divisor_msb); // 写入分频器锁存器最高有效字节(如果需要的话)
(3)写0x0000_001F到 线控制寄存器以设置数据格式
// 重新设置线控制寄存器  
uint16_t new_lcr_value = 0x001F; // 8数据位,2停止位,偶校验,DLAB=0  
write_to_register(0x<some_address>, new_lcr_value); // 写入新的线控制寄存器值
(4)启用中断
// 假设中断使能寄存器的地址是0x<ier_address> 
uint8_t ier_value = 0x11; // 启用THRE(Transmitter Holding Register Empty)和RDA(Receive Data Available)中断 
write_to_register(0x<ier_address>, ier_value); // 写入中断使能寄存器
(5)通过中断进行数据传输和接收
  • 当THRE中断触发时,意味着发送缓冲区为空,可以写入新的数据到发送保持寄存器(Transmitter Holding Register)。

  • 当RDA中断触发时,意味着接收缓冲区有新的数据可读,可以从接收缓冲区寄存器(Receiver Buffer Register)中读取数据。

    // 此代码表示如何处理中断
    void uart_isr() {
    if (is_interrupt_set(THRE_INTERRUPT)) { // 检查THRE中断是否设置
    // 清除THRE中断标志(如果需要的话)
    // 写入数据到Transmitter Holding Register
    }

      if (is_interrupt_set(RDA_INTERRUPT)) { // 检查RDA中断是否设置  
          // 清除RDA中断标志(如果需要的话)  
          // 从Receiver Buffer Register读取数据  
      }  
    
      // 其他中断处理...  
    

    }

3.2 使用外部XIN时钟时16550模式下的编程序列

设置目标:

波特率:56kbps

系统时钟:100Mhz

外部xin时钟:1.8432 MHz

使能FIFO接收缓冲区FIFO

异步数据传输格式:8数据位(data bits)、偶校验(Even parity)和2停止位(stop bits)

设置流程

(1)写0x0000_0080到线控制寄存器

设置DLAB(Divisor Latch Access Bit)位为1,允许写入Divisor Latch的值。

//假设UART的LCR寄存器地址是0x<some_address> 

uint16_t lcr_value = 0x0080; // 设置DLAB位为1

write_to_register(0x<some_address> , lcr_value); // 写入线控制寄存器
(2)写Divisor Latch以配置波特率

根据计算出的分频值设置Divisor Latch的最低有效字节(LSB)和最高有效字节(MSB)。分频器的值是通过AXI时钟频率和期望的波特率计算得出的。
divisor = (AXI CLK frequency/(16 × Baud Rate))
代码实现为:

// 假设UART的 Divisor Latch LSB和MSB的地址分别是0x<lsb_address>和0x<msb_address> 
uint8_t divisor_lsb = 0x02; // 分频器锁存器最低有效字节 
uint8_t divisor_msb = 0x00; // 分频器锁存器最高有效字节(对于56 Kbps,可能不需要这个字节,取决于UART的具体实现) 


write_to_register(0x<lsb_address>, divisor_lsb); // 写入分频器锁存器最低有效字节 
write_to_register(0x<msb_address>, divisor_msb); // 写入分频器锁存器最高有效字节(如果需要的话)
(3)写0x0000_001F到 线控制寄存器以设置数据格式
// 重新设置线控制寄存器  
uint16_t new_lcr_value = 0x001F; // 8数据位,2停止位,偶校验,DLAB=0  
write_to_register(0x<some_address>, new_lcr_value); // 写入新的线控制寄存器值
(4)启用中断
// 假设中断使能寄存器的地址是0x<ier_address> 
uint8_t ier_value = 0x11; // 启用THRE(Transmitter Holding Register Empty)和RDA(Receive Data Available)中断 
write_to_register(0x<ier_address>, ier_value); // 写入中断使能寄存器
(5)通过中断进行数据传输和接收
  • 当THRE中断触发时,意味着发送缓冲区为空,可以写入新的数据到发送保持寄存器(Transmitter Holding Register)。
  • 当RDA中断触发时,意味着接收缓冲区有新的数据可读,可以从接收缓冲区寄存器(Receiver Buffer Register)中读取数据。
相关推荐
上理考研周导师9 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战11 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩21 小时前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望1 天前
EDA技术简介
fpga开发
淘晶驰AK1 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~1 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发
檀越剑指大厂1 天前
【基于Zynq FPGA对雷龙SD NAND的测试】
fpga开发