本文是AXI Direct Memory Access IP核在Direct Register模式下的实战例程,参考文档:
AXI Direct Memory Access IP核(1):AXI DMA深度解析_xilinx axi-dma-优快云博客
源代码:
【免费】AXI-DMAIP核实战:24路并行数据高速存储实战程序资源-优快云下载
1 概述
在FPGA开发中,经常需要处理多路并行数据的采集与存储。本文将分享一个实际项目案例:将24路24位并行数据通过AXI_DMA高效地存入BRAM中。这个设计方案已经在我们的项目中稳定运行,希望能为有类似需求的开发者提供参考。
2 系统架构


整个系统由以下几个关键模块组成:
-
数据产生模块:定时产生24路24位测试数据
-
并行数据转AXIS模块:核心数据转换逻辑
-
AXI_DMA IP核:实现AXIS到AXI4总线的转换
-
AXI_VIP:用于配置和控制AXI_DMA
-
BRAM控制器:管理BRAM存储空间
3 详细设计说明
3.1 数据产生模块
数据产生模块以50MHz时钟运行,每1us(50个时钟周期)产生一组完整的24路24位数据,主状态机控制流程如下,详细设计可以参考资源【免费】AXI-DMAIP核实战:24路并行数据高速存储实战程序资源-优快云下载
// 数据生成组合逻辑
always @(*) begin
data_in_0 = {(24'h300000 + base_value[23:0]), (24'h200000 + base_value[23:0]), (24'h100000 + base_value[23:0]), (24'h000000 + base_value[23:0])};
data_in_1 = {(24'h700000 + base_value[23:0]), (24'h600000 + base_value[23:0]), (24'h500000 + base_value[23:0]), (24'h400000 + base_value[23:0])};
data_in_2 = {(24'hB00000 + base_value[23:0]), (24'hA00000 + base_value[23:0]), (24'h900000 + base_value[23:0]), (24'h800000 + base_value[23:0])};
data_in_3 = {(24'hF00000 + base_value[23:0]), (24'hE00000 + base_value[23:0]), (24'hD00000 + base_value[23:0]), (24'hC00000 + base_value[23:0])};
data_in_4 = {(24'h130000 + base_value[23:0]), (24'h120000 + base_value[23:0]), (24'h110000 + base_value[23:0]), (24'h100000 + base_value[23:0])};
data_in_5 = {(24'h170000 + base_value[23:0]), (24'h160000 + base_value[23:0]), (24'h150000 + base_value[23:0]), (24'h140000 + base_value[23:0])};
end
// -------------- 控制状态机
reg [2:0] current_state,next_state;
always @(posedge data_clk or negedge data_rstn) begin
if (!data_rstn) begin
current_state <= IDLE;
end else begin
current_state <= next_state;
end
end
// -------------- 主状态机
always @ (*) begin
next_state = current_state;
case(current_state)
IDLE:begin
next_state <= DATA_GEN;
end
DATA_GEN:begin
next_state <= DATA_VALID;
end
DATA_VALID:begin
next_state <= DATA_WAIT;
end
DATA_WAIT:begin
if (cycle_counter == DATA_FRE-1) begin
next_state <= DATA_GEN;
end
else begin
next_state = current_state;
end
end
default:begin
next_state = IDLE;
end
endcase
3.2 并行数据转AXIS模块
这是整个设计的核心,内部主要包含两个状态机。
3.2.1 状态机1:接收并行数据并按通道写入FIFO
状态机设计:
-
IDLE状态:等待传输使能信号
-
COLLECT_V状态:等待数据valid信号
-
COLLECT_D状态:根据计数器将数据依次存入FIFO,如果存储的数据已经足够gpio_package_length,就返回IDEL状态,等待下一次传输。
关键逻辑实现:
/ -------------- 控制状态机
reg [2:0] current_state,next_state;
always @(posedge data_clk or negedge data_rstn) begin
if (!data_rstn) begin
current_state <= IDLE;
end else begin
current_state <= next_state;
end
end
// ------------ 主状态机
always @ (*) begin
next_state = current_state;
case(current_state)
IDLE:begin
if (data_wr_en_d0 & !data_wr_en_d1) begin
next_state = COLLECT_V;
end
end
COLLECT_V:begin
if (word_valid_d0 & !word_valid_d1) begin //全为1,上升沿检测
next_state = COLLECT_D;
end
else begin
next_state = current_state;
end
end
COLLECT_D:begin
if (Rec_count == gpio_packet_length_reg-1 ) begin
next_state = IDLE;
end
else if (ch_count == CH_NUM-1) begin //共24个通道
next_state = COLLECT_V;
end
else begin
next_state = current_state;
end
end
default:begin
next_state = IDLE;
end
endcase
end
3.2.2 状态机2:从FIFO中取数据并转为AXIS
状态机设计:
-
IDLE状态:等待传输使能信号
-
UPDATE_LENGTH状态:取本次应该传输的数据量。
-
PREPARE_DATA状态:从FIFO中取数据
-
TRANSFER状态:转为AXIS总线形式,如果取数据量不足gpio_package_length,就返回PREPARE_DATA状态继续取数据,如果数据已经足够gpio_package_length,就返回IDEL状态,等待下一次传输使能。
关键逻辑实现:
// 状态寄存器
always @(posedge m_axis_clk or negedge m_axis_rstn) begin
if (!m_axis_rstn) begin
current_state_r <= IDLE;
end else begin
current_state_r <= next_state_r;
end
end
// 状态转移逻辑
always @(*) begin
next_state_r = current_state_r;
case(current_state_r)
IDLE:begin
if (start_en_d0 & !start_en_d1) begin // recieve start flag
next_state_r = UPDATE_LENGTH;
end
end
UPDATE_LENGTH:begin
if (!fifo_rd_empty) begin // 当有数据需要传输时,先更新数据量
next_state_r = PREPARE_DATA;
end
end
PREPARE_DATA:begin
if (!fifo_rd_empty) begin //
next_state_r = TRANSFER;
end
end
TRANSFER:begin
if (axis_tready && axis_tvalid ) begin
if (trans_count == gpio_packet_length_reg - 1) begin // data trans finish
next_state_r = IDLE;
end
else begin
next_state_r = PREPARE_DATA;
end
end
end
endcase
end
3.3 AXI_VIP模块配置AXI_DMA模块
3.3.1 AXI_DMA的GUI配置
其使用的是通用DMA模式,只使能了S2MM通道。

