【ZYNQ】ZYNQ7000 UART 控制器及驱动应用示例

article/2025/11/8 10:15:34

UART 简介

我们在使用 PS 的时候,通常会添加 UART 控制器,用于打印信息和调试代码。除此之外,PS 在和外部设备通信时,也会经常使用串口进行通信。

UART 控制器

UART 控制器是一个全双工异步收发控制器,ZYNQ 内部包含两个 UART 控制器,UART0 和 UART1。每一个 UART 控制器支持可编程的波特率发生器、64 字节的接收 FIFO 和发送 FIFO、产生中断、RXD 和 TXD 信号的环回模式设置以及可配置的数据位长度、停止位和校验方式等。
UART 控制器系统框图如图所示:

在这里插入图片描述

由上图可知,UART 控制器和 IO 端口由参考时钟(UART REF_CLK)驱动,同时控制器也需要连接 APB 总线时钟(CPU_1x clock),UART REF_CLK 和 CPU_1x clock 都是来自于 PS 时钟子系统。UART 控制器的配置以及状态的获取由控制(Control)和状态寄存器(Status Registers)完成。

另外,UART 控制器不仅可以连接至 MIO,也可以映射到 EMIO,从而使用 PL 的端口来实现串口通信的功能。当 UART 控制器连接到 MIO 时,只有 Tx(发送)和 Rx(接收)两个引脚;而当连接 EMIO 时,除 Tx 和 Rx 引脚外,可选的还有 CTSN、DSDN、DSRN 等引脚,这些引脚用于串口的流控制,即调制解调器的数据通讯中。

UART 控制器采用独立的接收和发送数据路径,每个路径包含一个 64 字节的 FIFO,控制器对发送和接收 FIFO 中的数据进行串并转换操作。FIFO 的中断标志支持轮询处理或中断驱动处理两种方式。另外,控制器中还有一个模式开关,支持 RXD 和 TXD 信号的各种环回配置。UART 控制器内部框图如下图所示:

在这里插入图片描述

UART 控制器的寄存器通过 APB 从机接口和 PS AXI 总线互联,控制器的寄存器用于对 UART 控制器进行配置和获取状态。波特率发生器(Baud Rate Generator)为 UART 控制器的接收端和发送端提供位周期时钟;中断控制器(GIC)为串口的收发提供了中断服务的功能。

APB 总线接口通过向 TxFIFO 寄存器写值,将数据加载到 TxFIFO 存储器中。当数据加载至 TxFIFO 后,TxFIFO 的空标志变成无效的状态,直到最后一个数据从 TxFIFO 中移出,加载至传输移位寄存器,TxFIFO 恢复空的标志位。同时 TxFIFO 使用 TFULL(满中断状态)用于表示当前 TxFIFO 已经写满,并且会阻止数据继续写入。如果此时继续执行写操作,那么会触发溢出,数据不会加载到 TxFIFO 中。RxFIFO 存储器接收来自接收移位寄存器的数据,当接收完数据后,RxFIFO 空标志信号同样变成无效的状态,直到所有的数据通过 APB 总线发送出去。RxFIFO 的满标志状态用于表示 RxFIFO 已经写满,并且会阻止更多的数据写入。

Mode Switch

模式切换(Mode Switch)控制器控制 RxD 和 TxD 的信号连接方式,总共分为四种模式,分别为:正常模式(Normal Mode)、自动回音模式(Automatic Echo Mode)、本地环回模式(Local Loopback Mode)和远程环回模式(Remote Loopback Mode)。模式切换的功能示意图如所示:

在这里插入图片描述

从上图中可以清晰的看出 UART 不同模式下所实现的功能。在实际应用中,最常用的就是 UART 的正常模式。

  • 正常模式是标准的 UART 操作模式;
  • 自动回音模式下,RxD 连接至 TxD,控制器可以接收数据,但是不能发送数据;
  • 本地环回模式没有连接 RxD 和 TxD 的引脚,用于本地程序的环回测试;
  • 远程环回模式下,RxD 连接至 TxD,但是并没有和控制器连接,因此控制器在此模式下无法发送数据和接收数据。

