1,AXI总线与AXI接口以及AXI协议
总线,接口和协议,总线是一组传输通道,是各种逻辑器件构成的传输数据的通道,一般由数据线,地址线,控制线等组成。接口是一种连接标准,有常常被称之为物理接口。协议就是传输数据的规则。
1.1 AXI总线概述
在ZYNQ中支持三种AXI总线,拥有三种AXI接口,当然用的都是AXI协议。其中三种AXI总线分别为:
AXI4:(For high-performance memory-mapped requirements)主要面向高性能地址映射通信的需求,是面向地址映射的接口,允许最大256轮的数据突发传输;
AXI4-Lite:(For simple,low-throughput memory-mapped communication)是一个轻量级的地址映射单此传输接口,占用很少的逻辑单元。
AXI4-Stream:(For high-speed streaming data)面向高速流数据传输;去掉了地址项,允许无限制的数据突发传输规模。
首先说AXI4总线和AXI4-Lite总线具有相同的组成部分:
(1)读地址通道,包含ARVALID,ARADDR,ARREADY信号;
(2)读数据通道,包含RVALID,RDATA,RREADY,RRESP信号;
(3)写地址通道,包含AWVALID,AWADDR,AWREADY信号;
(4)写数据通道,包含WVALID,WDATA,WSTRB,WREADY信号;
(5)写应答通道,包含BVALID,BRESP,BREADY信号;
(6)系统通道,包含ACLK,ARESETN信号。
AXI4-Stream总线的组成有:
(1),ACL信号:总线时钟,上升沿有效;
(2),ARESETN信号:总线复位,低电平有效;
(3),TREADY信号:从机告诉主机做好传输准备了;
(4),TDATA信号:数据,可选宽度为32,64,128,256bit;
(5),TSTRB信号:每一位Bit对应TDATA的一个有效字节,宽度为TDATA/8;
(6),TLAST信号:主机告诉从机该次传输为突发传输的结尾;
(7),TVALID信号:主机告诉从机数据本次传输有效;
(8),TUSER信号:用户定义信号,宽度为128bit
1.2 AXI接口介绍三种AXI接口分别是:
AXI-GP接口(4个):是通用的AXI接口,包括两个32位主设备接口和两个32位从设备接口,用该接口可以访问PS中的片内外设。
AXI-HP接口(4个):是高性能/带宽的标准的接口,PL模块作为主设备连接。主要用于PL访问PS上的存储器(DDR和on-chip ram)
AXI-ACP接口(1个):是ARM多核架构下定义的一种接口,中文翻译为加速器一致性端口,用来管理DMA之类的不带缓存的AXI外设,PS端是Slave接口。
我们可以双击查看ZYNQ的IP核的内部配置,就能发现上述的三种接口,图中已用红色方框标记出来,我们可以清楚的看出接口连接与总线的走向:
1.3 AXI协议概述
AXI总线协议的两端可以分为主(master),从(slave)两端,他们之间一般需要通过一个AXI Interconnect相连接,作用是提供将一个或多个AXI主设备连接到一个或多个AXI从设备的一种交换机制。当存在多个主机以及从机时,AXI Interconnect负责将它们联系并管理起来。由于AXI支持乱序传送,乱序传送需要主机的ID信号支撑,而不同的主机发送的ID可能不同,而AXI Interconnect解决了这一问题,他会对不同主机的ID信号进行处理让ID变得唯一。
AXI协议将读地址通道,读数据通道,写地址通道,写数据通道,写响应通道分开,各自通道都有自己的握手协议。每个通道互不干扰却又彼此依赖。这也是AXI高效的原因之一。
1.4 AXI协议之握手协议
AXI4所采用的是一种READY,VALID握手通信机制,简单来说主从双方进行数据通信前,有一个握手的过程。传输源产生VALID信号来指明何时数据或控制信息有效。而目的源产生READY信号来指明已经准备好接受数据或控制信息。传输发生在VALID和READY信号同时为高的时候。VALID和READY信号的出现有三种关系。
(1)VALID先变高READY后变高。时序图如下:
(2)READY先变高VALID后变高。时序图如下:
(3)VALID和READY信号同时变高。时序图如下:
1.5 突发式读写
1,突发式读的时序图如下:
当地址出现在地址总线后,传输的数据将出现在读数据通道上。设备保持VALID为低直到读数据有效。为了表明一次突发式读写的完成,设备用RLAST信号来表示最后一个被传输的数据。
2,突发式写的时序如下:
这一过程的开始,主机发送地址和控制信息到写地址通道中,然后主机发送每一个写数据到写数据通道中。当主机发送最后一个数据时,WLAST信号就变为高。当设备接受完所有数据之后他将一个写响应发送回主机来表明写事务完成。
2 AXI4-Lite详解
2.1 AXI4-Lite源码查看
Step1:要看到AXI-Lite的源码,我们先要自定义一个AXI-Lite的IP,新建工程之后,选择,菜单栏->Tools->Creat and Package IP:
Step2:选择Next
Step3:选择Create AXI4 Peripheral,然后Next:
Step4:默认,选择Next
Step5:注意这里接口类型选择Lite,选择Next:
Step6:选择Edit IP,点击Finish:
Step7:此后,Vivado会新建一个工程,专门编辑该IP,通过该工程,我们就可以看到Vivado为我们生成的AXI-Lite的操作源码:
2.2 AXI-Lite源码分析
当打开顶层文件的时,映入眼帘的是一堆AXI的信号,这些信号是否似曾相识?
我们先来看一段WDATA相关的代码:
这段程序的作用是,当PS那边向AXI4-Lite总线写数据时,PS这边负责将数据接收到寄存器slv_reg。而slv_reg寄存器有0~3共4个。至于赋值给哪一个由axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]决定,根据宏定义其实就是由
axi_awaddr[3:2] (写地址中不仅包含地址,而且包含了控制位,这里的[3:2]就是控制位)决定赋值给哪个slv_reg。
PS调用写函数时,如果不做地址偏移的话,axi_awaddr[3:2]的值默认是为0的,举个例子,如果我们自定义的IP的地址被映射为0x43C00000,那么我们Xil_Out32(0x43C00000,Value)写的就是slv_reg0的值。如果地址偏移4位,如Xil_Out32(0x43C00000 + 4,Value) 写的就是slv_reg1的值,依次类推。分析时只关注slv_reg0(其他结构上也是一模一样的):
其中,C_S_AXI_DATA_WIDTH的宏定义的值为32,也就是数据位宽,S_AXI_WSTRB就是写选通信号,S_AXI_WDATA就是写数据信号。
存在于for循环中的最关键的一句:slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
当byte_index = 0的时候这句话就等价于:slv_reg0[7:0] <= S_AXI_WDATA[7:0];
当byte_index = 1的时候这句话就等价于:slv_reg0[15:8] <= S_AXI_WDATA[15:8];
当byte_index = 2的时候这句话就等价于:slv_reg0[23:16] <= S_AXI_WDATA[23:16];
当byte_index = 3的时候这句话就等价于:slv_reg0[31:24] <= S_AXI_WDATA[31:24];
也就是说,只有当写选通信号为1时,它所对应S_AXI_WDATA的字节才会被读取。
读懂了这段话之后,我们就知道了,如果我们想得到PS写到总线上的数据,我们只
需要读取slv_reg0的值即可。
那如果,我们想写数据到总线让PS读取该数据,我们该怎么做呢?我们继续来看有
关RADTA读数据代码:
观察可知,当PS读取数据时,程序会把reg_data_out复制给axi_rdata(RADTA读数据)。我们继续追踪reg_data_out:
和前面分析的一样此时通过判断axi_awaddr[3:2]的值来判断将那个值给reg_data_out上,同样当PS调用读取函数时,这里axi_awaddr[3:2]默认是0,所以我们只需要把slv_reg0替换成我们自己数据,就可以让PS通过总线读到我们提供的数据。
和前面分析的一样此时通过判断axi_awaddr[3:2]的值来判断将那个值给reg_data_out上,同样当PS调用读取函数时,这里axi_awaddr[3:2]默认是0,所以我们只需要把slv_reg0替换成我们自己数据,就可以让PS通过总线读到我们提供的数据。
写应答,主要是回复主机你这个写过程是没有问题的,那读为什么不需要这个过程呢?
写应答,主要是回复主机你这个写过程是没有问题的,那读为什么不需要这个过程呢?这时因为主机在读取数据时,从机可以直接通过读数据通道给主机反馈信息,因此就没有必要再来开辟一个单独的应答通道了。
小结:
如果我们想读AXI4_Lite总线上的数据时,只需关注slv_reg的数据,我们可自行添加一段代码,如:
如果我们想对AXI4_Lite信号写数据时,我们只需修改对reg_data_out的赋值,如:
最后强调下如果我们自定义的IP的地址被映射为0x43C00000,那么我们Xil_Out32(0x43C00000,Value)写的就是slv_reg0的值。如果地址偏移4位,如Xil_Out32(0x43C00000 + 4,Value) 写的就是slv_reg1的值,依次类推。
目前这里只有4个寄存器,那是因为之前选择的是4个,其实我们可以定义的更多:
在ps的头文件里可以看到我们自定义的IP的地址是有个范围的
理论上只要基地址 + 偏移量不要超过HIGHADDR即可。
总结:
在ZYNQ中,支持AXI4-Lite,AXI4和AXI4-Stream三种总线协议,然而PS与PL之间的接口(AXI-GP接口,AXI-HP接口以及AXI-ACP接口)却只支持AXI-Lite和AXI协议这两种总线协议。也就是说PL这边的AXI-Stream的接口是不能直接与PS对接的,需要经过AXI4或者AXI4-Lite的转换。