一种Zynq7000内部通信的程序构架

发表时间:2021/4/22   来源:《科学与技术》2021年3期   作者:王晓迪 余佩 屈鹏珍
[导读] Zynq7000系列基于Xilinx全可编程的可扩展处理平台结构是一种SoC芯片
        王晓迪 余佩 屈鹏珍
        (陕西长岭电子科技有限责任公司产品开发部,宝鸡,721006)
        摘  要:Zynq7000系列基于Xilinx全可编程的可扩展处理平台结构是一种SoC芯片,集成了Cortex-A9双核ARM和FPGA。本文讲述了如何利用xilinx公司Zynq7000系列芯片的AXI_APB_Bridge、AXI_BRAM_Controller和AXI_GPIO这三种IP核实现芯片内部ARM与FPGA之间的通信。
        关键词:Zynq7000  IP核 内部通信
1  引言
        Zynq7000系列基于Xilinx全可编程的可扩展处理平台结构,该结构在单芯片内集成了基于ARM公司双核ARM Cortex-A9多核处理器的处理系统(PS),以及基于Xilinx可编程逻辑资源的可编程逻辑系统(PL)。同时,该结构基于最新的高性能低功耗的28nm、高k金属栅极工艺,能够保证该器件在高性能运行的同时,具有比同类Cortex-A9双核处理器更低的功耗。
        Zynq7000系列内部的多核处理器的处理系统与可编程逻辑系统通信(PS-PL)接口主要有AXI_GP、AXI_HP和AXI_ACP接口,这些接口时序复杂,不利于实际应用,因此,xilinx公司还提供了自定义ip的方法来满足用户的个性需求,同时提供了典型的接口ip供用户使用。
        利用自定义ip的方法实现PS-PL通信接口是使用xilinx提供的ip封装工具,将用户代码封装成为标准AXI总线形式模块,将模块以图形化的方式加入顶层文件中并进行AXI总线的自动连接,这种方式的优点在于操作较为简单,缺点在于程序中模块数量很多的时候图形化的方式较为混乱,并且调试不易。
        利用典型的接口ip方法实现PS-PL通信接口是使用xilinx提供的典型ip,构成简易的总线接口,在PL端将各个模块的输入输出数据映射到内存中,在PS端就可以利用直接寻址的方法进行数据的交互。这种方式的优点在于程序结构清晰,方便调试。下面,我们对其进行详细的论述。
2  内部通讯的整体结构
        本文使用黑金开发板AX7020,新建一个Zynq7000的工程,并新建一个CPU系统结构,如图1所示,其中包括:1个ARM模块ZYNQ7 Processing System、1个APB桥AXI_APB_Bridge、1个BRAM控制器AXI_BRAM_Controller和1个gpio中断AXI_GPIO,Processor System Reset与AXI Interconnect为自动添加。

图1  CPU系统结构
        其中,APB桥用于传输零散的数据,其总线形式类似于ISA总线,含有地址线、数据线和控制线;BRAM控制器用于传输大块的数据,可以和Block Memory Generator中的True Dual Port RAM直接对接;GPIO用于传输中断信号。这些总线和信号可涵盖大部分的处理器应用,下面对其中的各个模块的架设进行一一说明。
2.1  创建ARM核
        创建一个Zynq7000的工程,并新建一个CPU系统结构,添加1个ARM模块ZYNQ7 Processing System,设置在PS-PL Configuration页面打开M AXI GP0端口,在Clock Configuration页面设置FCLK_CLK0 50(100、200均可),在Interrupt页面设置中断IRQ_F2P。
2.2  创建外部设备
        添加一个gpio模块AXI_GPIO,选中All Inputs选项,GPIO width设置1,选中Enable Interrupt选项,其余默认;添加1个APB桥AXI_APB_Bridge, Number of Slaves设置为1,其余默认;添加1个BRAM控制器AXI_BRAM_Controller,Number of BRAM interfaces设置为1,其余默认;生成的4个主要模块。
        自动连线,生成端口。
        修改AXI Interconnect,增加一个Master Interface,将其数值由2改为3。手动连接AXI APB Bridge和gpio中断,删除bram模块。
        整理各模块位置,添加对外接口,对外时钟,修改接口名称。
        最后分配地址,修改地址空间。到此CPU系统完成,我们将其生成HDL文件,然后在顶层文件中调用即可。