UART 寄存器

UART 寄存器概述如下表所示。

在这里插入图片描述

UART 驱动示例

  • uart.c
/*** Copyright (c) 2022-2023,HelloAlpha* * Change Logs:* Date           Author       Notes*/
#include "uart.h"/*** @brief 串口初始化* * @param UartInstancePtr 串口实例* @param UartFormat 串口通信格式* @param UartDeviceId 串口 ID 号* @return int */
int UartInit(XUartPs* UartInstancePtr, XUartPsFormat* UartFormat, uint16_t UartDeviceId)
{int Status;XUartPs_Config *UartConfigPtr;UartConfigPtr = XUartPs_LookupConfig(UartDeviceId);if (NULL == UartConfigPtr) {return XST_FAILURE;}Status = XUartPs_CfgInitialize(UartInstancePtr, UartConfigPtr, UartConfigPtr->BaseAddress);if (Status != XST_SUCCESS) {return XST_FAILURE;}Status = XUartPs_SelfTest(UartInstancePtr);if (Status != XST_SUCCESS) {return XST_FAILURE;}/* Set UART mode Baud Rate 115200, 8bits, no parity, 1 stop bit */XUartPs_SetDataFormat(UartInstancePtr, UartFormat) ;/* Set the UART in Normal Mode */XUartPs_SetOperMode(UartInstancePtr, XUARTPS_OPER_MODE_NORMAL);return Status;
}/*** @brief 串口中断初始化* * @param IntcInstancePtr 中断实例* @param UartInstancePtr 串口中断实例* @param UartIntrId 串口中断 ID 号* @param CallBack 中断服务函数* @return int */
int UartIntrInit(XScuGic *IntcInstancePtr,	XUartPs *UartInstancePtr, uint32_t UartIntrId, void(* CallBack)(void *))
{int Status;XScuGic_Config *IntcConfig;IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);if (NULL == IntcConfig) {return XST_FAILURE;}Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS) {return XST_FAILURE;}Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler,IntcInstancePtr);Xil_ExceptionEnable();Status = XScuGic_Connect(IntcInstancePtr, UartIntrId,(Xil_ExceptionHandler) CallBack,(void *) UartInstancePtr);if (Status != XST_SUCCESS) {return XST_FAILURE;}/* Set the receiver timeout.*/XUartPs_SetRecvTimeout(UartInstancePtr, 8);/*Set receiver FIFO interrupt trigger level, here set to 1*/XUartPs_SetFifoThreshold(UartInstancePtr, 1);/* 设置中断触发类型 */XUartPs_SetInterruptMask(UartInstancePtr, XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXEMPTY | XUARTPS_IXR_TOUT);XScuGic_Enable(IntcInstancePtr, UartIntrId);return Status ;
}/*** @brief 串口数据发送函数* * @param InstancePtr 串口实例* @param BufferPtr 发送缓冲区指针* @param NumBytes 要发送的字节数* @return int 成功发送的字节数*/
int UartPsSend(XUartPs *InstancePtr, uint8_t *BufferPtr, uint32_t NumBytes)
{uint32_t SentCount = 0U;/* Setup the buffer parameters */InstancePtr->SendBuffer.RequestedBytes = NumBytes;InstancePtr->SendBuffer.RemainingBytes = NumBytes;InstancePtr->SendBuffer.NextBytePtr = BufferPtr;while (InstancePtr->SendBuffer.RemainingBytes > SentCount){/* Fill the FIFO from the buffer */if (!XUartPs_IsTransmitFull(InstancePtr->Config.BaseAddress)){XUartPs_WriteReg(InstancePtr->Config.BaseAddress,XUARTPS_FIFO_OFFSET,((uint32_t)InstancePtr->SendBuffer.NextBytePtr[SentCount]));/* Increment the send count. */SentCount++;}}/* Update the buffer to reflect the bytes that were sent from it */InstancePtr->SendBuffer.NextBytePtr += SentCount;InstancePtr->SendBuffer.RemainingBytes -= SentCount;return SentCount;
}/*** @brief 串口数据接收函数* * @param InstancePtr 串口实例* @param BufferPtr 接收缓冲区指针* @param NumBytes 要读取的字节数* @return int 成功读取的字节数*/
int UartPsRev(XUartPs *InstancePtr, uint8_t *BufferPtr, uint32_t NumBytes)
{uint32_t ReceivedCount = 0;uint32_t CsrRegister;/* Setup the buffer parameters */InstancePtr->ReceiveBuffer.RequestedBytes = NumBytes;InstancePtr->ReceiveBuffer.RemainingBytes = NumBytes;InstancePtr->ReceiveBuffer.NextBytePtr = BufferPtr;/** Read the Channel Status Register to determine if there is any data in* the RX FIFO*/CsrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,XUARTPS_SR_OFFSET);/** Loop until there is no more data in RX FIFO or the specified* number of bytes has been received*/while((ReceivedCount < InstancePtr->ReceiveBuffer.RemainingBytes)&&(((CsrRegister & XUARTPS_SR_RXEMPTY) == (u32)0))){InstancePtr->ReceiveBuffer.NextBytePtr[ReceivedCount] =XUartPs_ReadReg(InstancePtr->Config.BaseAddress, XUARTPS_FIFO_OFFSET);ReceivedCount++;CsrRegister = XUartPs_ReadReg(InstancePtr->Config.BaseAddress,XUARTPS_SR_OFFSET);}InstancePtr->is_rxbs_error = 0;/** Update the receive buffer to reflect the number of bytes just* received*/if(NULL != InstancePtr->ReceiveBuffer.NextBytePtr){InstancePtr->ReceiveBuffer.NextBytePtr += ReceivedCount;}InstancePtr->ReceiveBuffer.RemainingBytes -= ReceivedCount;return ReceivedCount;
}/*** @brief 串口波特率更改* * @param UartDeviceId 串口 ID 号* @param Baudrate 要设置的波特率* @return int */
int UartSetBaudRate(uint16_t UartDeviceId , uint32_t Baudrate)
{static XUartPs Uart;XUartPs_Config *UartConfigPtr;UartConfigPtr = XUartPs_LookupConfig(UartDeviceId);if (NULL == UartConfigPtr) {return XST_FAILURE;}XUartPs_CfgInitialize(&Uart, UartConfigPtr, UartConfigPtr->BaseAddress);XUartPs_SetBaudRate(&Uart, Baudrate);return XST_FAILURE;
}
  • uart.h
