这个模块预实现一个高级直接内存访问 (DMA) 控制器,用于在高速外设和 DDR3 内存之间进行高效数据传输。它支持突发传输模式,可以批量处理数据块,减少 CPU 干预,提高系统性能
DMA(Direct Memory Access,直接内存访问) 是一种无需 CPU 直接参与,允许外设(如硬盘、网卡、传感器等)与内存之间直接进行数据传输的技术。它通过专用的 DMA 控制器(DMAC)接管总线控制权,实现高速、高效的数据搬运,显著减轻 CPU 负担,提升系统整体性能。(具体详细讲解见前文)
在 DDR3 内存控制器中,配置突发长度(Burst Length) 是指设置一次连续内存访问操作中传输的数据块大小。DDR3 采用突发传输模式,一旦启动传输,会自动连续传输多个数据块,无需每次都重新发送地址和控制信号,从而显著提高传输效率。
DDR3 的突发传输机制类似于 "批量处理":
例如,设置突发长度为 8 时,控制器会从指定地址开始,连续传输 8 个数据块(每个数据块大小取决于总线宽度)。
同时例如,当burst_size=4
时,DDR3 会从起始地址开始,连续传输 4 个数据块,地址依次为:
起始地址 → 起始地址+32 → 起始地址+64 → 起始地址+96
(假设每个数据块 32 字节)。
BURST_START: begin
if (ddr3_req_ready) begin
ddr3_start_addr <= current_addr; // 记录当前突发的起始地址
burst_count <= burst_size;
current_addr <= current_addr + (burst_size * 32); // 256位 = 32字节
end
end
功能:
0x1000
开始,burst_size=4
,则下一个突发的起始地址为0x1000 + 4*32 = 0x1080
。burst_size * 32
)。DDR3 的突发传输是原子性的,一旦启动,必须完成整个burst_size
的数据传输。因此,在开始时就更新地址到下一个突发的起点,确保后续数据连续写入。
BURST_TRANSFER: begin//处理单个数据块
if (ddr3_req_ready && burst_count > 0) begin
burst_count <= burst_count - 1;//每完成一个 256 位数据块传输,突发计数器减 1
bytes_transferred <= bytes_transferred + 32;//在此处累加已传输字节数
end
end
功能:
0x1000
,下一个数据块地址为0x1032
。在突发传输过程中,DDR3 内部会自动递增地址,但代码中需要维护一个逻辑地址(current_addr
),用于跟踪下一个数据块的位置。这个地址仅用于内部计数,不影响 DDR3 的实际突发传输。
//DMA控制模块
module advanced_dma (
input clk,
input reset_n,
input start_dma,//控制信号,启动DMA传输
input [31:0] src_addr,//源地址
input [31:0] dest_addr,//目标地址
input [31:0] transfer_len,//传输长度
input [7:0] burst_size, // 突发配置,2^n 字节突发长度,它表示每次突发传输的数据块数量最大为8
input [255:0] data_in,//256 位(32 字节),因此每次传输的数据块大小为 32 字节。
input data_in_valid,
output data_in_ready,
//下列为DDR3状态接口
output reg [255:0] ddr3_wdata,
output reg [31:0] ddr3_addr,
output reg [31:0] ddr3_burst_len,
output reg ddr3_write_en,
output reg ddr3_req_valid,
input ddr3_req_ready,
output reg dma_done,
output reg dma_error
);
// DMA状态机
localparam IDLE = 4'd0,//IDLE: 空闲状态,等待启动命令
CONFIGURE = 4'd1,//配置DMA参数
WAIT_DATA = 4'd2,//等待有效数据输入
BURST_START = 4'd3,//开始突发传输
BURST_TRANSFER = 4'd4,//进行突发传输
BURST_END = 4'd5,//结束突发传输
COMPLETE = 4'd6,//传输完成状态
ERROR = 4'd7;//错误状态
reg [3:0] state, next_state;
reg [31:0] bytes_transferred;//记录已传输字节数
reg [31:0] current_addr;//指向当前的传输位置
reg [31:0] ddr3_start_addr; // 记录当前突发的起始地址
reg [7:0] burst_count;//定义突发剩余数据块计数器
reg dma_active;//指示DMA是否处于活跃状态
// 状态机寄存器
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= IDLE;
bytes_transferred <= 0;
current_addr <= 0;
burst_count <= 0;
dma_active <= 0;
dma_done <= 0;
dma_error <= 0;
end else begin
state <= next_state;
case (state)
IDLE: begin
if (start_dma) begin
current_addr <= dest_addr;//将当前传输位置指向目标地址
bytes_transferred <= 0;
dma_active <= 1;
dma_done <= 0;
dma_error <= 0;
end
end
CONFIGURE: begin
// 配置突发长度
ddr3_burst_len <= burst_size;
end
BURST_START: begin
if (ddr3_req_ready) begin
ddr3_start_addr <= current_addr; // 记录当前突发的起始地址
burst_count <= burst_size;
current_addr <= current_addr + (burst_size * 32); // 256位 = 32字节
//bytes_transferred <= bytes_transferred + (burst_size * 32);
end
end
BURST_TRANSFER: begin//处理单个数据块
if (ddr3_req_ready && burst_count > 0) begin
burst_count <= burst_count - 1;//每完成一个 256 位数据块传输,突发计数器减 1
//current_addr <= current_addr + 32; // 256位 = 32字节
bytes_transferred <= bytes_transferred + 32;//在此处累加已传输字节数
end
end
COMPLETE: begin
dma_active <= 0;
dma_done <= 1;
end
ERROR: begin
dma_active <= 0;
dma_error <= 1;
end
endcase
end
end
// 状态机逻辑
always @(*) begin
next_state = state;
case (state)
IDLE: begin
if (start_dma)
next_state = CONFIGURE;
end
CONFIGURE: begin
next_state = WAIT_DATA;
end
WAIT_DATA: begin
if (data_in_valid)
next_state = BURST_START;
end
BURST_START: begin
if (ddr3_req_ready)
next_state = BURST_TRANSFER;
end
BURST_TRANSFER: begin
if (ddr3_req_ready && burst_count == 0) begin
if (bytes_transferred >= transfer_len)//当实际的传输字节数到达传输长度时
next_state = COMPLETE;
else
next_state = WAIT_DATA;
end
end
COMPLETE: begin
if (!start_dma)
next_state = IDLE;
end
ERROR: begin
if (!start_dma)
next_state = IDLE;
end
default: next_state = IDLE;
endcase
end
// DDR3接口控制
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
ddr3_wdata <= 0;
ddr3_addr <= 0;
ddr3_write_en <= 0;
ddr3_req_valid <= 0;
end else begin
case (state)
BURST_START: begin
ddr3_wdata <= data_in;
ddr3_addr <= ddr3_start_addr; // 使用记录的突发起始地址
ddr3_write_en <= 1;
ddr3_req_valid <= 1;
end
BURST_TRANSFER: begin
ddr3_wdata <= data_in;
// 注意:DDR3控制器会自动递增地址,此处无需更新ddr3_addr
ddr3_write_en <= 1;
ddr3_req_valid <= 1;
end
default: begin
ddr3_wdata <= 0;
ddr3_addr <= 0;
ddr3_write_en <= 0;
ddr3_req_valid <= 0;
end
endcase
end
end
// 数据输入控制
assign data_in_ready = (state == WAIT_DATA || (state == BURST_TRANSFER && burst_count > 0)) && !dma_error;
// 错误检测
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
dma_error <= 0;
end else begin
if (bytes_transferred > transfer_len)
dma_error <= 1;
else if (state == ERROR)
dma_error <= 1;
end
end
endmodule
突发传输机制
burst_size
),允许一次连续传输多个数据块(如 32 字节 / 块),大幅减少 DDR3 接口的控制开销。双缓冲区地址管理
current_addr
预计算下一个突发的起始地址,同时使用 ddr3_start_addr
保存当前突发的实际起始地址,实现无缝的连续传输。BURST_TRANSFER
状态中,DDR3 控制器自动递增地址,而模块仅需跟踪逻辑进度(burst_count
)。精确的字节计数
BURST_TRANSFER
)递增 bytes_transferred
,避免预计算导致的计数错误。transfer_len
实时比较,确保传输长度不超过预设值。完整的状态机控制
data_in_ready
)和传输完成(dma_done
)的精确控制。预计算下一个突发地址
BURST_START
状态中提前计算下一个突发的起始地址(current_addr += burst_size*32
),减少状态切换延迟,适合高速数据流场景。分离物理地址与逻辑地址
ddr3_start_addr
存储当前突发的物理起始地址,用于 DDR3 接口控制。current_addr
作为逻辑指针,预指向下一个突发的起始地址,使状态机可以提前准备下一次传输。错误检测与恢复机制
bytes_transferred
,防止传输长度越界。dma_error
标志反馈异常状态,支持系统快速响应。数据流控制优化
data_in_ready
信号精确控制数据输入时机,确保缓冲区不会溢出。高速数据采集系统
从 ADC(模数转换器)以 40MSPS 速率采样数据,通过 DMA 快速传输到 DDR3 内存,避免数据丢失。实时信号处理
将传感器数据批量传输到内存,供 DSP 或 FPGA 进行后续处理(如滤波、FFT 变换)。视频 / 图像处理
高效传输大尺寸图像帧或视频流,利用突发模式提高带宽利用率。网络数据收发
在网络接口与内存之间快速搬运数据包,减少 CPU 干预,提高系统吞吐量。高吞吐量
通过突发传输和预计算地址,减少 DDR3 接口的空闲时间,接近理论带宽上限。低延迟
状态机设计优化了传输流程,减少了状态切换和等待时间。资源高效
仅需少量寄存器(current_addr
、ddr3_start_addr
、burst_count
)实现复杂的地址管理,硬件成本低。可扩展性
状态机架构清晰,易于扩展支持更多功能(如读操作、循环缓冲区、多通道传输)。