ZYNQ 您所在的位置:网站首页 如何获取串口数据信息的方法 ZYNQ

ZYNQ

2024-07-10 03:03| 来源: 网络整理| 查看: 265

目录

一、搭建Vivado工程

1. PS核配置如下:

2. PL设计如下:

二、新建vitis工程,关联vivado工程的硬件设计

1. 建立vitis工程,在刚才vivado工程设计的硬件基础上,进行软件的设计开发工作

2.在vitis中 编写uart收发的程序

(1)初始化GIC中断控制器

(2)编写uart初始化和操作的代码

(3)main.c函数调用,对GIC控制器、串口进行初始化配置

本文档主要对ZYNQ SOC芯片裸机开发中串口的使用进行讲解,包含了PS串口和PL串口的使用,PS、PL串口都集成在同一个工程中,目前网上通过一个工程同时讲解PS和PL串口的教程还是比较少的,也是因为这个原因写的该文档,大家觉得有用的话可以帮忙点个赞收藏下~

一、搭建Vivado工程

具体搭建vivado工程的一般方法,可以详见以下文章

ZYNQ-Linux开发之(二)Vivado工程搭建、Block Design设计搭建、PS、PL的IP核的使用配置

1. PS核配置如下:

ps端串口波特率配置为230400,如果这里不配置,后续在vitis中也可以通过代码配置修改

QSPI做如下配置,主要是为了方便固化程序,其中QSPI对应引脚的约束以及Bank0、Bank1的电平,需要根据自己项目的原理图去确定。不要直接抄图

PS串口这里只用了1个,用的UART0,同样IO约束根据自己项目选取,其余SD卡配置等可以不选,根据自己项目需求

时钟按照如下配置,选取一个PS向外部输出的时钟配置,配置为输出200MHZ时钟

DDR配置,型号一定要选对,根据自己项目原理图的选型选择,选错可能程序起不来

增加PL到PS的中断,该中断最多支持16路,设计blockdesign时,一定要注意这点,否则可能会导致中断资源不够用

PS配置完成后,是这样子的

2. PL设计如下:

添加PL端的IP核,也就是咱们这次需要使用的PL端的uart ip核,即AXI Uartlite核,整个BlockDesign搭建完毕后如下图所示,添加了两个AXI Uartlite IP核,为了将PS与PL端IP核通过AXI总线相连,添加了AXI Interconnect IP核,相当于集线器功能,同时添加Concat IP核,用来将PL端两个AXI Uartlite核的中断信号,集合起来引到PS端,详细连接方式见图:

右击工程文件,选择输出产品,选择Global,点击Generate

输出产品后,再生成顶层文件

新建约束文件,在约束文件中,增加PL端两个串口收发引脚的约束,对应约束引脚,根据自己项目硬件原理图修改

然后依次点击左边菜单栏的:综合、实现、导出bit文件

bit文件生成成功后,将生成的xsa文件导出来,用于后续的vitis使用,具体步骤如下:

这里选择第二个选项,include bit,因为包含PL端的设计,如果只有PS端,则选择第一个

点击next,选择文件输出的路径,这个路径记清楚,待会建立vitis工程时需要使用这个文件

直接点击finish即可,到这步,vivado的相关工作就完成了,后续就是vitis工程的内容了

二、新建vitis工程,关联vivado工程的硬件设计 1. 建立vitis工程,在刚才vivado工程设计的硬件基础上,进行软件的设计开发工作

点击tools,选择Launch Vitis IDE

选择vitis工程所在的目录,我是新建了一个目录用来存放vitis工程,然后将vivado生成的xsa文件放在了vitis工程的目录下,点击launch

弹出vitis软件中,点击新建应用工程,点击next

选择通过xsa方式建立工程,并点击Browse选取xsa工程文件

xsa文件导入后如下图所示,直接点击next

输入vitis工程的名字,选取ARM处理器,我用的ZYNQ 7020,ARM是双核,所以有两个选择,点击next

这里配置一些信息以及确认一些信息,比如是裸机开发,还是使用简单的系统freertos开发,我这里选择裸机

这里选择新建工程模板,可以选择hello word,也可以选择空白工程,建议选择hello word,因为hello word工程模板包含一些系统编译运行的必须文件,而空白模板工程什么也没有,容易出现编写错误,然后点击finish,完成工程的创建,这样一个vitis工程就创建完毕了。

2.在vitis中 编写uart收发的程序 (1)初始化GIC中断控制器

使用串口收发数据时,首先需要初始化zynq的GIC中断控制器,串口收发数据都是通过中断完成的,在Vitis中,新建intr_hdl.c和intr_hdl.h文件,用来初始化GIC中断控制器

