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

news2024/11/24 22:28:27

简介

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

在这里插入图片描述

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

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

UART 驱动示例

测试平台:黑金 AX7Z035

芯片型号:XC7Z035-2FFG676

  • uart.c
/**
 * Copyright (c) 2022-2023,HelloAlpha
 * 
 * Change Logs:
 * Date           Author       Notes
 */
#include "uart.h"

/**
 * @brief 串口初始化
 */
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 串口中断初始化
 */
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 串口数据发送函数
 */
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 串口数据接收函数
 */
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 串口波特率更改
 */
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/559829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第一个SpringBoot程序

如何创建一个SpringBoot项目&#xff0c;两种方式&#xff0c;官网或IDEA 官方提供了一个快速生成的网站&#xff0c;IDE集成了这个网站 spring官网 Spring | Homehttps://spring.io/进入spring官网&#xff0c;点击projects&#xff0c;点击SpringBoot&#xff0c;进到如下…

前端设计必须知道!7个超实用的工具推荐!

前端网络开发作为一个高薪行业&#xff0c;近年来的繁荣是业内人士所看到的。网络开发工具也在上升&#xff0c;市场上出现了越来越多的前端页面设计工具。但随着前端页面设计工具数量的增加&#xff0c;找到合适的前端页面设计工具来完成工作有时会让开发团队感到困惑。 本文…

看不上的年金险

前言 像我这种“资深”股民&#xff0c;激进的有股票期货&#xff0c;稳健的有国债、政策性金融债、地方政府债、城投债&#xff0c;中间的还有etf、宽基指数、指增基金&#xff0c;平时因为对冲风险买点保障性保险也就罢了&#xff0c;储蓄型的保险压根看不上。 但现在通过熬…

Golang语言初识

Windows 下搭建 Go 开发环境-安装和配置 SDK 采用文章 2.5.1介绍了 SDK SDK 的全称(Software Development Kit 软件开发工具包)SDK 是提供给开发人员使用的&#xff0c;其中包含了对应开发语言的工具包 2.5.2下载 SDK 工具包 1) Go 语言的官网为&#xff1a;golang.org , 因…

基于单片机的步进电机驱动电路设计

基于单片机的步进电机驱动电路设计 步进电机在控制系统中具有广泛的应用。它可以把脉冲信号转换成角位移&#xff0c;并且可用作电磁制动轮、电磁差分器、或角位移发生器等。 有时从一些旧设备上拆下的步进电机(这种电机一般没有损坏)要改作它用&#xff0c;一般需自己设计驱动…

Flask 设置头像及创建帖子模型类

我们经常在一些网站上看到&#xff0c;在用户没有自定义头像的情况下&#xff0c;会给每个用户都生成一个头像&#xff0c;这让网站显得更美观&#xff0c;那这个是怎么实现的呢&#xff1f;在Flask中有一个插件&#xff0c;叫做Flask-avatars&#xff0c;专门提供头像解决方案…

UNIX网络编程卷一 学习笔记 第十五章 Unix域协议

本书中&#xff0c;作者说Unix域数据报套接字是不可靠的&#xff0c;这一说法已经过时&#xff0c;当前大多实现中&#xff0c;Unix域套接字都是可靠的&#xff0c;不论是数据报套接字还是字节流套接字。 Unix域协议不是一个实际的协议族&#xff0c;而是单个主机上执行客户/服…

人员定位及轨迹管理技术原理及应用领域

人员定位及轨迹管理的实现涉及多种技术和设备。例如&#xff0c;在GPS定位方面&#xff0c;使用卫星系统可以提供全球范围内的准确定位信息。然而&#xff0c;GPS在室内环境下的信号覆盖可能存在限制&#xff0c;因此在室内定位应用中&#xff0c;常常采用无线传感器网络&#…

Python简单的验证码识别: 图片验证, 滑动验证, 点选验证...

目录 前言环境使用:模块使用:代码展示图片验证码滑动验证码:点选验证: 尾语 &#x1f49d; 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 环境使用: Python 3.8 解释器 Pycharm 编辑器 模块使用: selenium --> pip install selenium3.141.0 ddddocr --> pip i…

