ZYNQ PS使用axi uartlite进行串口收发

这篇具有很好参考价值的文章主要介绍了ZYNQ PS使用axi uartlite进行串口收发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

由于使用的ZYNQ PS部分只有两个串口,其中一个还当成了控制台用,串口不够用,于是使用PL的逻辑部分并利用IP核:AXI UARTLITE 为PS增加串口数量,并添加了AXI TIMER。
Vivado和Vitis为2020,PS为裸机使用。
包含以下内容:
1、Vivado的配置
2、axi uartlite代码
3、axi timer代码
4、利用IP核:axi timer,实现类似串口空闲中断的功能,这种思路我在FPGA、单片机和一些软件开发时经常使用,比较方便。
5、使用效果

一、Vivado配置

1.1. axi uartlite添加

我这里使用的波特率是460800,PL的时钟频率为120M,在配置的时候发现PL频率需要大于100M才能使用460800的波特率,比较费解。

1.2. axi timer添加

axi uartlite,FPGA 开发笔记,fpga开发
使能了两个通道

1.3. PL时钟修改

axi uartlite,FPGA 开发笔记,fpga开发

1.4. ZYNQ系统

axi uartlite,FPGA 开发笔记,fpga开发
最终的ZYNQ系统如图,注意axi uartlite 和axi timer都使能了中断。

二、axi uartlite代码

2.1. 头文件包含:

#include "xuartlite.h"
#include "xuartlite_l.h"
#include "stdio.h"
#include "xparameters.h"
#include "xil_printf.h"
#include "xscugic.h"

#define AXI_UARTLITE_DEVICE_ID		XPAR_AXI_UARTLITE_0_DEVICE_ID				//AXI_Timer设备ID
#define AXI_UARTLITE_IRPT_INTR		XPAR_FABRIC_AXI_UARTLITE_0_INTERRUPT_INTR	//AXI TIMER 中断号

XUartLite xUartLite1;

uint16_t xUartLite1_RecvCount=0;
uint8_t xUartLite1_RecvBuffer[1024];

2.2. 串口接收

初始化代码,注意串口中断回调是xUartLite1_Int_Handler函数,Sys_ScuGic顾名思义 是系统中断控制器的实例:

int xUartLite1_Init(XUartLite *xUartLite_Ptr)
{
	int Status;

	//初始化AXI UART
	Status = XUartLite_Initialize(xUartLite_Ptr,AXI_UARTLITE_DEVICE_ID);

	//自检
	Status = XUartLite_SelfTest(xUartLite_Ptr);
	if (Status != XST_SUCCESS)\
	{
		return XST_FAILURE;
	}

	//中断设置
	XScuGic_SetPriorityTriggerType(&Sys_ScuGic, AXI_UARTLITE_IRPT_INTR,0xA0, 0x3);

	//中断设置
	XScuGic_Connect(&Sys_ScuGic, AXI_UARTLITE_IRPT_INTR,(Xil_ExceptionHandler)xUartLite1_Int_Handler, (void *)xUartLite_Ptr);

	//使能 GIC中的中断
	XScuGic_Enable(&Sys_ScuGic, AXI_UARTLITE_IRPT_INTR);

	//中断使能
	XUartLite_EnableInterrupt(xUartLite_Ptr);

	return XST_SUCCESS;
}

中断回调函数:
串口相关的中断都会进入此函数,例如发送完成、接收到数据等,在此函数中,仅判断是否接收到数据,然后进入xUartLite1_RecvInt_Handler函数进行数据读取。

void xUartLite1_Int_Handler()
{
	int IsrStatus;

	IsrStatus = XUartLite_ReadReg(xUartLite1.RegBaseAddress,XUL_STATUS_REG_OFFSET);

	if((IsrStatus & (XUL_SR_RX_FIFO_FULL | XUL_SR_RX_FIFO_VALID_DATA)) != 0)
	{
		xUartLite1_RecvInt_Handler();
	}
}

//串口接收回调
void xUartLite1_RecvInt_Handler()
{
	//获取接收字节
	xUartLite1_RecvBuffer[xUartLite1_RecvCount++] = XUartLite_RecvByte(xUartLite1.RegBaseAddress);

	xTmrCh2_Count = 0;
}

2.3. 串口发送

直接调用库函数:

void xUartLite1_Send(uint8_t *Data,uint16_t Lenth)
{
	XUartLite_Send(&xUartLite1,Data,Lenth);
}

三、axi timer代码

比较简单,不做解释了,就这些代码,注意timer的ch1定时周期是1秒,ch2是1us,ch2是供串口使用的

#include "timer.h"

#define AXI_TIMER_DEVICE_ID		XPAR_AXI_TIMER_0_DEVICE_ID				//AXI_Timer设备ID
#define AXI_TIMER_IRPT_INTR		XPAR_FABRIC_AXI_TIMER_0_INTERRUPT_INTR	//AXI TIMER 中断号

uint8_t xTmr1Ch1_IntFlg=0;
uint32_t xTmrCh2_Count=0;

extern uint16_t xUartLite1_RecvCount;
extern uint8_t xUartLite1_RecvBuffer[1024];
extern void xUartLit1_ReceiveData_Process(uint8_t *Data,uint16_t Lenth);

XTmrCtr		xTmr1_Inst;	//AXI Timer

#define AXI_TIMER_CH1_PERIOD_US		1000000	//AXI TIMER CH1 的定时器周期为1S
#define AXI_TIMER_CH2_PERIOD_US		1		//AXI TIMER CH2 的定时器周期为1US

//定时器中断回调
void xTmrCtr_Int_Handler(void *CallBackRef, u8 TmrCtrNumber)
{
	//AXI TIMER 的定时器1
	if(TmrCtrNumber == AXI_TIMER_CHANNEL_1)
	{
		xTmr1Ch1_IntFlg = 1;
	}

	//AXI TIMER 的定时器2
	if(TmrCtrNumber == AXI_TIMER_CHANNEL_2)
	{
		xTmrCh2_Count++;

		if(xUartLite1_RecvCount != 0 && xTmrCh2_Count > 100)
		{
			xUartLit1_ReceiveData_Process(xUartLite1_RecvBuffer,xUartLite1_RecvCount);

			//重新开始接收
			xUartLite1_RecvCount = 0;
		}
	}
}

//定时的微秒数转寄存器值
//AXI TIMER是倒计时,如果想定时1MS,那么寄存器中要写入:最大值-1MS
//AXI TIMER的时钟为120M,1US为120个Tick
u32 xTmr_US_To_RegValue(u32 US)
{
	u32 Value;

	Value = 120*US;

	return 0xFFFFFFFF - Value;
}

//定时的微秒数转纳秒
u32 xTmr_US_To_NS(u32 US)
{
	return US*1000;
}