头文件:intr_hdl.h

通过宏定义INTC_DEVICE_ID重新定义GIC设备ID,也是为了后续方便修改和移植,直接使用XPAR_SCUGIC_SINGLE_DEVICE_ID也行。

/*! \file intr_hdl.h \brief firmware functions to manage intr \version 2024-03-12, V1.0.0 \author tbj */ #ifndef INTR_HDL_H #define INTR_HDL_H #include "xscugic.h" #ifdef __cplusplus extern "C" { #endif //GIC中断控制器ID号 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //GIC中断控制器初始化 int Gic_Intr_Init(XScuGic *GicDevicePtr); #ifdef __cplusplus } #endif #endif /* INTR_HDL_H */

源文件:intr_hdl.c

/*! \file intr_hdl.c \brief firmware functions to manage intr \version 2024-03-12, V1.0.0 \author tbj */ #include "intr_hdl.h" /* 功能:初始化GIC中断控制器 * 入参1:GIC中断控制器实例化对象指针 * 入参2:GIC中断控制器设备ID号 */ int Gic_Intr_Init(XScuGic *GicDevicePtr){ int Status = 0; XScuGic_Config *IntcConfig; //初始化中断控制器 IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); if (NULL == IntcConfig) { return XST_FAILURE; } Status = XScuGic_CfgInitialize(GicDevicePtr, IntcConfig, IntcConfig->CpuBaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } (2)编写uart初始化和操作的代码

头文件:uart_hdl.h

通过宏定义对PS、PL串口的设备ID号、设备GIC中断号进行了重定义

声明了PS、PL串口初始化函数

声明了PS、PL串口中断初始化函数

声明了PS、PL串口接收中断处理函数

上面的头文件,根据自己需求进行删减,或放在其余文件中引用

/*! \file uart_hdl.h \brief firmware functions to manage COM ports \version 2024-03-12, V1.0.0 \author tbj */ #ifndef UART_HDL_H #define UART_HDL_H #include #include #include "xparameters.h" #include "xuartlite.h" #include "xil_exception.h" #include "xil_printf.h" #include "xscugic.h" #include "xuartlite_l.h" #include "xgpiops.h" #include "sleep.h" #include "platform.h" #include "xscuwdt.h" #include "xscutimer.h" #include "xuartps.h" #ifdef __cplusplus extern "C" { #endif //PS串口设备ID号 #define UART0_PS_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID //PL串口设备ID号 #define UART0_PL_DEVICE_ID XPAR_UARTLITE_0_DEVICE_ID #define UART1_PL_DEVICE_ID XPAR_UARTLITE_1_DEVICE_ID //PS串口GIC中断号 #define UART0_PS_INTR_ID XPAR_XUARTPS_0_INTR //PL串口GIC中断号 #define UART0_PL_INTR_ID XPAR_FABRIC_UARTLITE_0_VEC_ID #define UART1_PL_INTR_ID XPAR_FABRIC_UARTLITE_1_VEC_ID //初始化PL端的串口 int Pl_Uart_Init(u8 PlUartId); //初始化PS端的串口 int Ps_Uart_Init(u8 PsUartId); //PL串口中断初始化 int Pl_Uart_Intr_Init(u8 PsUartId, XScuGic *IntcInstancePtr); //PS串口中断初始化 int Ps_Uart_Intr_Init(u8 PlUartId, XScuGic *IntcInstancePtr); //PL串口接收中断函数 void Pl_Uart0_Intr_Hander(void *CallBackRef); void Pl_Uart1_Intr_Hander(void *CallBackRef); //PS串口接收中断函数 void Ps_Uart0_Intr_Hander(void *CallBackRef); #ifdef __cplusplus } #endif #endif /* UART_HDL_H */

源文件:uart_hdl.c

实例化PS、PL串口结构体对象,并新建数组,存放实例化后的对象指针,方便后续使用操作,这样后面的串口初始化配置等操作,只需要传入对应串口号即可操作响应的串口结构体;

将PS、PL串口的设备ID号和GIC中断ID号列到数组中,同样是为了方便后续操作;

定义一个串口接收的buffer:recv_buf[100],100个字节;

然后分别对PS串口初始化函数、PS串口中断初始化函数、PL串口初始化函数、PL串口中断初始化函数、PS串口中断接收函数、PL串口中断接收函数进行实现,具体可见下列代码;

其中PS和PL串口中断接收函数中,收到数据后直接就发送出去了,实际项目中需根据自己的需求对数据进行处理;

