这个模块预实现一个高级直接内存访问 (DMA) 控制器,用于在高速外设和 DDR3 内存之间进行高效数据传输。它支持突发传输模式,可以批量处理数据块,减少 CPU 干预,提高系统性能
DMA(Direct Memory Access,直接内存访问) 是一种无需 CPU 直接参与,允许外设(如硬盘、网卡、传感器等)与内存之间直接进行数据传输的技术。它通过专用的 DMA 控制器(DMAC)接管总线控制权,实现高速、高效的数据搬运,显著减轻 CPU 负担,提升系统整体性能。(具体详细讲解见前文)
在 DDR3 内存控制器中,配置突发长度(Burst Length) 是指设置一次连续内存访问操作中传输的数据块大小。DDR3 采用突发传输模式,一旦启动传输,会自动连续传输多个数据块,无需每次都重新发送地址和控制信号,从而显著提高传输效率。
突发传输的工作原理
DDR3 的突发传输机制类似于 "批量处理":
- 单次命令,多次传输:发送一次地址和控制命令后,内存控制器会自动连续传输多个数据块。
- 固定步长:数据按顺序从起始地址开始,以固定间隔(通常是 8 字节或 16 字节)递增传输。
- 无额外延迟:突发期间无需重新发送地址和命令,减少了总线开销。
例如,设置突发长度为 8 时,控制器会从指定地址开始,连续传输 8 个数据块(每个数据块大小取决于总线宽度)。
同时例如,当burst_size=4
时,DDR3 会从起始地址开始,连续传输 4 个数据块,地址依次为:
起始地址 → 起始地址+32 → 起始地址+64 → 起始地址+96
(假设每个数据块 32 字节)。
1. BURST_START 状态
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
的数据传输。因此,在开始时就更新地址到下一个突发的起点,确保后续数据连续写入。
2. BURST_TRANSFER 状态
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
功能:
- 处理突发传输中的单个数据块(256 位 = 32 字节)。
- 地址更新:每次只增加一个数据块的大小(32 字节)。
例如,当前数据块地址为0x1000
,下一个数据块地址为0x1032
。 - 字节计数:每次传输一个数据块,计数增加 32 字节。
- 负责监控突发进度,逐块传输数据,更新逻辑地址。
在突发传输过程中,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 接口的控制开销。 - 利用 DDR3 的突发模式特性,在单次命令后自动连续传输数据,提高带宽利用率。
- 支持配置突发长度(
-
双缓冲区地址管理
- 通过
current_addr
预计算下一个突发的起始地址,同时使用ddr3_start_addr
保存当前突发的实际起始地址,实现无缝的连续传输。 - 在
BURST_TRANSFER
状态中,DDR3 控制器自动递增地址,而模块仅需跟踪逻辑进度(burst_count
)。
- 通过
-
精确的字节计数
- 仅在实际传输数据时(
BURST_TRANSFER
)递增bytes_transferred
,避免预计算导致的计数错误。 - 与
transfer_len
实时比较,确保传输长度不超过预设值。
- 仅在实际传输数据时(
-
完整的状态机控制
- 包含 8 个状态(IDLE、CONFIGURE、WAIT_DATA、BURST_START、BURST_TRANSFER、BURST_END、COMPLETE、ERROR),覆盖 DMA 操作的全生命周期。
- 实现数据就绪(
data_in_ready
)和传输完成(dma_done
)的精确控制。
独特设计之处
-
预计算下一个突发地址
- 在
BURST_START
状态中提前计算下一个突发的起始地址(current_addr += burst_size*32
),减少状态切换延迟,适合高速数据流场景。 - 与 DDR3 控制器的硬件特性深度配合,充分利用突发传输的效率优势。
- 在
-
分离物理地址与逻辑地址
ddr3_start_addr
存储当前突发的物理起始地址,用于 DDR3 接口控制。current_addr
作为逻辑指针,预指向下一个突发的起始地址,使状态机可以提前准备下一次传输。
-
错误检测与恢复机制
- 实时监控
bytes_transferred
,防止传输长度越界。 - 通过
dma_error
标志反馈异常状态,支持系统快速响应。
- 实时监控
-
数据流控制优化
data_in_ready
信号精确控制数据输入时机,确保缓冲区不会溢出。- 突发传输与数据接收并行处理,最大化吞吐量。
与传统 DMA 的对比
典型应用场景
-
高速数据采集系统
从 ADC(模数转换器)以 40MSPS 速率采样数据,通过 DMA 快速传输到 DDR3 内存,避免数据丢失。 -
实时信号处理
将传感器数据批量传输到内存,供 DSP 或 FPGA 进行后续处理(如滤波、FFT 变换)。 -
视频 / 图像处理
高效传输大尺寸图像帧或视频流,利用突发模式提高带宽利用率。 -
网络数据收发
在网络接口与内存之间快速搬运数据包,减少 CPU 干预,提高系统吞吐量。
性能优势
-
高吞吐量
通过突发传输和预计算地址,减少 DDR3 接口的空闲时间,接近理论带宽上限。 -
低延迟
状态机设计优化了传输流程,减少了状态切换和等待时间。 -
资源高效
仅需少量寄存器(current_addr
、ddr3_start_addr
、burst_count
)实现复杂的地址管理,硬件成本低。 -
可扩展性
状态机架构清晰,易于扩展支持更多功能(如读操作、循环缓冲区、多通道传输)。