springcloud-alibaba (03)sentinel实现规则持久化-流控规则为例

Sentinel和Nacos的整合可以实现规则动态配置&#xff0c;即在Nacos中修改规则后&#xff0c;Sentinel能够实时地读取并应用新的规则。而规则持久化则是指将规则保存在Nacos中&#xff0c;以避免意外故障或重启时规则被丢失。 实现规则持久化&#xff0c;可以按照以下步骤进行操…

龙蜥白皮书精选:利用 io_uring 提升数据库系统性能

文/高性能存储 SIG 01 背景介绍 传统的 IO 软件栈已经无法完全释放出高性能存储设备的性能&#xff0c;高性能 IO 栈是当前存储领域重点研究的课题之一&#xff0c;代表性的如用户态方案 SPDK&#xff0c;以及标准的内核态方案 io_uring。 02 关键技术 Linux 社区从零开始设…

Raft算法

这是一种选举算法&#xff0c;用来确认分布式架构下主节点(领导者)是哪一个结点 只有成为了主节点才能向其他结点进行指令的下达来进行数据的同步 三种角色&#xff1a;追随者Follower&#xff0c;候选人Candidate&#xff0c;领导者leader (1)追随者Follower&#xff1a;接收…

电脑版pdf阅读器有哪些?编辑途径分析

PDF 阅读器电脑版是一种十分流行的电子文档阅读工具&#xff0c;它可以让用户在电脑上轻松地阅读各种文档&#xff0c;包括 PDF 文件。在数字化信息时代&#xff0c;PDF 阅读器电脑版已经成为了许多人电脑上必备的工具之一。本文将探讨 PDF 阅读器电脑版的优缺点&#xff0c;以…

【面试题】面试官:谈谈你知道的DOM常见的操作

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 前言 面试官&#xff1a;“谈谈你知道的DOM常见的操作” 紧张的萌新&#xff1a;“可以获…

达梦数据库索引的建立使用

达梦数据库支持聚集索引&#xff0c;复合索引&#xff0c;函数索引&#xff0c;唯一索引&#xff0c;位图索引等等。 一.建立索引的准则 1.1在表中插入数据后创建索引 一般情况下&#xff0c;在插入或装载了数据后&#xff0c;为表创建索引会更加有效率。如果在装载数据之前…

基于最新SolVES 模型与多技术融合【QGIS、PostgreSQL、ARCGIS、MAXENT、R】实现生态系统服务功能社会价值评估及拓展案例分析

目录 第一章 理论基础与研究热点 第二章 SolVES 4.0 模型运行环境配置 第三章 SolVES 4.0 模型运行 第四章 数据获取与入库 第五章 环境变量与社会价值的相关分析 第六章 拓展案例分析 SolVES模型&#xff08;Social Values for Ecosystem Services&#xff09;全称为生态…

功能开发如何实现多终端设备上的体验统一?

多端能力服务统一&#xff08;Multi-Experience Service Orchestration&#xff0c;MESO&#xff09;是一种技术和服务架构的概念&#xff0c;旨在为多种终端设备提供统一的用户体验和功能。它解决了在不同终端设备上使用不同应用程序和服务时出现的问题&#xff0c;使得用户可…

【云原生-深入理解 Kubernetes 系列 3】深入理解容器进程的文件系统

文章目录 系列文章目录&#x1f479; 关于作者一、回顾二、容器进程的文件系统是什么样子的&#xff1f;rootfs一致性解决应用依赖关系解决复用性 三、OverlayFS 联合文件系统先决条件overlay2 驱动程序如何工作结构图探索含义-磁盘上的镜像层和容器层镜像层容器层 四、overlay…

Lua学习笔记:浅谈对闭包的认识

前言 本篇在讲什么 我们从几个方面简单认识和理解lua的闭包 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Lua5.1的环境 依赖Sublime Text3编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手 提供全…

docker 安装常用软件

安装docker 下载docker curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun修改镜像仓库 vim /etc/docker/daemon.json{"registry-mirrors": ["https://dockerhub.azk8s.cn","https://hub-mirror.c.163.com"] }查看docker …