/*** Copyright (c) 2022-2023,HelloAlpha* * Change Logs:* Date           Author       Notes*/
#ifndef __UART_H__
#define __UART_H__#include "xuartps.h"
#include "xscugic.h"#ifndef INTC_DEVICE_ID
#define INTC_DEVICE_ID      XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif#define UART0_DEVICE_ID     XPAR_XUARTPS_0_DEVICE_ID
#define UART1_DEVICE_ID     XPAR_XUARTPS_1_DEVICE_ID
#define UART0_IRPT_INTR     XPAR_XUARTPS_0_INTR
#define UART1_IRPT_INTR     XPAR_XUARTPS_1_INTR/** Function declaration*/
int UartInit(XUartPs* UartInstancePtr, XUartPsFormat* UartFormat, uint16_t UartDeviceId);
int UartIntrInit(XScuGic *IntcInstancePtr,	XUartPs *UartInstancePtr, uint32_t UartIntrId, void(* CallBack)(void *));
int UartPsSend(XUartPs *InstancePtr, uint8_t *BufferPtr, uint32_t NumBytes) ;
int UartPsRev (XUartPs *InstancePtr, uint8_t *BufferPtr, uint32_t NumBytes) ;
int UartSetBaudRate(uint16_t UartDeviceId , uint32_t Baudrate);#endif