一些注意事项:PS和PL串口同时使用时,PL串口配置的中断优先级不能小于等于0xA0(即数值不能大于等于0xA0),目前代码中配置的PL串口中断优先级为0x98,如果数值大于等于0xA0时,单独使用PL串口收发没有问题,一旦使用了一次PS串口的收发,PL串口收发功能就失效了,具体原因我也不太清楚,还没深究,大家知道的话可以评论区说下~

#include "uart_hdl.h" //PS串口初始化实例 XUartPs PsUart0; //PS串口初始化实例指针数组 XUartPs *Ps_Uart_Arry[1] = {&PsUart0}; //PS设备ID号以及中断ID号 u32 Ps_Uart_Id[1] = {UART0_PS_DEVICE_ID}; u32 Ps_Uart_Intr_Id[1] = {UART0_PS_INTR_ID}; //PL串口初始化实例 XUartLite PlUart0, PlUart1; //PL串口初始化实例指针数组 XUartLite *Pl_Uart_Arry[2] = {&PlUart0, &PlUart1}; //PL设备ID号以及中断ID号 u32 Pl_Uart_Id[2] = {UART0_PL_DEVICE_ID, UART1_PL_DEVICE_ID}; u32 Pl_Uart_Intr_Id[2] = {UART0_PL_INTR_ID, UART1_PL_INTR_ID}; //串口接收数据缓存区 u8 recv_buf[100] = {0}; /* 功能:初始化PS端串口 * 入参1:PS端串口号 */ int Ps_Uart_Init(u8 PsUartId){ int Status = 0; XUartPs_Config *Config; //提取PS串口结构体指针 Config = XUartPs_LookupConfig(Ps_Uart_Id[PsUartId]); if (NULL == Config) { return XST_FAILURE; } //初始化对应PS串口 Status = XUartPs_CfgInitialize(Ps_Uart_Arry[PsUartId], Config, Config->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } //串口自检 Status = XUartPs_SelfTest(Ps_Uart_Arry[PsUartId]); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* *PS串口可以在代码中设置模式、波特率等属性 *PL串口不需要在代码中设置模式、波特率等属性,是在block design中的IP核配置的 */ //设置工作模式:正常模式 XUartPs_SetOperMode(Ps_Uart_Arry[PsUartId], XUARTPS_OPER_MODE_NORMAL); //设置波特率 XUartPs_SetBaudRate(Ps_Uart_Arry[PsUartId],230400); //设置 RxFIFO 的中断触发等级,FIFO中只要收到一个字节就触发中断,类似于非空中断 XUartPs_SetFifoThreshold(Ps_Uart_Arry[PsUartId], 1); return XST_SUCCESS; } /* 功能:初始化PS端串口中断 * 入参1:PS端串口号 * 入参2:GIC中断实例化对象指针 */ int Ps_Uart_Intr_Init(u8 PsUartId, XScuGic *IntcInstancePtr){ int Status = 0; //绑定中断处理函数-接收串口数据到buffer switch(Ps_Uart_Intr_Id[PsUartId]){ case UART0_PS_INTR_ID: //绑定中断处理函数 Status = XScuGic_Connect(IntcInstancePtr, Ps_Uart_Intr_Id[PsUartId], (Xil_ExceptionHandler)Ps_Uart0_Intr_Hander, Ps_Uart_Arry[PsUartId]); break; default: break; } if (Status != XST_SUCCESS) { return Status; } //打开中断异常处理 Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstancePtr); Xil_ExceptionEnable(); //设置 UART 的中断触发方式 XUartPs_SetInterruptMask(Ps_Uart_Arry[PsUartId], XUARTPS_IXR_RXOVR); //使能 GIC 中的串口中断 XScuGic_Enable(IntcInstancePtr, Ps_Uart_Intr_Id[PsUartId]); return XST_SUCCESS; } /* 功能:初始化PL端的串口 * 入参1:PL端串口号 */ int Pl_Uart_Init(u8 PlUartId){ int Status = 0; //初始化串口 Status = XUartLite_Initialize(Pl_Uart_Arry[PlUartId], Pl_Uart_Id[PlUartId]); if (Status != XST_SUCCESS) { return XST_FAILURE; } //串口自检 Status = XUartLite_SelfTest(Pl_Uart_Arry[PlUartId]); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* *PS串口可以在代码中设置模式、波特率等属性 *PL串口不需要在代码中设置模式、波特率等属性,是在block design中的IP核配置的 */ return XST_SUCCESS; } /* 功能:PL串口中断初始化 * 入参1:PL端串口号 * 入参2:GIC中断实例化对象指针 */ int Pl_Uart_Intr_Init(u8 PlUartId, XScuGic *IntcInstancePtr){ int Status = 0; //打开中断异常处理 Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstancePtr); Xil_ExceptionEnable(); /*初始化配置中断优先级和中断触发类型 0x98:优先级160,0最高 *优先级,0xF8(248)是最低的。有32个优先级 *由8的台阶支撑。因此,支持的优先事项是0、8、16、32、40。。。,248 *0x3:B11,触发类型上升沿 *PL串口中断优先级不能使用0xA0,否则和PS串口同时使用时,PL先收发好用,一旦PS串口收发,PL串口收发就会失灵 */ switch(Pl_Uart_Intr_Id[PlUartId]){ case UART0_PL_INTR_ID: XScuGic_SetPriorityTriggerType(IntcInstancePtr, Pl_Uart_Intr_Id[PlUartId], 0x98, 0x3); //绑定中断处理函数 Status = XScuGic_Connect(IntcInstancePtr, Pl_Uart_Intr_Id[PlUartId], (Xil_ExceptionHandler)Pl_Uart0_Intr_Hander, (void*)Pl_Uart_Arry[PlUartId]); break; case UART1_PL_INTR_ID: XScuGic_SetPriorityTriggerType(IntcInstancePtr, Pl_Uart_Intr_Id[PlUartId], 0x98, 0x3); //绑定中断处理函数 Status = XScuGic_Connect(IntcInstancePtr, Pl_Uart_Intr_Id[PlUartId], (Xil_ExceptionHandler)Pl_Uart1_Intr_Hander, (void*)Pl_Uart_Arry[PlUartId]); break; default: break; } if (Status != XST_SUCCESS) { return Status; } //使能串口中断 XScuGic_Enable(IntcInstancePtr, Pl_Uart_Intr_Id[PlUartId]); XUartLite_EnableInterrupt(Pl_Uart_Arry[PlUartId]); return XST_SUCCESS; } /* * 功能:PS串口uart0中断接收处理函数 */ void Ps_Uart0_Intr_Hander(void *CallBackRef){ u32 recv_num = 0 ; //接收数据个数 u32 isr_status ; //中断状态标志 //读取中断 ID 寄存器,判断触发的是哪种中断 isr_status = XUartPs_ReadReg(PsUart0.Config.BaseAddress, XUARTPS_IMR_OFFSET); isr_status &= XUartPs_ReadReg(PsUart0.Config.BaseAddress, XUARTPS_ISR_OFFSET); //判断中断标志位 RxFIFO 是否触发 if (isr_status & (XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXFULL)){ //读取接收的数据到缓存区 recv_num = XUartPs_Recv(&PsUart0, recv_buf, 100); //将缓存区中接收到的数据再发送出去 XUartPs_Send(&PsUart0, recv_buf, recv_num); //清空缓存区 memset(recv_buf, 0, 100); } } /* * 功能:PL串口uart0中断接收处理函数 */ void Pl_Uart0_Intr_Hander(void *CallBackRef){ uint16_t recv_num = 0 ; u32 IsrStatus ; //中断状态标志 //读取中断 ID 寄存器,判断触发的是哪种中断 IsrStatus = XUartLite_ReadReg(PlUart0.RegBaseAddress, XUL_STATUS_REG_OFFSET); if ((IsrStatus & (XUL_SR_RX_FIFO_FULL | XUL_SR_RX_FIFO_VALID_DATA)) != 0) { //读取接收的数据到缓存区 recv_num = XUartLite_Recv(&PlUart0, recv_buf, 100); //发送出去-测试使用 XUartLite_Send(&PlUart0, recv_buf, recv_num); //清空缓存区 memset(recv_buf, 0, 100); } } /* * 功能:PL串口uart1中断接收处理函数 */ void Pl_Uart1_Intr_Hander(void *CallBackRef){ //同uart0 } (3)main.c函数调用,对GIC控制器、串口进行初始化配置 #include #include "platform.h" #include "xil_printf.h" int main() { //初始化GIC中断控制器 Gic_Intr_Init(&GicIntrDevice); //初始化PS串口 Status |= Ps_Uart_Init(0); Status |= Ps_Uart_Intr_Init(0, &GicIntrDevice); Status |= Pl_Uart_Init(0); Status |= Pl_Uart_Intr_Init(0, &GicIntrDevice); //初始化PL串口 while(1){ } return 0; }

创作不易,希望大家点赞、收藏、关注哦!!!ヾ(o◕∀◕)ノ



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有