ZYNQ_PS读写PL资源

前言

最近比较系统的学习了zynq,内容还是很多的,不过它的架构我还是很熟悉的,所以一些嵌入式知识很快就过了,我的时间主要花在AXI总线和操作系统;
1、AXI总线:
由于Xilinx是将双核ARM与7系列FPGA集成于一块硅片构成SoC,所以比较重要的一个模块就是硬核处理器(PS)与可编程逻辑(PL)之间的通信,传统的有SPI总线、IFC总线的方式,zynq使用的是ARM和Xilinx共同制定的总线协议AMBA AXI4(Advanced Microcontroller Bus Architec),根据使用场景不同它有三种标准Lite、Stream、Full,Full即总线结构最完整的AXI4,4代表第4代,所以要是想和之前第三代总线模块互联的话,之间必须添加总线转换IP,它的总线结构和时序需要好好看看,《Xilinx AP Z-7000 SoC 设计指南》中有很详细介绍,其中有一段关于交易通道握手信号关系很重要:
在这里插入图片描述
在这里插入图片描述
2、操作系统:
这里的操作系统主要是指嵌入式linux,需要掌握peta-linux、uboot、内核、设备树、文件系统等,好多,不过幸运的是,在导入硬件文件后Vivado SDK会自动生成一些库,如头文件和BSP,最大的意义在于完成了硬件资源的映射,软件可以通过对地址的调用完成对硬件的操作。

AXI总线寄存器模块

在Tools中选择生成AXI总线接口的模块(IP),然后需求是PS可以读写32个位宽为32的寄存器,所以我选择的深度是32,其实打开代码就会发现,代码中的示例逻辑本身就是一个寄存器模块,PS和PL都可以对这32个寄存器读写操作,它们的W/R属性也是可以修改的

在这里插入图片描述

//读操作
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
	always @(*)
	begin
	      // Address decoding for reading registers
	      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	        5'h00   : reg_data_out <= slv_reg0;
	        5'h01   : reg_data_out <= slv_reg1;
	        5'h02   : reg_data_out <= slv_reg2;
	        5'h03   : reg_data_out <= slv_reg3;
	        5'h04   : reg_data_out <= slv_reg4;
	        5'h05   : reg_data_out <= slv_reg5;
	        5'h06   : reg_data_out <= slv_reg6;
	        5'h07   : reg_data_out <= slv_reg7;
	        5'h08   : reg_data_out <= slv_reg8;
	        5'h09   : reg_data_out <= slv_reg9;
	        5'h0A   : reg_data_out <= slv_reg10;
	        5'h0B   : reg_data_out <= slv_reg11;
	        5'h0C   : reg_data_out <= slv_reg12;
	        5'h0D   : reg_data_out <= slv_reg13;
	        5'h0E   : reg_data_out <= slv_reg14;
	        5'h0F   : reg_data_out <= slv_reg15;
	        5'h10   : reg_data_out <= slv_reg16;
	        5'h11   : reg_data_out <= slv_reg17;
	        5'h12   : reg_data_out <= slv_reg18;
	        5'h13   : reg_data_out <= slv_reg19;
	        5'h14   : reg_data_out <= slv_reg20;
	        5'h15   : reg_data_out <= slv_reg21;
	        5'h16   : reg_data_out <= slv_reg22;
	        5'h17   : reg_data_out <= slv_reg23;
	        5'h18   : reg_data_out <= slv_reg24;
	        5'h19   : reg_data_out <= slv_reg25;
	        5'h1A   : reg_data_out <= slv_reg26;
	        5'h1B   : reg_data_out <= slv_reg27;
	        5'h1C   : reg_data_out <= slv_reg28;
	        5'h1D   : reg_data_out <= slv_reg29;
	        5'h1E   : reg_data_out <= slv_reg30;
	        5'h1F   : reg_data_out <= slv_reg31;
	        default : reg_data_out <= 0;
	      endcase
	end
//写操作片段
 if (slv_reg_wren)
	      begin
	        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
	          5'h00:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 0
	                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          5'h01:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 1
	                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          5'h02:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 2
	                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  
	          5'h03:
	            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
	              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
	                // Respective byte enables are asserted as per write strobes 
	                // Slave register 3
	                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
	              end  

硬件连接

把Zynq PS和上述生成的寄存器IP PL连接起来,其实很简单,两次自动连线就可以了,这里需要强调的是,需要检查DDR的配置、MIO的配置和PL时钟,由于需要串口打印,所以将串口和PS连接起来,具体管脚需要看原理图,可以看到是14 15,点击与之对应的UART0就可以了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后是将原理图设计转换成代码,再完成综合、实现和最终的bit文件,烧录进pynq Z2,硬件方面的设计就结束了。

软件设计

在File菜单先Export Hardware,然后 Launch SDK,就进入Xilinx软件开发环境,可以在Hello World模板上直接操作。
源码来源于米联客的教程,我根据自己的工程有改动:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"			//Xil_In32 Xil_Out32函数的头文件
#include "xparameters.h"	//硬件映射的地址信息,XPAR_MYIP_REGS_0_S00_AXI_BASEADDR 即PL IP核中寄存器的起始偏移地址

int main()
{
    init_platform();
    print("Hello World\n\r");


    int num;
    int rev;

    xil_printf("------The test is start...------\n\r");


    for( num=0; num<32; num++ )//写入

        {
			xil_printf("%x",num);
			Xil_Out32(XPAR_MYIP_REGS_0_S00_AXI_BASEADDR + num*4, 0x10000000+num);     //
        }



    for( num=0; num<32; num++ )//读出

        {

			rev = Xil_In32(XPAR_MYIP_REGS_0_S00_AXI_BASEADDR + num*4);
			xil_printf( "The data at %x is %x \n\r",XPAR_MYIP_REGS_0_S00_AXI_BASEADDR + num*4,rev);

        }

    xil_printf("------The test is end!------\n\r");

    int test;
    test = Xil_In32( XPAR_MYIP_REGS_0_S00_AXI_BASEADDR + 4);
    xil_printf("%x",test);

    //cleanup_platform();
    return 0;
}

在这里插入图片描述

总结

调试时遇到一个错误,现象是PL能正常烧录,PS能正常编译但是不能下载RUN,反复一直报错:

AP transaction error, DAP status f0000021

我在网上查找了一下,其他不同厂商的开发板也有遇到类似问题,大致原因是软件通过jtag找不到ARM处理器,我联系了开发板的FAE,他给的解释是可能供电电压不稳,换一种供电方式,但是我并没有适配器,但是我看到开发板上ARM的指示灯(DONE)是亮起的,于是重启了电脑和开发板后就恢复正常了,我觉得这很可能是硬件上的缺陷,也有可能是我笔记本USB接口电压不稳?希望能给有同样遭遇的同学一个思路。

  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值