UART 应用示例

  • 初始化串口一

  • app_uart.c

/*** Copyright (c) 2022-2023,HelloAlpha* * Change Logs:* Date           Author       Notes*/
#include "app_uart.h"#define UART0_BAUDRATE   115200Uextern XScuGic IntcInstPtr;static XUartPsFormat _Uart0Format = {UART0_BAUDRATE, 8, 0, 1};/*** @brief Interrupt handling functions*  * @param CallBackRef is a pointer to an upper-level callback reference*/
static void Uart0Handler(void *CallBackRef)
{XUartPs *UartInstancePtr = (XUartPs *) CallBackRef;struct uart_msg *_uart0_msg = &g_uart0_msg;static uint32_t ReceivedCount = 0;static uint32_t UartSrValue = 0;_uart0_msg->ReceivedFlag = 0 ;/* Read interrupt status and enable bits */UartSrValue = XUartPs_ReadReg(UartInstancePtr->Config.BaseAddress, XUARTPS_IMR_OFFSET);UartSrValue &= XUartPs_ReadReg(UartInstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET);/* check if receiver FIFO trigger */if (UartSrValue & XUARTPS_IXR_RXOVR){ReceivedCount = UartPsRev(UartInstancePtr, _uart0_msg->ReceivedBufferPtr, UART_MSG_MAX_LEN);_uart0_msg->ReceivedByteNum += ReceivedCount;_uart0_msg->ReceivedBufferPtr += ReceivedCount;}/* check if receiver FIFO empty */if (UartSrValue & XUARTPS_IXR_RXEMPTY){/* do nothing */}/* check if it is a timeout interrupt */if (UartSrValue & XUARTPS_IXR_TOUT){_uart0_msg->ReceivedFlag = 1;}/* clear trigger interrupt */XUartPs_WriteReg(UartInstancePtr->Config.BaseAddress, XUARTPS_ISR_OFFSET, UartSrValue);
}int app_uart_init(void)
{int Status;XUartPs *_Uart0_Ps = &Uart0_Ps;/* init UART */Status = UartInit(&Uart0_Ps, &_Uart0Format, UART0_DEVICE_ID);if (Status != XST_SUCCESS) {return XST_FAILURE;}/* init UART interrupt */Status = UartIntrInit(&IntcInstPtr, &Uart0_Ps, UART0_IRPT_INTR, Uart0Handler);if (Status != XST_SUCCESS) {return XST_FAILURE;}/* clear trigger interrupt */XUartPs_WriteReg(_Uart0_Ps->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_MASK);return XST_SUCCESS;
}
  • app_uart.h
/*** Copyright (c) 2022-2023,HelloAlpha* * Change Logs:* Date           Author       Notes*/
#ifndef __APP_UART_H__
#define __APP_UART_H__#include "uart.h"/* maximum receiver length */
#define UART_MSG_MAX_LEN    100struct uart_msg 
{uint8_t ReceivedBuffer[UART_MSG_MAX_LEN];uint8_t *ReceivedBufferPtr;uint32_t ReceivedByteNum;char ReceivedFlag;uint8_t SendBuffer[UART_MSG_MAX_LEN];uint8_t *SendBufferPtr;uint32_t SendByteNum;
};typedef struct uart_msg uart_msg_t;XUartPs Uart0_Ps;uart_msg_t g_uart0_msg;int app_uart_init(void);
int uart_msg_print(void);
int uart_lookback_test(void);
int uart_report(uint8_t dev, uint8_t err);#endif

测试平台:黑金 AX7Z035

芯片型号:XC7Z035-2FFG676

参考来源:UG585


http://chatgpt.dhexx.cn/article/x9Da08M6.shtml

相关文章

Xilinx ZYNQ 7000入门

ZYNQ是Xilinx推出的新一代全可编程片上系统&#xff0c;将处理器的软件可编程性与FPGA的硬件可编程性完美整合。 ZYNQ7020&#xff1a;xc7z020clg400-2 ZYNQ7010&#xff1a;xc7z010clg400-1 组合了一个双核ARM Cortex-A9&#xff08;PS&#xff09;处理器和一个传统的…

