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

news2024/9/21 2:32:13

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 驱动应用示例

测试平台:黑金 AX7Z035

芯片型号:XC7Z035-2FFG676

驱动示例

  • 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

应用实例

  • 初始化串口一

  • app_uart.c

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

#define UART0_BAUDRATE   115200U

extern 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    100

struct 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

参考来源:UG585

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

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

相关文章

ssm实现发送邮箱功能

参考&#xff1a;ssm整合JavaMail发送邮件_ssm整合mimemessage_ds_surk的博客-CSDN博客 我在这位前辈写的博客的基础上进行讲解完善&#xff0c;避免踩坑。 我的jdk版本&#xff1a;1.8.0_333 1、引入依赖 相信很多朋友都卡在这里&#xff1a; 1、没有JavaMailSenderImpl类 2、…

数字逻辑 期末

概述 教材&#xff1a;《电子技术基础&#xff08;数字部分&#xff09;》 第五版 7400系列是TTL型芯片&#xff0c;商用型 数制 十进制->二进制 除2取余法&乘2取整法&#xff08;注意精度&#xff0c;但计科简单不考&#xff09; 十六进制->二进制 一位变四位 八…

Linux下串口编程

Linux下串口编程 Linux下的串口编程是通过串口设备文件和串口通信的系统调用函数来实现的。Linux下的串口设备文件通常为/dev/ttyS或/dev/ttyUSB(*表示数字),这些设备文件代表了对应的串口硬件设备。 在进行串口编程之前,需要先打开并初始化串口设备,其中包括设置波特率…

Linux 在桌面添加快捷启动图标(可添加至收藏夹)

0 背景 在 Ubuntu 系统下启动程序一般在 Terminal 通过输入指令启动&#xff0c;如 ./cfw。对于常用的程序&#xff0c;为了方便&#xff0c;创建桌面快捷图标 .desktop。为了让图标能够添加在收藏栏中&#xff0c;将 .desktop 融入桌面环境。 1 创建 .desktop 文件 参考&…

dvwa靶场通关(一)

第一关&#xff1a;Brute force low 账号是admin&#xff0c;密码随便输入 用burp suite抓包 爆破得出密码为password 登录成功 Medium 中级跟low级别基本一致&#xff0c;分析源代码我们发现medium采用了符号转义&#xff0c;一定程度上防止了sql注入&#xff0c;采用暴力破…

如何成为一名黑客?小白必学的12个基本步骤

黑客攻防是一个极具魅力的技术领域&#xff0c;但成为一名黑客毫无疑问也并不容易。你必须拥有对新技术的好奇心和积极的学习态度&#xff0c;具备很深的计算机系统、编程语言和操作系统知识&#xff0c;并乐意不断地去学习和进步。 如果你想成为一名优秀的黑客&#xff0c;下…

大项目参考地址​编辑 大项目接口实现

目录 大项目参考地址​编辑 口语考试 纸笔口语考试通常会安排在笔试前一周至笔试后一周的任意一天&#xff0c;机考口语考试通常会安排在笔试当天或者与笔试日期尽可能相邻的日期。根据考务安排的需要&#xff0c;在特殊情况下&#xff0c;口试日期有可能超出此区间&#xff0…

Java——《面试题——多线程并发篇》

前文 java——《面试题——基础篇》 Java——《面试题——JVM篇》 目录 前文 1、说说Java中实现多线程有几种方法 2、如何停止一个正在运行的线程 3、notify()和notifyAll()有什么区别&#xff1f; 4、sleep()和wait() 有什么区别&#xff1f; 5、volatile 是什么?可…

nodejs+vue网络课程在线考试系统an7ib

在线考试系统的设计与实现主要实现角色有管理员和用户,管理员在后台管理学生模块、用户表模块、token表模块、考试资讯模块、考试记录表模块、试题表模块、试卷表模块、配置文件模块、在线答疑模块 采用了Windows10操作系统平台&#xff0c;使用vue前端模板node作为后台监控&am…

k8s补充+helm(待续)