//AXITIMER初始化
int xTmrCtr_Init(XTmrCtr *xTmrCtr_Ptr)
{
	int Status;

	//初始化AXI_TIMER 0
	Status = XTmrCtr_Initialize(xTmrCtr_Ptr, AXI_TIMER_DEVICE_ID);
	if(Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	//自检:两个定时器
	Status = XTmrCtr_SelfTest(xTmrCtr_Ptr, 2-1);
	if(Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}

	//设置中断回调函数
	XTmrCtr_SetHandler(xTmrCtr_Ptr,xTmrCtr_Int_Handler,xTmrCtr_Ptr);

	//定时器1中断计数
	XTmrCtr_SetResetValue(xTmrCtr_Ptr,AXI_TIMER_CHANNEL_1,xTmr_US_To_RegValue(AXI_TIMER_CH1_PERIOD_US));
	//定时器2中断计数
	XTmrCtr_SetResetValue(xTmrCtr_Ptr,AXI_TIMER_CHANNEL_2,xTmr_US_To_RegValue(AXI_TIMER_CH2_PERIOD_US));

	//定时器中断打开
	XTmrCtr_SetOptions(xTmrCtr_Ptr, AXI_TIMER_CHANNEL_1, XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION);
	XTmrCtr_SetOptions(xTmrCtr_Ptr, AXI_TIMER_CHANNEL_2, XTC_INT_MODE_OPTION | XTC_AUTO_RELOAD_OPTION);

	//中断设置
	XScuGic_Connect(&Sys_ScuGic, AXI_TIMER_IRPT_INTR,(Xil_ExceptionHandler)XTmrCtr_InterruptHandler, (void *)xTmrCtr_Ptr);

	//使能 GIC中的定时器中断
	XScuGic_Enable(&Sys_ScuGic, AXI_TIMER_IRPT_INTR);

	return XST_SUCCESS;
}

void xTmr_Enable(XTmrCtr *xTmrCtr_Ptr,uint8_t Channel)
{
	XTmrCtr_Start(xTmrCtr_Ptr,Channel);
}

void xTmr_Disable(XTmrCtr *xTmrCtr_Ptr,uint8_t Channel)
{
	XTmrCtr_Stop(xTmrCtr_Ptr,Channel);
}

四、利用定时器实现串口空闲中断

串口波特率是460800,一个字节大约耗时21us,每当收到串口数据时,定时器清0,在定时器1us的回调中,检测到串口接收长度不为0,且定时器时间>100us,认为一帧数据接收完成,100us的时间可以调整。

//串口接收
void xUartLite1_RecvInt_Handler()
{
	//获取接收字节
	xUartLite1_RecvBuffer[xUartLite1_RecvCount++] = XUartLite_RecvByte(xUartLite1.RegBaseAddress);

	xTmrCh2_Count = 0;
}

//定时器判断串口接收
//定时器中断回调
void xTmrCtr_Int_Handler(void *CallBackRef, u8 TmrCtrNumber)
{
	//AXI TIMER 的定时器1
	if(TmrCtrNumber == AXI_TIMER_CHANNEL_1)
	{
		xTmr1Ch1_IntFlg = 1;
	}

	//AXI TIMER 的定时器2
	if(TmrCtrNumber == AXI_TIMER_CHANNEL_2)
	{
		xTmrCh2_Count++;

		//认为一帧数据接收完成,可以处理
		if(xUartLite1_RecvCount != 0 && xTmrCh2_Count > 100)
		{
			xUartLit1_ReceiveData_Process(xUartLite1_RecvBuffer,xUartLite1_RecvCount);
			//重新开始接收
			xUartLite1_RecvCount = 0;
		}
	}
}

五、使用效果

每次收到一帧数据后,打印长度、第一个数据和最后一个数据

void xUartLit1_ReceiveData_Process(uint8_t *Data,uint16_t Lenth)
{
	xil_printf("AXI UartLite Receive Process,Lenth: %d,Data:%02X,%02X\n",Lenth,Data[0],Data[Lenth-1]);
}

axi uartlite,FPGA 开发笔记,fpga开发
完整工程下载连接,包括vivado和vitis:
https://download.csdn.net/download/qq_36365231/88677067文章来源地址https://www.toymoban.com/news/detail-848993.html

到了这里,关于ZYNQ PS使用axi uartlite进行串口收发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • ZYNQ通过AXI DMA实现PL发送连续大量数据到PS DDR

    ZYNQ通过AXI DMA实现PL发送连续大量数据到PS DDR

    硬件:ZYNQ7100 软件:Vivado 2017.4、Xilinx SDK 2017.4   ZYNQ PL 和 PS 的通信方式有 AXI GPIO、BRAM、DDR等。对于数据量较少、地址不连续、长度规则的情况,BRAM 比较适用。而对于传输速度要求高、数据量大、地址连续的情况,比如 ADC,可以通过 AXI DMA 来完成。 1、硬件设计 1.1 ZYNQ7

    2024年02月04日
    浏览(13)
  • ZYNQ PS与PL通过AXI-LITE连接,在Linux下直接读写PL的物理地址,实现PS与PL的交互

    ZYNQ PS与PL通过AXI-LITE连接,在Linux下直接读写PL的物理地址,实现PS与PL的交互

    ZYNQ开发,如果PL与PS的交互方式仅为AXI-Lite总线的话,在Linux下可以通过直接访问PL的寄存器物理地址来实现PS-PL的数据交互。 测试代码的PC开发平台为Ubuntu18.04,QT5。 ZYNQ为7020,并移植了Linux系统和Ubuntu16.04的最小系统。 将PL的程序封装成IP核,通过AXI-LITE与PS连接,对外是18个寄

    2024年04月10日
    浏览(12)
  • FPGA----UltraScale+系列的PS侧与PL侧通过AXI-HP交互(全网唯一最详)附带AXI4协议校验IP使用方法

    FPGA----UltraScale+系列的PS侧与PL侧通过AXI-HP交互(全网唯一最详)附带AXI4协议校验IP使用方法

    1、之前写过一篇关于ZYNQ系列通用的PS侧与PL侧通过AXI-HP通道的文档,下面是链接。 FPGA----ZCU106基于axi-hp通道的pl与ps数据交互(全网唯一最详)_zcu106调试_发光的沙子的博客-CSDN博客 大家好,今天给大家带来的内容是,基于AXI4协议的采用AXI-HP通道完成PL侧数据发送至PS侧(PS侧数

    2024年02月13日
    浏览(9)
  • FPGA - ZYNQ 基于EMIO的PS和PL交互

    FPGA - ZYNQ 基于EMIO的PS和PL交互

    Xilinx ZYNQ 系列的芯片,GPIO分为 MIO 、 EMIO 、 AXI_GPIO 三种方式。 MIO    :固定管脚,属于PS端,也就是ARM端。 EMIO   :通过PL扩展,使用时需要分配 PL ( FPGA ) 管脚,消耗PL端资源。 AXI_GPIO :封装好的IP核,PS通过M_AXI总线可以控制PL的IO接口,使用时,消耗管脚资源和逻辑资源。

    2024年04月26日
    浏览(10)
  • fpga 通过axi master读写PS侧DDR的仿真和上板测试

    fpga 通过axi master读写PS侧DDR的仿真和上板测试

           FPGA和ARM数据交互是ZYNQ系统中非常重要的内容。PS提供了供FPGA读写的AXI-HP接口用于两者的高速通信和数据交互。一般的,我们会采用AXI DMA的方式去传输数据,DMA代码基本是是C编写,对于FPGA开发者来说不利于维护和debug。本文提供一种手写AXI_MASTER接口用于PL 向DDR指定位

    2024年04月12日
    浏览(9)
  • FPGA——串口收发

    FPGA——串口收发

    常用的三大低速串口通信有UART,SPI,IIC。这里使用FPGA实现UART通信。UART通信只有两根线,一根是发送数据tx,一根是接受数据rx。PC和PFGA通过两个线实现数据通信。 完成FPGA部分的收发设计实现串口通信。 RS232 1、RS232 是 UART 的一种,没有时钟线,只有两根数据线,分别是 rx

    2024年02月15日
    浏览(7)
  • FPGA----ZCU106基于axi-hp通道的pl与ps数据交互(全网唯一最详)

    FPGA----ZCU106基于axi-hp通道的pl与ps数据交互(全网唯一最详)

    1、大家好,今天给大家带来的内容是,基于AXI4协议的采用AXI-HP通道完成PL侧数据发送至PS侧(PS侧数据发送至PL侧并没有实现,但是保留了PL读取PS测数据的接口) 2、如果大家用到SoC这种高级功能,那大家应该对于AXI4协议已经很熟悉了,但本文侧重点为初学者直接提供可以上

    2023年04月24日
    浏览(58)
  • FPGA基础设计(八):串口收发之RAM存储

    FPGA基础设计(八):串口收发之RAM存储

    实现上位机通过串口发送数据到FPGA,FPGA接收到数据后将其存储在RAM的一段连续空间中,然后通过按键触发读出RAM数据,再通过串口发送到上位机。 1、串口接收模块; 2、按键消抖模块 3、创建RAM IP核模块 4、RAM IP核控制模块; 5、串口发送模块。 前面已经设计好了串口发送模

    2024年02月03日
    浏览(54)
  • ZYNQ 7020 之 FPGA知识点重塑笔记一——串口通信

    ZYNQ 7020 之 FPGA知识点重塑笔记一——串口通信

    目录 一:串口通信简介 二:三种常见的数据通信方式—RS232串口通信 2.1 实验任务 2.2 串口接收模块的设计 2.2.1 代码设计 2.3 串口发送模块的设计 2.3.1 代码设计 2.4 顶层模块编写 2.4.1 代码设计 2.4.2 仿真验证代码 2.4.3 仿真结果 2.4.4 板上验证        通信方式一般分为 串行

    2024年02月03日
    浏览(9)
  • 【FPGA + 串口】功能完备的串口测试模块,三种模式:自发自收、交叉收发、内源

    【FPGA + 串口】功能完备的串口测试模块,三种模式:自发自收、交叉收发、内源 将 mode设置为0,是自发自收; 将 mode设置为1,是交叉收发; 将 mode设置为2,是内源;外部串口直接看数据即可; 通过三种模式的测量,可以精确的测量串口是否通,出故障,也可以判断出 是

    2024年02月15日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包