3.3.2 AXI_VIP仿真激励
配置AXI_DMA的传输使能、中断、目的地址、数据长度。详细可查看AXI Direct Memory Access IP核(1):AXI DMA深度解析_xilinx axi-dma-优快云博客
之后拉起start_en,即告诉系统可以开始传输数据了。

当接收到AXI_DMA传输完成的中断的时候,清中断,之后重新配置AXI_DMA,使能start_en,发起下一次传输。

4 仿真结果
从下图可以看出,每隔一段时间,就会收到来资源前端的有效数据。

4.1 关于写FIFO:
当ADMA配置完成之后,会拉起start_en;
当 数据转换模块检测到 start_en之后,开始检测有效数据
当 检测到有效数据valid之后,将数据写入fifo

当写入数据量,足够我们要求的数据量时(本次是1024个32bit),停止写入

以上为写FIFO的工作流程
4.2 关于读FIFO:
当ADMA配置完成之后,会拉起start_en;
当 数据转换模块检测到 start_en之后,开始等待FIFO有数据
当 检测到FIFO有数据之后,从FIFO中取数据

取够我们所需要的数据量之后,tlast拉起,停止取数

因为我们写入的数据量 和 取走的数据量是一致的,故我们可以看到到最后一拍的时候我们的fifo是empty的状态

4.3 仿真结论:
通过trans count我们也可以看出,我们的parallel_to_axis_converter,每次发出的数据均是1024个32bit,一个tlast信号。

我们再来看看ADMA端
ADMA端,1024个数据一个Tlast信号,之后数据转为AXI4存入ram,然后拉起adma的中断。

最后再来看看存入RAM的数据,因为我每次都是从0x000地址开始的,然后递增的方式存进去。
所以可以根据BRAM中的数据写入情况来查看。

3847

被折叠的 条评论
为什么被折叠?



