前言

开发环境:vivado 2020.2 vitis windows10 黑金开发板

基于板厂给的模板,修改文件,实现以下功能:

PS端向PL端发送数据(写至BRAM),PL端对数据进行处理,处理后将数据写回BRAM,接着PS端读取BRAM并通过串口发送至win10,win10下使用串口接收数据并利用python导出数据保存。

1.原板厂例程

https://download.csdn.net/download/wxkhturfun/77297149
内容包含vivado工程、vitis工程、说明文档

2.PL端

PL端的vivado工程没什么好讲的,厂家自己封了一个IP,这个IP自己可以改:

    case(state)IDLE            : beginif (start)beginstate <= READ_RAM     ;addr  <= start_addr   ;start_addr_tmp <= start_addr ;len_tmp <= len ;dout <= init_data ;en    <= 1'b1 ;start_clr <= 1'b1 ;end          if (intr_clr)intr <= 1'b0 ;endREAD_RAM        : beginif ((addr - start_addr_tmp) == len_tmp - 4)      //read completedbeginstate <= READ_END ;en    <= 1'b0     ;endelsebeginaddr <= addr + 32'd4 ;                 //address is byte based, for 32bit data width, adding 4         endstart_clr <= 1'b0 ;endREAD_END        : beginaddr  <= start_addr_tmp ;en <= 1'b1 ;we <= 4'hf ;state <= WRITE_RAM  ;                     endWRITE_RAM       : beginif ((addr - start_addr_tmp) == len_tmp - 4)   //write completedbeginstate <= WRITE_END ;dout  <= 32'd0 ;en    <= 1'b0  ;we    <= 4'd0  ;endelsebeginaddr <= addr + 32'd4 ;dout <= dout + 32'd1 ;                       endendWRITE_END       : beginaddr <= 32'd0 ;intr <= 1'b1 ;state <= IDLE ;                       end default         : state <= IDLE ;endcaseend
end

intr是中断,它与Zynq的中断信号相连,这里的READ_RAM是指PS端向BRAM写数据,WRITE_RAM是指PL端向BRAM写数据,read write是相对于PL端来讲的,总体控制代码很简单。synthesis->implementation->generate Bitstream
生成Bit流后,将硬件信息进行Export,具体操作如下:

如果只用到PS端的话,只用pre-synthesis即可,这里用到了PL端,还是要include bitstream的

最后会生成一个 .xsa文件,用解压软件打开会发现如下内容,这个东西后续要交给vitis开发,即软件工程师的内容。

3. Vitis

2018之后的vivado已经没有SDK这个选项了,所以放弃吧别找了,Xilinx把他给集成到Vitis里了。

之后按下列图选择(未出现的图自己默认起个文件名或直接点击next)


最后会生成一个Helloworld工程,自己可以基于这个模板写对就的PS端操作,但是BRAM的相关操作什么的一定要和vivado的地址等相关信息一致。

把helloworld.c进行魔改,改成板厂的提供的文件,在此基础上在进行些修订,方便后续 python串口处理