ZYNQ7000平台介绍

基于ZYNQ7000平台软件开发 ZYNQ7000平台简介 本文介绍ZYNQ7000平台采用Avnet推出的ZedBoard开发板进行讲解&#xff0c;ZedBoard开发板基于Xilinx Zynq-7000 All Programmable Soc&#xff0c;整合了双核Cortex-A9的PS处理单元和PL逻辑单元。 在zynq上&#xff0c;ARM Cortex…

【ZYNQ】ZYNQ7000 全局定时器及其驱动示例

定时器简介 在 ZYNQ 嵌入式系统中&#xff0c;定时器的资源是非常丰富的&#xff0c;每个 Cortex-A9 处理器都有各自独立的 32 位私有定时器和 32 位看门狗定时器&#xff0c;这两个 CPU 同时共享一个 64 位的全局定时器&#xff08;GT&#xff09;。 系统框图 全局定时器&am…

Xilinx ZYNQ 7000学习笔记一(复位和启动)

一、复位系统 参考文献&#xff1a;Zynq-7000 SoC Technical Reference Manual (UG585)-ch26 Reset System zynq7000复位信号源包括硬件复位、看门狗定时器、JTAG控制器复位信号和软件复位信号。其中&#xff0c;硬件复位引脚由上电复位信号PS_POR_B和系统复位信号PS_SRST_B驱…

zynq7000系列芯片介绍

ZYNQ从架构上可以划分为两大模块&#xff0c;一个是PS&#xff08;处理器系统&#xff09;&#xff0c;另一个是PL&#xff08;可编程逻辑&#xff09; PS由APU、内存接口、IO外设、互连线4大模块组成。 1、APU&#xff08;Application Processor Unit)应用处理单元 即PS【可编…

xilinx zynq-7000 基本知识

Zynq-7000 采用可扩展式处理平台架构&#xff08;Extensible Processing Platform、EPP&#xff09;&#xff0c;是 Xilinx 用 28nm HKMG工艺制成的低功耗&#xff0c;高性能&#xff0c;高扩展性的新型芯片&#xff0c;这款新品里面集成了ARM CORTEX-A9 MPSOC 硬核以及相应的S…

ZYNQ-7000概述

摘要 Xilinx推出的ZYNQ-7000被称为全可编程片上系统&#xff08;SOC&#xff09;&#xff0c;它由FPGA与ARM组合构成&#xff0c;硬件可编程&#xff0c;软件也可编程&#xff0c;在众多应用场合有一定优势。本文根据Xilinx官网的介绍并结合ZYNQ-7000的多份数据手册总结了此产品…

ZYNQ学习笔记(一)---初识ZYNQ-7000系列

前几日刚入手一款ZYNQ-7000系列的板卡&#xff0c;之前我也没用过FPGA&#xff0c;直接跨越到ZYNQ的原因主要是某宝上这款板卡相较于其他片上仅有一块FPGA的板卡性价比更高。作为入门&#xff0c;在学习过程中&#xff0c;笔者选择先单独学习ZYNQ上的FPGA部分&#xff0c;也就是…

ZYNQ7000 Vivado详细教学步骤

ZYNQ7000 Vivado开发 ZYNQ7000 Vivado详细教学步骤 ZYNQ7000 Vivado开发1.建立工程项目2.创建Block Design3.配置IO BANK4.配置DDR和CLOCK5.配置PS外设6.测试PS外设7.增加PL外设 1.建立工程项目 Xilinx提供了一系列开发工具&#xff0c;其中包括Vivado平台工具&#xff0c;它是…

mongodb客户端 robo 3T 查询突破50行限制

robo 3T的小bug 这个mongodb客户端&#xff0c;每次查询数据只有50行&#xff0c;虽然有向下翻页的功能 但实际上点击后会被重置&#xff0c;还是只有前50条 解决办法 DBQuery.shellBatchSize 500; 当前窗口最大查询数量修改到500&#xff08;只有当前窗口生效&#xff09;…