目录 master高可用架构master节点——整个集群的控制中枢node节点——工作节点搭建kubeadm搭建二进制搭建 探针检测方式探针检查参数配置执行顺序为什么有了livenessProbe和readnessProbe还要有StartupProbe&#xff08;1.16&#xff09; 零宕机发布pod退出流程preStop 无状态服…

上网速度太慢?这样设置可以提升60%的上网速度!

虽然现在光纤上网是最好的上网方式&#xff0c;但是对于一般人的选择还是宽带上网&#xff0c;网速永远都是一个值得讨论的话题。花了那么多的钱&#xff0c;却得到的是低品质的网速服务&#xff0c;因此越来越多的人想方设法在现有条件上提高网速。网上的那些方法基本人人都会…

手把手教你用Python编写配置脚本引擎(福利篇)

版权声明&#xff1a;原创不易&#xff0c;本文禁止抄袭、转载需附上链接&#xff0c;侵权必究&#xff01; 目录 一、配置信息写入二、读取配置信息三、修改配置信息四、配置引擎总结五、作者Info 一、配置信息写入 配置信息初始化 定义配置引擎类和初始化方法&#xff0c;其…

day18文件上传下载与三层架构思想

servlet文件上传 注意事项:在写了响应后,若后面还需要执行代码,需要添加return; apach的servlet3.0提供了文件上传的功能. **在客户端中的jsp如何上传文件:**使用form标签 使用input标签type的file属性 form表单中的的enctype必须加:使用二进制的方式进行传输,否则不能进行…

day20 过滤器和监听器

过滤器Filter 作用:对请求和响应进行预处理 使用场景:字符编码处理,登录检验,敏感词过滤,前端框架分发器 Filter的开发步骤 filter也是一个web组件,结构和servlet相似 1.定义类:实现javax.servlet.Filter接口 2.覆盖里面的3个方法: innit:初始化 doFilter:对请求和响应…

线程池C和C++实现

一、线程池介绍 1&#xff09;应用场景 当并发数很多的时候&#xff0c;并且每个线程执行时间很短的任务&#xff0c;这样就会频繁创建线程&#xff0c;而这样的频繁创建和销毁线程会大大降低系统的执行效率。对于这种场景我们可以使用线程池来复用之前创建的线程&#xff0c…

Java 与排序算法(7):堆排序

一、堆排序 堆排序是一种基于比较的排序算法&#xff0c;它的基本思想是将待排序的元素构建成一个堆&#xff0c;然后依次将堆顶元素取出&#xff0c;放到已排序的序列中&#xff0c;直到堆中所有元素都被取出&#xff0c;最终得到一个有序的序列。 堆是一种特殊的树形数据结…

5.24 基础题目

快速幂 #include<bits/stdc.h> using namespace std; //126348976 982638476 938420413 int main(){int a,b,p;cin>>a>>b>>p;long long res 1,ci1;int flag0;if(b0){res%p;}else{while(b){if (flag0)cia%p;elseci(ci%p)*(ci%p)%p;if (b&1)res(res…

【学习随笔】

2022/11/13 HTML :讲完了 css&#xff1a;讲完了 作业&#xff1a;编写登陆界面、整理一下sql优化,对于mybatis不熟练的继续练习 关于MySQL优化的问题? 思路总结&#xff1a;主要考虑数据库优化与SQL语句优化。 1&#xff0c;数据库优化&#xff0c;包括存储引擎的优化&…

FreeRTOS:时间管理

目录 前言一、FreeRTOS 延时函数1.1函数vTaskDelay()1.2 函数prvAddCurrentTaskToDelayedList()1.3 函数vTaskDelayUntil() 二、FreeRTOS 系统时钟节拍 前言 在使用FreeRTOS 的过程中我们通常会在一个任务函数中使用延时函数对这个任务延时&#xff0c;当执行延时函数的时候就…

【C/C++】内存管理

【C/C】内存管理 目录 【C/C】内存管理C/C内存分布C语言和C中动态内存管理方式new/delete操作内置类型new和delete操作自定义类型 operator new与operator delete函数operator new与operator delete的类专属重载new和delete的实现原理定位new表达式(placement-new)重要的知识ma…