目录
第一部分、AXI总线的相关知识
1、ZYNQ架构
2、AXI 总线和 AXI 接口以及 AXI 协议
3、AXI 总线与 ZYNQ 的关系
4、AXI 总线介绍
5、AXI 接口介绍
6、AXI 协议介绍
7、AXI高效传输的原因
8、常见总线汇总
9、HP接口写时序配置
10、HP DDR的地址分配
11、缓存一致性的问题
12、跨时钟域数据传输问题
12.1、单bit数据
慢到快:
快到慢:
12.2、多bit数据
第二部分、AXI HP接口的使用
1、HP口的封装
2、ZYNQ HP口的配置
3、IP核的调用以及连线
4、HP 口的读写时序
4.1、读时序
4.2、写时序
第三部分、总结
1、写在前面
2、工程链接
第一部分、AXI总线的相关知识
这里的知识部分来源于米联客实验手册部分来源于个人总结,想知道更多细节请参考这本书《ZYNQ 修炼秘籍裸机篇 2019 版》。
1、ZYNQ架构
ZYNQ 拥有 ARM+FPGA 这个神奇的架构, ARM 和 FPGA 通过 AXI4 总线进行通信。
2、AXI 总线和 AXI 接口以及 AXI 协议
总线、接口和协议,这三个词经常被联系在一起, 但是三者有区别。
(1)、总线:是一组传输通道,是各种逻辑器件构成的传输数据的通道,一般由数据线、地址线、控制线等构成。
(2)、接口:是一种连接标准,又被称为物理接口。(AXI-GP 接口, AXI-HP 接口以及 AXI-ACP 接口)
(3)、总线协议:就是传输数据的规则(AXI4-Lite, AXI4 和 AXI4-Stream )。
这里需要特别说明一下 AXI 总线和 AXI 接口的关系。在 ZYNQ 中,支持 AXI4-Lite, AXI4 和 AXI4-Stream 三种总线协议,需要注意的是 PS 与 PL 之间的接口(AXI-GP 接口, AXI-HP 接口以及 AXI-ACP 接口)只支持 AXI4-Lite和 AXI 4协议这两种总线协议。
也就是说 PL 这边的 AXI-Stream 的接口是不能直接与 PS 对接的,需要经过 AXI4 或者 AXI4-Lite 的转换。比如后面将用到的 VDMA IP ,它就实现了在 PL 内部 AXI4 到 AXI-Stream 的转换, VDMA利用的接口就是 AXI-HP 接口。(区别于我的设计:我的设计没有调用VDMA 这个IP核,而是直接通过改写AXI HP接口的读写时序来实现的,但功能应该核VDMA类似)。
3、AXI 总线与 ZYNQ 的关系
AXI(Advanced eXtensible Interface)本是由 ARM 公司提出的一种总线协议, Xilinx 从 6 系列的 FPGA 开始对 AXI 总线提供支持,此时 AXI 已经发展到了 AXI4 这个版本,所以当你用到 Xilinx 软件的时候看到的都是“AIX4” 的 IP,如 Vivado 打包一个 AXI IP 的时候,看到的都是 Create a new AXI4 peripheral。
4、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.)面向高速流数据传输;去掉了地址项,允许无限制的数据突发传输规模。
5、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 接口
6、AXI 协议介绍
协议和总线关系密切,协议要在总线的结构上制定。虽然说 AXI4, AXI4-Lite, AXI4-Stream 都是 AXI4 协议, 但是各自细节上还是不同的。
总的来说, AXI 总线协议的两端可以分为分为主(master)、从(slave)两端,他们之间一般需要通过一个 AXI Interconnect 相连接,作用是提供将一个或多个 AXI 主设备连接到一个或多个 AXI 从设备的一种交换机制。当我们添加了 zynq 以及带 AXI 的 IP 后再进行自动连线时,vivado 会自动帮我们添加上这个 IP。
AXI Interconnect的主要作用是,当存在多个主机以及从机器时, AXI Interconnect负责将它们联系并管理起来。 由于 AXI 支持乱序发送,乱序发送需要主机的 ID 信号支撑,而不同的主机发送的 ID 可能相同,而 AXI Interconnect 解决了这一问题,他会对不同主机的 ID 信号进行处理让 ID 变得唯一。
7、AXI高效传输的原因
(1)、AXI 协议将读地址通道,读数据通道,写地址通道,写数据通道,写响应通道分开,各自通道都有自己的握手 协议。每个通道互不干扰却又彼此依赖。
(2)、支持乱序操作。
8、常见总线汇总
AXI、AHB、APB(下面是嫖过来的截图)
9、HP接口写时序配置
最大数据位宽:64bitByte
最大同步时钟:250MHz
最大突发长度:256
10、HP DDR的地址分配
只有0008_0000to3fff_ffff才映射在DDR,而0000——0000to0003——ffff映射在OCM上。
1KB = 1024 Bytes = 0x400
1MB = 1024 KB = 0x10_0000
1GB = 1024MB = 0x4000_0000
下图:AXI HP接口能访问DDR的大小为8_0000 - 3FFF_FFFF刚好是1GB
11、缓存一致性的问题
提到缓存一致性,我就想到这篇文章:“不会被封的外挂”,为何使用FPGA作为FPS游戏的“DMA”桥梁 (qq.com)
由上面ZYNQ的架构图可以知道,PL端的4个AXI HP接口直接连接着AMBA 总线,而AMBA又是直接连接着DDR3,这中间没有任何其他的存储设备。因此,PL端通过AXI的HP口可以直接访问DDR,而不需要经过CPU的约束。
AMBA是由ARM公司研发的一种高级微控制器总线架构(Advanced Microcontroller Bus Architecture)。其中AMBA包含了四种不同的总线标准,分别是:AHB、ASB、APB、AXI
而在多级存储器结构中,CPU 通过1级或多级 Cache 与 DDR 产生连接, CPU 本身不直接访问 DDR,而是通过 Cache 访问 DDR。 Cache 中始终会暂存一小部分(通常是几KB~几MB量级) CPU 最近访问的 DDR 某些地址区域中的数据。因此,在应用程序中对 DDR 进行读或写操作, 实际上都是 CPU 对 Cache进行读或写操作。
因此缓存一致性的问题就是:当 DDR 中某个地址范围内的数据突然被除 CPU 以外的 Master(如 DMA)改变时, 若此时 Cache中保存了这些区域的数据,且这些数据在 Cache 中状态为有效时,当 CPU 需要再次读取 DDR 这片区域的数据时,就不会让 Cache 去读取 DDR 中此区域内最新的数据来更新 Cache, 再从 Cache 里读取最新的数据, 而是直接从 Cache中读取原来的旧数据, 显然这不是我们所期望的结果。
ZYNQ 中存在 ICache 和 DCache, ICache 用于缓存可执行程序, DCache 用于缓存数据。 一般情况下, 用于保存可执行程序的 DDR 地址范围不会被除 CPU 以外的对象访问。 因此, 一般不存在 ICache 的一致性问题。 而 DCache在很多应用中却经常会被除 CPU 以外的对象访问,所以存在一致性问题。
ZYNQ 中维护 DCache 一致性的方法有两种:
第一种暴力的:直接把Cache关了,CPU不用Cache。
第二种不暴力的: 刷新Cache,重新载入DDR数据。
12、跨时钟域数据传输问题
在AXI总线的时钟一般都比较高,最高可到250MHz。因此在实际使用中都会存在慢速数据到快速数据的一个转换过程,因此这里简单介绍一下跨时钟域数据的传输问题。
12.1、单bit数据
一般是一些标志信号或者使能信号。
慢到快:
将慢速数据在快时钟域下打两拍。打两拍的目的是将慢时钟域信号同步到快时钟域。
快到慢:
(展宽法) 跨时钟域传输和Verilog代码-CSDN博客
将快脉冲在快时钟域下展宽,然后慢时钟去捕获,捕获四次,前两次的&输出慢脉冲,最后一次的高拉低展宽信号。
注意事项:
- 结绳法适合采样数据少(信号脉冲间隔大)的信号;
- 脉冲间隔应该大于3个慢时钟域时钟周期
- 等待3拍后,才能完成复位,允许下一个输入脉冲同步。
Verilog代码
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN : 大屁桃
// E-mail : 2624507313@qq.com
// File : slow2fast.v
// Create : 2023-12-06 10:54:34
// -----------------------------------------------------------------------------
module slow2fast(input wire rst,input wire clk_50MHz,input wire clk_200MHz,input wire fast_pulse,output wire slow_pulse,output wire widen_flag_see);reg widen_flag;//展宽信号
reg capture_widen,capture_widen_old;//慢时钟域捕获快时钟
reg capture_widen2,capture_widen_old2;//慢时钟域捕获快时钟assign widen_flag_see = widen_flag;//展宽信号
always @(posedge clk_200MHz or posedge rst) beginif (rst == 1'b1) beginwiden_flag <= 1'b0;endelse if(capture_widen_old2 == 1'b1) beginwiden_flag <= 1'b0;endelse if (fast_pulse == 1'b1) beginwiden_flag <= 1'b1;end
end//将展宽信号同步回低频时钟
always @(posedge clk_50MHz or posedge rst) beginif (rst == 1'b1) begin{capture_widen_old,capture_widen} = {1'b0,1'b0};endelse begin{capture_widen_old,capture_widen} = {capture_widen,widen_flag};end
endalways @(posedge clk_50MHz or posedge rst) beginif (rst == 1'b1) begin{capture_widen_old2,capture_widen2} = {1'b0,1'b0};endelse begin{capture_widen_old2,capture_widen2} = {capture_widen2,capture_widen_old};end
end//低频脉冲
assign slow_pulse = (~capture_widen_old) & capture_widen;endmodule
仿真代码
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : BigFartPeach
// CSDN : 大屁桃
// E-mail : 2624507313@qq.com
// File : tb_fast2slow.v
// Create : 2023-12-06 11:12:27
// -----------------------------------------------------------------------------
`timescale 1ns/1psmodule tb_fast2slow();reg rst;
reg clk_50MHz,clk_200MHz;
reg fast_pulse;
wire slow_pulse,widen_flag_see;initial beginrst = 1;fast_pulse = 0;clk_50MHz = 0;clk_200MHz = 0;#102.5;rst = 0;fast_pulse = 1;#5fast_pulse = 0;
endalways #2.5 clk_200MHz = ~clk_200MHz;
always #10 clk_50MHz = ~clk_50MHz;slow2fast inst_slow2fast(.rst (rst),.clk_50MHz (clk_50MHz),.clk_200MHz (clk_200MHz),.fast_pulse (fast_pulse),.slow_pulse (slow_pulse),.widen_flag_see (widen_flag_see));endmodule
仿真代码的波形
12.2、多bit数据
目前遇到的方法就是采用异步fifo。
第二部分、AXI HP接口的使用
这里通过自行修改的AXI HP IP的方式来实现对DDR3的访问,实际过程中可以通过调用vivado内部VDMA IP来实现。
1、HP口的封装
第一步、创建一个AXI4的IP
第二步、新建名称,注意,IP的路径要选择当前的工程下的文件夹
第三步、由于这里是建立HP端口,因此这里接口类型要选择 Full模式,接口模式为Master主机模式。因为HP口只能PL做主机。
注意:这里的数据位宽还修改不了,需要后面通过编辑IP的方式修改数据位宽。最大为位宽就是64bit
第四步、选择Edit IP,修改内部代码等。(不同的时序代码不同,具体参考第2小节)
第五步、修改IP基地址、突发长度、数据位宽(单次传输的数据位宽),最后封装IP
2、ZYNQ HP口的配置
第一步、打开PL clock 200M(HP口最高为250M,但是这里还是配置为200M)
第二步、打开一个复位端口
第三步、打开HP0口,位宽64bit
3、IP核的调用以及连线
这里的时钟配置为200M,虽然HP口最高为250M,但是这里还是配置为200M。
注意:整个工程,只有时钟没有拉到最高配置(这里200M,最高250M)。HP口的最大位宽(64bit)和突发长度(256),都拉到了最大。
HP IP核连接时钟后,其它的都可以自动连接。Run Connection Automation。
4、HP 口的读写时序
通过修改读写代码来实现自己想要实现的功能。正常情况下都需要异步fifo来缓存数据,因此代码在不同的场景不一致。
4.1、读时序
读数据的时序
读数据数据的波形,由下图我们可以知道,AXI 总线去DDR3内读取数据的时候,先给地址赋值,赋值结束后,数据就源源不断的过来,直到突发长度的最后一个。
4.2、写时序
写数据时序
第三部分、总结
1、写在前面
该篇文章介绍AXI总线的相关知识、缓存一致性原理、单bit数据跨时钟域传输问题、包括AXI HP口封装原理等。
主要是我调试过程中的笔记,但是希望能够给你提供一定的思路。
2、工程链接
这篇文章的内容是为了这篇文章的内容做铺垫,关于工程下载链接以及实验现象,请参考这篇文章【ZYNQ实验】第一篇、ZYNQ驱动HDMI显示图片-CSDN博客