centos7仅安装mysql/mongodb客户端

1、仅安装MySQL客户端 # 添加rpm源 [rootk8s-master ~]# rpm -ivh https://repo.mysql.com//mysql57-community-release-el7-11.noarch.rpm [roottest1 ~]# # 通过yum搜索 [roottest1 ~]# yum search mysql-community [roottest1 ~]# # 安装x64位的 mysql客户端 [roottest1 ~]…

专业级MongoDB桌面客户端:MongoBooster for Mac

mongobooster mac破解版是适用于MongoDB的最智能IDE,也是以shell为中心的跨平台GUI工具,它提供了流畅的查询构建器,SQL查询SQL查询,就地更新,ES2017语法支持和真正的智能感知体验。MongoBooster下载可以帮助用户能够连接到选项卡式用户界面中的多个数据库,并通过shell命令…

mongodb官方客户端可视化工具Compass,免费,官方值得信赖

之前一直用的客户端是nosqlbooster4mongo&#xff0c;基本操作还都是挺好用的&#xff0c;但是有一些命令在这个客户端上运行不了&#xff0c;以后要慢慢的替换到compass上。 下载compass 官方下载&#xff1a;https://downloads.mongodb.com/compass/mongodb-compass-1.26.1…

Centos下mongodb的安装

方法一 可以使用yum命令直接安装MongoDB服务端和客户端。 sudo yum install mongodb-server # 安装MongoDB服务端 sudo yum install mongodb # 安装MongoDB客户端 sudo mongod -f /etc/mongod.conf # 加载配置项&#xff0c;启动mongodb服务器 mongo #启动客户端方法…

linux下MongoDB客户端shell基本操作

MongoDB 是一款NoSql数据库&#xff0c;没有固定的模式&#xff0c;即同一个集合中的不同文档结构可以不同&#xff0c;如&#xff1a;第一条记录{name:”xiaoming”}&#xff0c;第二条记录&#xff1a;{name:”xiaoli”,age:15}&#xff0c;这在关系型数据库中是无法实现的。…

MongoDB 客户端 MongoVue

直接上图片&#xff0c;图片是按顺序来的 软件下载地址&#xff08;Windows下的MongoDB客户端MongoVUE 这是最后一个全功能的不收费的版本&#xff09;: http://pan.baidu.com/s/1skYIEq5

mongoDB介绍与客户端认证权限

mongoDB简介 Mongo 是 humongous 的中间部分&#xff0c;在英文里是“巨大无比”的意思。所以 MongoDB 可以翻译成“巨大无比的数据库”&#xff0c;更优雅的叫法是“海量数据库”。 Mongodb是一款非关系型数据库&#xff0c;说到非关系型数据库&#xff0c;区别于关系型数据库…

MongoDB客户端Robo 3T安装使用

MongoDB客户端Robo 3T安装使用 MongoDB安装 MacBook解压安装MongoDB Linux解压安装MongoDB Robo 3T下载和安装 官网下载Robo 3T 官网下载地址&#xff1a; https://robomongo.org/download 有解压版本和安装版本 下载成功后,点击安装,这里不多做说明 Robo 3T使用 打开Ro…

linux/centos单独安装mysql、mongodb客户端

安装mysql客户端 下载想要版本mysql客户端 带client https://downloads.mysql.com/archives/community/ rpm卸载已安装mysql rpm -qa | grep -i mysql 查询出来的rpm -e 全部卸载 rpm -e mysql57-community-release-el7-9.noarch rpm -e mysql-community-server-5.7.17-1…

最佳的MongoDB客户端管理工具

《最佳的MongoDB客户端管理工具》 作者:chszs,未经博主允许不得转载。经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 一个好的MongoDB客户端管理工具,可以大大提高MongoDB应用的开发效率。MongoDB自带的Shell是一个很好的工具,但是它在操纵大数据集时就没…