ZYNQ-UART串口中断测试

本文介绍ZYNQ芯片的串口中断功能及其实现方法,包括UART控制器的工作原理、开发环境搭建、硬件平台配置及软件编程流程。通过实际代码示例,详细解析如何配置串口参数、初始化中断及编写中断服务函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习内容

本文主要介绍关于ZYNQ芯片的串口中断功能,并编写相关读写测试代码,完成串口中断的读写测试。

开发环境

vivado 18.3&SDK,PYNQ-Z2开发板。

UART控制器

简介

UART控制器是一个全双工异步接收和发送,支持可编程波特率和I/O信号格式。 该控制器可实现奇偶校验自动生成和多主检测模式。UART操作由配置和模式寄存器控制。

FIFO、调制解调器信号和其他控制器功能的状态是使用状态、中断状态和调制解调器状态寄存器读取的。UART控制器有独立的RX和TX数据路径。每个路径包括一个64字节的FIFO。 控制器TX和RX FIFO中的数据进行串行化和反串行化,并包括一个模式开关,以支持RXD和TXD信号的各种环回配置。(RXD和TXD使用模式:正常模式、各种环回诊断测试模式)

FIFO中断状态位支持轮询或中断驱动的处理程序。 软件使用RX和TX数据端口寄存器读取和写入数据字节。当在类似于调制解调器的应用程序中使用UART时,调制解调器控制模块检测并生成调制解调器握手信号,并且还根据握手协议控制接收和发送器路径。(调制解调器控制信号:CTS, RTS, DSR, DTR, RI和DCD只有在EMIO接口可用

系统框图

UART控制器的系统框图如下图所示:

在这里插入图片描述
在图中,SLCR寄存器(系统级控制寄存器(SLCR)由用于控制PS行为的各种寄存器组成。这些寄存器可以通过中央互连使用加载和存储指令访问。)包括控制位用于UART时钟,复位和MIO-EMIO信号映射。软件可以使用APB 32位的从接口访问UART控制器寄存器。每个控制器的IRQ(中断号为59,82)连接到PS中断控制器,并连接到PL。UART控制器由参考时钟( UART REF_CLK)驱动,同时控制器也需要连接APB 总线时钟( CPU_1x clock), UART REF_CLK 和 CPU_1x clock 都是来自于 PS 时钟子系统。

内部框图

UART控制器内部框图如下图所示。
在这里插入图片描述
由上图可知,UART控制器使用PS AXI interconnect 进行数据交互,通过APB Slave接口来接收PS端口的配置信息和一些数据信息。假设要发送数据,则系统先将发生的字符串缓存到TxFIFO下,然后经Transmitter模块实现并转串,如果工作在正常模式下,则数据之间接到MIO/EMIO引脚上,正常向接收设备发送;假设要接收其他设备传来的串口信息,则首先通过串口接收引脚接收串行数据,然后经过receiver模块实现串转并,转换过后存入到RxFIFO下,经过APB从接口传输到PS端,即可对接收数据进行处理。

通过控制状态寄存器可以对UART控制器进行控制,而这些引脚只能连接到EMIO。UART控制器内部包括一个中断模块,所以可以和其他模块一样正常接收到来自系统的中断信号。对于UART的参考时钟在控制器内部首先进行了一个八分频,接着再产生波特率时钟。

Transmit FIFO

Transmit FIFO (Tx FIFO)存储由APB从接口写入的数据,发送模块收到FIFO中的数据后删除FIFO的数据然后进行串并转换,并装入其移位寄存器。TxFIFO的最大数据宽度为8位。数据通过写入TxFIFO寄存器加载到TxFIFO。

当数据加载到TxFIFO时,TxFIFO空标志将被清除并保持在这个Low状态,直到TxFIFO中的最后一个字符被删除并加载到发送器移位寄存器中。TxFIFO满中断状态(TFULL)表明TxFIFO已经完全写满了,并且阻止数据被写入到TxFIFO中。如果对TxFIFO执行另一个APB写入操作,则触发溢出,写入数据不会加载到TxFIFO中。

发送 FIFO接近满标志(TNFULL)表明在FIFO中没有足够的空间来进行一次程序大小的写入,这是由模式寄存器的WSIZE位控制的。TxFIFO接近满标志(TNFULL)表示TxFIFO中只有字节空闲。

可以在TxFIFO填充级别上设置一个阈值触发器(TTRIG)。发射器触发寄存器可以用来设置这个值,这样当TxFIFO填充深度达到设定的阈值时触发可以设置。

Receiver FIFO

Receiver FIFO和Transmit FIFO类似。RxFIFO存储由接收器串行移位寄存器接收的数据。RxFIFO的最大数据宽度是8位。当数据加载到RxFIFO时,RxFIFO空标志被清除,并且这种状态保持为低,直到RxFIFO中的所有数据通过APB接口传输完毕。空标志重新置位为高,如果接着读FIFO的话,则会从空的RxFIFO读取返回0。

RxFIFO满状态(Chnl_int_sts_reg0 [RFUL]和Channel_sts_reg0 [RFUL]位)表明RxFIFO满了,阻止数据被加载到RxFIFO。同时也可以在RxFIFO上设置一个阈值触发器(RTRIG)。接收器触发级别寄存器(Rcvr_FIFO_trigger_level0)可以用来设置这个值,取值范围是1 ~ 63。

I / O模式切换

这里的模式切换即为内部框图中的 Mode Switch 模块,如下图所示。
在这里插入图片描述
该模式由mode_reg0 [CHMODE]寄存器设置控制,总共分为四种模式,分别
为:正常模式( Normal Mode)、自动回音模式( Automatic Echo Mode)、本地环回模式( Local Loopback Mode)和远程环回模式( Remote Loopback Mode)。
在这里插入图片描述
正常模式( Normal Mode) :用于标准UART操作,就是发送接收功能。

自动回音模式( Automatic Echo Mode) :Automatic Echo Mode模式在RxD上接收数据,模式开关将数据连接到接收端和UARTx_TxD。而PS的TXD端口的数据无法正常发出。

本地环回模式( Local Loopback Mode) :本地环回模式不连接到RxD或TxD引脚,而是直接把PS发送的数据传输到PS的接收端。

远程环回模式( Remote Loopback Mode) :远程环回模式将RxD信号连接到TxD信号。在这种模式下,控制器不能在TxD上发送任何内容,也不能在RxD上接收任何内容。

UART启动顺序

UART 的启动顺序如下:

  1. 复位UART控制器,在PS进行系统复位时进行控制器的复位。
  2. 配置 IO 引脚信号。
  3. 配置 UART 参考时钟(可以保护默认)。
  4. 配置控制器功能( UART 控制器初始化)。
  5. 配置中断,通过中断来管理 RxFIFO 和 TxFIFO。
  6. 配置串口模式控制(可选)。
  7. 管理发送和接收的数据,采用轮询或中断驱动处理两种方式。

配置控制器功能步骤

在UART控制器中,控制器可以配置字符帧、波特率、FIFO触发级别、Rx超时机制,并使能控制器。所有步骤都必须在复位之后。
配置控制器的功能步骤如下:

  1. 配置 UART 数据帧格式。 数据位长度、停止位、校验方式、 IO 模式等。
  2. 设置波特率。
  3. 设置 RxFIFO 触发器等级,可以选择启用或禁用该功能。
  4. 使能 UART 控制器。
  5. 配置接收器的超时机制,可以选择启用或禁用该功能。

发送数据步骤

编写软件程序时,可以通过使用轮训和中断的方式控制RxFIFO和TxFIFO中的数据流。

使用轮询方式发送数据顺序

  1. 检查TxFIFO是否为空。直到uart.Channel sts rego[TEMPTY] =1,执行后续步骤。
  2. 用数据填充TxFIFO。向uart.TX_RX_FIFO0寄存器写入64字节的数据。
  3. 向TxFIFO写入数据。有两种方法:方法一: 可以等待 TxFIFO 为空之后再写入 64 个字节,即执行第 2 步;方法一: 可以检测 TxFIFO 是否写满,即不停的读取 TFUL 标志和写单个字节的数据。

使用中断方法发送数据的顺序

  1. 禁用 TxFIFO 空状态中断。
  2. 写入数据到TxFIFO中。
  3. 检测TxFIFO是否还有足够的空间容纳数据。
  4. 重复2和3操作。
  5. 使能中断。
  6. 等待TxFIFO为空,然后从步骤 1 重新开始。

接收数据步骤

使用轮询方式发送数据顺序

  1. 等待RxFIFO被填满到触发器级别。
  2. 从RxFIFO读取数据。
  3. 重复步骤2,直到FIFO为空。
  4. 设置Rx超时中断状态位时清除。

使用中断方法发送数据顺序

  1. 使能中断。
  2. 等待RxFIFO被填满到触发级别或Rx超时。
  3. 从RxFIFO读取数据。
  4. 重复步骤2和3,直到FIFO为空。
  5. 如果设置了中断状态位,则清除中断状态位。

系统框图

这里仅仅使用了UART部分,所以可以利用前文的helloworld工程,不需要进行特殊的配置。通过串口的中断功能把发送的数据再接收到PS端进行一个回环显示。
在这里插入图片描述

硬件平台搭建

新建工程,创建 block design。添加ZYNQ7 ip,根据本次工程需要对IP进行配置。勾选本次工程使用的uart资源
在这里插入图片描述

将ZYNQ无用资源进行取消勾选:
在这里插入图片描述
在这里插入图片描述
硬件系统构建完成如下:
在这里插入图片描述
然后我们进行generate output product 然后生成HDL封装。这里只用到了UART,是MIO引脚,所以不需要进行管脚分配。点击导出硬件资源(可以不包含bit流文件,因为只用到了PS资源),接着launch SDK。

SDK软件部分

打开SDK后,新建application project。
在system.mss中可以打开相关参考文档辅助设计。
在这里插入图片描述
这里使用串口中断可以参考赛灵思提供的例程代码进行修改设计:
在这里插入图片描述
这里导入uart_intr_example例程模板在main.c中输入以下代码:

#include "xparameters.h"
#include "stdio.h"
#include "xuartps.h"
#include "xuartps_hw.h"
#include "xscugic.h"
#define UART_0_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID
#define INTR_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
#define UART_INT_IRQ_ID		XPAR_XUARTPS_0_INTR
XUartPs Uart_Inst;
XScuGic ScuGic_Inst;
int uart_init();
void intr_init(XScuGic *intr, XUartPs *uart);
void UartIntr_Handler(void *call_back_ref);
int main(){

	//uart初试化函数
	uart_init();
	xil_printf("intr\n");
	//中断初始化
	intr_init(&ScuGic_Inst,&Uart_Inst);
	while(1);
	return 0;
}

//uart初始化
int uart_init(){
	XUartPs_Config *UartPs_Cfg;
	int Status;
	//查找配置信息
	UartPs_Cfg= XUartPs_LookupConfig(UART_0_DEVICE_ID);
	//对uart控制器进行初始化
	XUartPs_CfgInitialize(&Uart_Inst, UartPs_Cfg, UartPs_Cfg->BaseAddress);
	//检测硬件搭建是否正确
	Status = XUartPs_SelfTest(&Uart_Inst);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	//设置波特率
	XUartPs_SetBaudRate(&Uart_Inst,115200);
	//设置RXFIFO触发阈值
	XUartPs_SetFifoThreshold(&Uart_Inst,1);
	//设置操作模式
	XUartPs_SetOperMode(&Uart_Inst, XUARTPS_OPER_MODE_NORMAL);

	return XST_SUCCESS;
}

//中断初始化
void intr_init(XScuGic *intr, XUartPs *uart){
	XScuGic_Config *IntcConfig;
	//中断控制器初始化
	IntcConfig = XScuGic_LookupConfig(INTR_DEVICE_ID);
	XScuGic_CfgInitialize(intr,IntcConfig,IntcConfig->CpuBaseAddress);
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
					(Xil_ExceptionHandler) XScuGic_InterruptHandler,
					(void *)intr);
	Xil_ExceptionEnable();
	//为中断设置中断处理函数
	XScuGic_Connect(intr, UART_INT_IRQ_ID,
					  (Xil_ExceptionHandler) UartIntr_Handler,
					  (void *) uart);
	//设置触发类型
	XUartPs_SetInterruptMask(uart, XUARTPS_IXR_RXOVR);
	//使能中断
	XScuGic_Enable(intr, UART_INT_IRQ_ID);

}
//中断处理函数
void UartIntr_Handler(void *call_back_ref){
	XUartPs *uartinst =(XUartPs *)call_back_ref;
	u32 read_data = 0;
	u32 intr_status;
	//读取中断ID寄存器
	intr_status = XUartPs_ReadReg(uartinst->Config.BaseAddress,
			XUARTPS_IMR_OFFSET);//读取掩码
	intr_status &= XUartPs_ReadReg(uartinst->Config.BaseAddress,
			XUARTPS_ISR_OFFSET);//读取状态
	if(intr_status & (u32)XUARTPS_IXR_RXOVR){
		read_data = XUartPs_RecvByte(XPAR_PS7_UART_0_BASEADDR);//接收发送的字节
		XUartPs_WriteReg(uartinst->Config.BaseAddress,XUARTPS_ISR_OFFSET,
				XUARTPS_IXR_RXOVR);//清除中断状态
	}
	//设置发送
	XUartPs_SendByte(XPAR_PS7_UART_0_BASEADDR,read_data);
}

部分代码讲解

在整体的代码设计中,代码思路如下:

  1. 初始化UART控制器
  2. 初始化UART中断
  3. 编写中断服务函数

对于初始化UART部分,在#include "xuartps.h" 头文件中可以找到很多配置的函数,调用即可对uart的波特率,中断触发阈值等参数进行设置。
对于中断的配置可以类比GPIO的中断配置函数,先在初始化SGIC,然后进行异常初始化,完成注册异常并使能,接着需要连接SGIC和UART,最后设置中断类型并使能完成中断整体操作配置。
在中断服务函数中,实现的功能为回环读写,所以要在中断函数中进行检测中断类型,当进入相应的中断时进行数据的读取,读取到上位机的发送数据,然后清除中断标志,最后把读到的数据进行发送。

Reference

  1. 正点原子视频教程
  2. UG585
### Zynq 平台中的 UART 配置与使用 Zynq-7000 All Programmable SoC 是一种集成 ARM Cortex-A9 处理器和可编程逻辑的器件,广泛应用于嵌入式系统设计中。UART(Universal Asynchronous Receiver/Transmitter)是一种常见的串行通信接口,在 Zynq 中可以通过硬件模块实现其功能。 #### 硬件配置 在 Vivado 或 Xilinx SDK 工具链中,可以利用 PS(Processing System)部分的 UART 控制器来完成基本的串口通信设置。PS 的 UART 功能默认支持多种波特率以及标准的数据位、停止位和校验模式的选择[^1]。具体配置过程如下: - **创建 Block Design**: 在 Vivado 中新建一个项目并添加 Zynq Processing System (PS) 模块。 - **启用 UART 接口**: 打开 PS 配置界面,进入 `Peripheral I/O Pins` 页面,找到 UART 相关选项并将它们映射到外部引脚上。 - **分配引脚位置**: 使用工具自动或手动指定 TX 和 RX 引脚的位置以便于后续连接物理设备测试电路板上的信号传输情况。 #### 软件初始化 对于软件层面的操作,则主要依赖 Linux 驱动程序或者裸机应用程序来进行详细的参数设定工作。如果是在运行操作系统环境下的开发流程里,通常不需要过多关注底层细节因为已经有现成可用的服务函数可供调用;而对于无 OS 场景则需自行编写驱动代码管理寄存器读写动作等操作行为。 以下是基于纯 C 语言的一个简单例子展示如何打开端口、设置波特率为 115200bps 及其他必要属性之后发送字符串消息给另一方接收终端显示出来: ```c #include <stdio.h> #include "xparameters.h" #include "xuartps.h" #define UART_BASEADDR XPAR_XUARTPS_0_BASEADDR int main(){ int Status; XUartPs Uart; /* Initialize the UART driver */ Status = XUartPs_CfgInitialize(&Uart,(XUartPs_Config *)XPAR_XUARTPS_0_DEVICE_ID,UART_BASEADDR); if(Status != XST_SUCCESS){ return XST_FAILURE; } /* Set Baud Rate to 115200 bps*/ XUartPs_SetBaudRate(&Uart,115200); /* Send String Over UART */ char *msg="Hello World!\n\r"; XUartPs_Send(&Uart,msg,strlen(msg)); while(XUartPs_IsTransmitFull(&Uart)); // Wait until all bytes are sent return 0; } ``` 上述片段展示了通过调用特定 API 函数完成整个初始化过程,并最终实现了向目标发出固定文本的功能演示效果[^2]。 #### 注意事项 当实际部署解决方案时还需要考虑更多方面因素比如错误处理机制的设计思路规划等问题都需要提前做好充分准备才能确保整体系统的稳定性和可靠性达到预期水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA and ICer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值