#include "xil_printf.h"
#include "xil_printf.h"
#include "xbram.h"
#include <stdio.h>
#include "pl_bram_ctrl.h"
#include "xscugic.h"#define BRAM_CTRL_BASE      XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define BRAM_CTRL_HIGH      XPAR_AXI_BRAM_CTRL_0_S_AXI_HIGHADDR
#define PL_RAM_BASE         XPAR_PL_BRAM_CTRL_1_S00_AXI_BASEADDR
#define PL_RAM_CTRL         PL_BRAM_CTRL_S00_AXI_SLV_REG0_OFFSET
#define PL_RAM_INIT_DATA    PL_BRAM_CTRL_S00_AXI_SLV_REG1_OFFSET
#define PL_RAM_LEN          PL_BRAM_CTRL_S00_AXI_SLV_REG2_OFFSET
#define PL_RAM_ST_ADDR      PL_BRAM_CTRL_S00_AXI_SLV_REG3_OFFSET#define START_MASK   0x00000001
#define INTRCLR_MASK 0x00000002#define INTC_DEVICE_ID       XPAR_SCUGIC_SINGLE_DEVICE_ID
#define INTR_ID             XPAR_FABRIC_PL_BRAM_CTRL_1_INTR_INTR#define TEST_START_VAL      0xC
/** BRAM bytes number*/
#define BRAM_BYTENUM        4XScuGic INTCInst;int Len  ;
int Start_Addr ;
int Intr_flag ;
/** Function declaration*/
int bram_read_write() ;
int IntrInitFuntion(u16 DeviceId);
void IntrHandler(void *InstancePtr);int main()
{int Status;Intr_flag = 1 ;IntrInitFuntion(INTC_DEVICE_ID) ;while(1){if (Intr_flag){Intr_flag = 0 ;printf("Please provide start address\t\n") ;//scanf("%d", &Start_Addr) ;Start_Addr = 0;printf("Start address is %d\t\n", Start_Addr) ;printf("Please provide length\t\n") ;//scanf("%d", &Len) ;Len = 100;printf("Length is %d\t\n", Len) ;Status = bram_read_write() ;if (Status != XST_SUCCESS){xil_printf("Bram Test Failed!\r\n") ;xil_printf("******************************************\r\n");Intr_flag = 1 ;}}}
}int bram_read_write()
{u32 Write_Data = TEST_START_VAL ;int i ;/** if exceed BRAM address range, assert error*/if ((Start_Addr + Len) > (BRAM_CTRL_HIGH - BRAM_CTRL_BASE + 1)/4){xil_printf("******************************************\r\n");xil_printf("Error! Exceed Bram Control Address Range!\r\n");return XST_FAILURE ;}/** Write data to BRAM*/for(i = BRAM_BYTENUM*Start_Addr ; i < BRAM_BYTENUM*(Start_Addr + Len) ; i += BRAM_BYTENUM){XBram_WriteReg(XPAR_BRAM_0_BASEADDR, i , Write_Data) ;Write_Data += 1 ;}//Set ram read and write lengthPL_BRAM_CTRL_mWriteReg(PL_RAM_BASE, PL_RAM_LEN , BRAM_BYTENUM*Len) ;//Set ram start addressPL_BRAM_CTRL_mWriteReg(PL_RAM_BASE, PL_RAM_ST_ADDR , BRAM_BYTENUM*Start_Addr) ;//Set pl initial data//PL_BRAM_CTRL_mWriteReg(PL_RAM_BASE, PL_RAM_INIT_DATA , (Start_Addr+9)) ;PL_BRAM_CTRL_mWriteReg(PL_RAM_BASE, PL_RAM_INIT_DATA , (Start_Addr)) ;//Set ram start signalPL_BRAM_CTRL_mWriteReg(PL_RAM_BASE, PL_RAM_CTRL , START_MASK) ;return XST_SUCCESS ;
}int IntrInitFuntion(u16 DeviceId)
{XScuGic_Config *IntcConfig;int Status ;//check device idIntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);//intializationStatus = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress) ;if (Status != XST_SUCCESS)return XST_FAILURE ;XScuGic_SetPriorityTriggerType(&INTCInst, INTR_ID,0xA0, 0x3);Status = XScuGic_Connect(&INTCInst, INTR_ID,(Xil_ExceptionHandler)IntrHandler,(void *)NULL) ;if (Status != XST_SUCCESS)return XST_FAILURE ;XScuGic_Enable(&INTCInst, INTR_ID) ;Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&INTCInst);Xil_ExceptionEnable();return XST_SUCCESS ;}void IntrHandler(void *CallbackRef)
{int Read_Data ;int i ;printf("Enter interrupt\t\n");//clear interrupt statusPL_BRAM_CTRL_mWriteReg(PL_RAM_BASE, PL_RAM_CTRL , INTRCLR_MASK) ;for(i = BRAM_BYTENUM*Start_Addr ; i < BRAM_BYTENUM*(Start_Addr + Len) ; i += BRAM_BYTENUM){Read_Data = XBram_ReadReg(XPAR_BRAM_0_BASEADDR , i) ;printf("Address:@%d$%d@over\t\n",  i/BRAM_BYTENUM ,Read_Data) ;}printf("^exit^\n");Intr_flag = 1 ;
}

代码很简单,一次PS写BRAM、一次PL写BRAM,PL写完后引发Zynq中断。

4. win10端接收数据

不需要数据导出的,直接在putty里看就行了:
安装驱动

将串口打开后,vitis将工程烧进FPGA(烧前,先编译)


以下是Helloworld

5. 数据导出

好吧,我需要将串口的数据导出到

环境:python 3.8.10 64-bits
pip3 install pyserial
我不是软件工程师,python写的很菜,好歹最后能用了。

因为接收到的是二进制数据,所以需要先进行utf-8转码,最后我要的16进制数据,所以还需要转一下(当然你也可以在printf中直接发送16进制数),在vitis中我在PL端最后一次写BRAM之后还printf("^ exit^\n");,我也是根据是否接收到exit来决定是否跳出While循环.
因为串口接收的数据可能是跨行的,或者说不连续的,我无法确定是数据的相关连的,所以只好先将接收的数据通过:dataline = dataline + data全部拼接到一起,最后才处理,由于需要对字符进行split操作,为了方便起见,我在vitis工程的的printf函数中对数据的两端进行添加了若干符号:

printf("Address:@%d$%d@over\t\n",  i/BRAM_BYTENUM ,Read_Data) ;//@与$就是我用来spilt的符号

以下是python3代码(由于各种原因,只能展示部分代码),并不难写,框架和思路我都写好的,自己处理导出数据就行了。

#此处略去部分代码if __name__ == '__main__'
#此处略去部分代码#COM3serial = serial.Serial('COM3', 115200)#serial = serial.Serial('COM3', 115200, timeout=0.01)  print(serial)if serial.isOpen() :print("open success")else :print("open failed")ex = Falsewhile True:data =recv(serial)if  data != b'' :dataline = dataline + dataprint("receive : ",data)#print("receive : ",data.decode('utf-8'))w_data = b'12\r\n'#serial.write(w_data) #数据写回f_data = data.decode('utf-8')f_data = f_data.strip('\n')  #去掉列表中每一个元素的换行符f_p_split = f_data.split('^')   #按'@'进行切片#此处略去部分代码          result = splitData(dataline,len)print(result)#此处略去部分代码

Zynq——PL_BRAM_PS数据传输相关推荐

  1. 基于 ZYNQ 的无线超声数据传输及显示系统的实现

    随着互联网技术的高速发展,移动设备逐渐成为人类生活中不可或缺的工具, 通过各类 App 的支持,使得它能够具有多种多样的功能.因此,本课题将传统的 医疗超声探头和日常生活中的手机进行结合,使移动设备作 ...

  2. axi dma 寄存器配置_FPGA Xilinx Zynq 系列(三十二)AXI 接口

    大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分.大侠可以关注FPGA技术江湖,在"闯荡江湖"."行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢. ...

  3. ZYNQ AXI总线 PS与PL内部通信(用户自定义IP)

    ZYNQ .AXI协议.PS与PL内部通信  三种AXI总线分别为: AXI4:(For high-performance memory-mapped requirements.)主要面向高性能地址映 ...

  4. Xilinx zynq的资料获取总结

    Xilinx zynq zc702开发: 一.zynq开发整个生态系统搭建: 1.基础资料获取: https://github.com/Xilinx/           (包括:交叉编译工具,lin ...

  5. zynq tcp如何从网口发数据_基于TCP/IP协议的电口通信

    之前有介绍过TCP/IP协议的实现是通过轻量级LWIP协议实现的,具体在FPGA中实现又可以分为多种方式,具体如下: 图8‑98 LWIP协议在FPGA中的实现方式 LWIP可以通过硬核实现或者软核实 ...

  6. (13)ZYNQ AXI总线应用范围(学无止境)

    0 AXI协议应用 ZYNQ FPGA中PL与PS交互接口为AXI接口,AXI接口按照协议分类,可以分为AXI4总线.AXI4-Lite.AXI4-Stream. 1 AXI4总线简介 (For hi ...

  7. zynq开发系列5:通过AXI GPIO的中断实现PL端按键控制PS端LED

    在pg144-axi-gpio(LogiCORE IP Product Guide)中可以看见AXI GPIO提供通用输入输出接口到AXI接口,32位软核,设计与AXI4-Lite接口进行连接.IOP ...

  8. 【正点原子FPGA连载】第一章 ZYNQ简介 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  9. ZYNQ PS部分简介

    简介 最近开始接触一些比较高端的芯片,例如:MCIMX6Y2CVM08AB.FPGA.ZYNQ等最近几年很流行的芯片,后面由于一些需要我选择开始学习ZYNQ-7000系列的芯片.也拿到了一块开发板芯片 ...

最新文章

  1. windows phone 8.0 app 移植到windows10 app 页面类
  2. 技术分享 | 微服务模式下如何高效进行API测试
  3. 单独组件_阿里P8年薪百万大牛-教你打造一个Android组件化开发框架
  4. 【*项目调研+论文阅读】SVM-BILSTM-CRF模型SVM-BILSTM-CRF模型 | day7
  5. Hadoop、spark、Flink、Blink、storm介绍
  6. 2017CCPC哈尔滨 A:Palindrome(manacher+树状数组)
  7. Windows Forms Programming In C# 读书笔记 - 第三章 Dialogs (2)
  8. 最贵服务器多少钱_十次方分享:租服务器一般花费多少钱一年?
  9. 【数字信号调制】基于matlab GUI QPSK调制+解调【含Matlab源码 646期】
  10. qxdm无法安装问题闪一下_关于QXDM的安装,解决Win7下QIK报错的问题
  11. 基于STM32的超声波避障小车
  12. 用户体验衡量指标分析
  13. linux命令(3) 链接ln和搜索locate,find, whereis, which, grep命令
  14. CodeForces 576C Points on Plane 莫队
  15. 我的世界服务器无限铁傀儡,我的世界刷铁教程 铁傀儡无限刷铁攻略
  16. php sybase存储过,SYBASE存储过程详解
  17. iOS小技能: 创建渐变色背景(提供渐变色无法覆盖整个视图的解决方案)
  18. 通用获取公众号文章历史,阅读量接口
  19. “重塑”—— 与ISV同行
  20. 【MySQL】黑马教程MySQL数据库 MySQL基础(一)

热门文章

  1. chariot iperf使用_jperf使用说明
  2. DSP_TMS320F28377D_ePWM学习笔记
  3. 只需两步,教你正确识别百度蜘蛛
  4. Java用map实现沁园春_QQ飞车:沁园春地图车神跑法,实力老司机带你了解这几个技巧...
  5. TrackingNet:最经典大规模、多样化的单目标跟踪数据集
  6. 高新技术企业是什么?
  7. centOS7重启网卡失败
  8. 集团信息化之路-我们集团的人力资源软件功能模块如何选定?
  9. 网站web服务器分析小程序
  10. 走进WebKit--开篇