2.3  APB端口程序
        APB端口读写时序,APB_port_pready信号为PL端准备好信号,可以常置为1,APB_port_pslverr为PL端接收错误信号可以常置为0;APB_port_penable为使能信号;APB_port_psel为选择信号;APB_port_pwrite为读写控制信号,传输每个数据需要18个时钟周期,在50MHz的总线时钟速率下,其数据率为11MBps。
        在PS-PL传输数据时序中,PS写数据到PL。当APB_port_pwrite、APB_port_psel和APB_port_penable这3个信号同时为1时,表示PS将要写入PL的数据可靠的发送到APB_port_pwdata上,此时可以将数据锁存到所需要的位置。
        在PL-PS传输数据时序中,PS从PL读取数据。当APB_port_pwrite为0,APB_port_psel为1时,需要PL将数据放置到APB_port_prdata总线上。
        对应PL端程序如下:
//-----------------------------APB端------------------------------------------   
        reg intr = 0;
        reg[31:0] intr_time = 0;
        reg[31:0] ctrlword = 0;
        assign cpu_intrrupt = intr;
        
        assign APB_port_pready = 1'b1;
        assign APB_port_pslverr = 1'b0;
        wire iow = (APB_port_pwrite & APB_port_psel & APB_port_penable & APB_port_pready);
        wire ior = ((~APB_port_pwrite) & APB_port_psel);
        
        always @(posedge bus_clk_50m)
        begin
                if(iow)
                        begin
                                case(APB_port_paddr)
                                        32'h43C0_0000   :   ctrlword <= APB_port_pwdata;
                                endcase
                        end
                if(ior)
                        begin
                                case(APB_port_paddr)
                                        32'h43C0_1000   :   APB_port_prdata <= 32'hf0f00a0a;
                                        default                 :   APB_port_prdata <= 32'd0;
                                endcase
                        end
          end
        对应PS段程序如下:
        while(1)
        {
                recv = *(int*)0x43c01000;//PS从PL读数据
                *(int*)0x43c00000 = 0x12345678;//PS向PL写数据
                recv = *(int*)0x43c01004; //PS从PL读数据
                *(int*)0x43c00004 = 0x0abcdef9; //PS向PL写数据
        }
2.4  BRAM端口程序
        BRAM端口读写时序,PL端直接对接Block Memory Generator中的True Dual Port RAM。PS向PL写数据时,每个数据需要11个时钟周期,在50MHz的总线时钟速率下,其数据率为18MBps;PS从PL中读取数据时,每个数据需要16个时钟周期,在50MHz的总线时钟速率下,其数据率为12.5MBps。
对应PL端程序如下:
blk_mem_gen_0 u_blk_mem_gen_0 (
          .clka(BRAM_port_clk),        // input wire clka
          .ena(BRAM_port_en),          // input wire ena
          .wea(BRAM_port_we[0]),          // input wire [0 : 0] wea
          .addra(BRAM_port_addr[7:0]),  // input wire [7 : 0] addra
          .dina(BRAM_port_din),        // input wire [31 : 0] dina
          .douta(BRAM_port_dout),  // output wire [31 : 0] douta
          .clkb(),        // input wire clkb
          .enb(),          // input wire enb
          .web(),          // input wire [0 : 0] web
          .addrb(),  // input wire [7 : 0] addrb
          .dinb(),        // input wire [31 : 0] dinb
          .doutb()  // output wire [31 : 0] doutb
        );
对应PS端程序如下:
while(1)
{
            memset((void*)0x40000000,0,64);//向BRAM中写数据
            memcpy((void*)0x13000000,(void*)0x40000000,64);//从BRAM中读数据
}
2.5  GPIO中断程序
        GPIO中断需要在PL端产生一个至少一个时钟周期的高电平,PS端程序较为复杂, SDK中的system.mss中有例程可以进行参考,网上或AX7020开发板中附带的教程中均有详细的讲解,此处篇幅有限,不做详细介绍。
3  总结
        本文介绍了Zynq7000系列芯片的一种典型程序结构,这种结构具备一个外部中断,一个传输零散数据的低速接口,一个传输数据块的低速接口,其优点在于程序结构清晰、简单,可以满足大部分的常规应用,缺点在于数据传输率较低,无法满足高速数据传输,例如高速数据采集处理,HDMI显示等,对于这些需要高速数据传输的场合则需要采用DMA数据传输结构,其数据传输速率近似为总线时钟频率的4倍,即一个时钟周期传输4Byte数据,这种结构应用起来较为困难,还需读者们进行试验,探讨。

参考文献
[1]  何宾 张艳辉,Xilinx Zynq-7000嵌入式系统设计与实现,电子工业出版社 ,2016
投稿 打印文章 转寄朋友 留言编辑 收藏文章
  期刊推荐
1/1
转寄给朋友
朋友的昵称:
朋友的邮件地址:
您的昵称:
您的邮件地址:
邮件主题:
推荐理由:

写信给编辑
标题:
内容:
您的昵称:
您的邮件地址: