FPGA视频4分屏项目 - 系统架构详细讲解
一、系统整体架构
┌─────────────────────────────────────────────────────────────────────┐
│ CMOS摄像头 (双路) │
│ (CMOS1/2 采集8bit数据) │
└────────────┬────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 图像预处理模块 (4路处理) │
│ (cam_pre_process / process_filter / process_gamma 等) │
│ 输出 16bit 图像数据到写FIFO │
└────────────┬────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────┐
│ 写FIFO缓存 (4组, 每组256bit) │
│ 从16bit摄像头数据到256bit │
│ 宽度转换和缓冲处理 │
└────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AXI主机仲裁层 (axi_m_arbitration.v) │
│ 4个AXI主机 + 仲裁器 + FIFO控制器 │
│ 读写状态机 & 突发长度控制 & 地址管理 │
└──────────┬──────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AXI总线接口 (axi_m.v - 4个AXI_FULL_M主机模块) │
│ • 写地址通道 (AWADDR/AWVALID/AWREADY) │
│ • 写数据通道 (WDATA/WVALID/WREADY/WLAST) │
│ • 读地址通道 (ARADDR/ARVALID/ARREADY) │
│ • 读数据通道 (RDATA/RVALID/RLAST) │
└──────────┬──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────┐
│ DDR3 SDRAM │
│ (多帧缓存区) │
│ 4页双缓冲 │
└──────────┬───────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ AXI读取 + 读FIFO (4组, 每组256bit) │
│ 从DDR3读取数据宽度转换为32bit │
└──────────┬──────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ sync_generator (时序生成器) │
│ 生成HDMI时序信号 (VS, HS, DE) │
│ 数据并行输出到4个象限 │
└──────────┬──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────┐
│ HDMI输出 │
│ (4分屏显示) │
└──────────────────┘
二、各文件功能详解
2.1 rw_fifo_ctrl.v (读写FIFO控制器)
功能: 控制读写FIFO的复位和数据流转
关键功能点:
-
FIFO复位逻辑 (帧同步复位)
verilog// 检测竖同步信号上升沿,生成复位脉冲 - vs_in: 写FIFO的竖同步输入 - vs_out: 读FIFO的竖同步输入 // 时序处理:使用移位寄存器生成多周期复位 always @(posedge wfifo_wr_clk) r_vs_in_d1 <= {r_vs_in_d1[14:0], r_vs_in_d0}; // 上升沿检测 if(r_vs_in_d1[0] && !r_vs_in_d1[14]) r_wr_rst <= 1'b1; -
FIFO模块例化
写FIFO (write_ddr_fifo): - 写端: 32bit @ wfifo_wr_clk (摄像头时钟) - 读端: 256bit @ ddr_clk (DDR时钟) - 功能: 宽度转换 (32→256) + 时钟域转换 读FIFO (read_ddr_fifo): - 写端: 256bit @ ddr_clk (DDR时钟) - 读端: 32bit @ rfifo_rd_clk (像素时钟) - 功能: 宽度转换 (256→32) + 时钟域转换 -
信号说明
信号 方向 位宽 说明 wfifo_wr_en 输入 1 写FIFO写使能 wfifo_wr_data32_in 输入 32 从摄像头输入的32bit数据 wfifo_rd_water_level 输出 9 写FIFO读端水位(256bit单位) wfifo_rd_data256_out 输出 256 写FIFO读端256bit数据 rfifo_wr_req 输入 1 读FIFO写请求(来自AXI) rfifo_wr_data256_in 输入 256 来自DDR的256bit数据 rfifo_rd_data32_out 输出 32 输出到HDMI的32bit数据
2.2 axi_m.v (AXI主机模块)
功能: 单个AXI主机,实现与DDR3的数据交互
2.2.1 参数说明
verilog
parameter integer VIDEO_LENGTH = 1920 // 图像宽度
parameter integer VIDEO_HIGTH = 1080 // 图像高度
parameter integer PIXEL_WIDTH = 32 // 像素位宽(32bit=2个16bit像素)
parameter integer CTRL_ADDR_WIDTH = 28 // 地址宽度
parameter integer DQ_WIDTH = 32 // DDR数据宽度(32bit)
parameter integer M_AXI_BRUST_LEN = 8 // 突发长度(8个256bit数据)
parameter integer VIDEO_BASE_ADDR = 2'd0 // 基地址页号(0-3页)
2.2.2 地址构成
28位地址 = [27:22 基址] + [21:20 页号(2bit)] + [19:0 页内偏移(20bit)]
例: VIDEO_BASE_ADDR=0, r_wr_addr_page=0, r_wr_addr_cnt=0
M_AXI_AWADDR = {4'b0, 2'b00, 2'b00, 20'b0} = 28'h0000000
地址空间分配(以1920×1080为例):
- 单帧大小: 1920×1080×16bit = 33,177,600 bits = 4,147,200 字节
- DDR地址数: 4,147,200 / 4 = 1,036,800 = 0x100800
- 页号分配: 0-3页,每页存放一帧数据
2.2.3 写流程 (摄像头 → DDR)
状态机: IDLE → WRITE_START → WRITE_ADDR → WRITE_DATA
关键信号:
| 信号 | 方向 | 说明 |
|---|---|---|
| M_AXI_AWADDR | 输出 | 写地址 |
| M_AXI_AWVALID | 输出 | 写地址有效(主机向从机) |
| M_AXI_AWREADY | 输入 | 从机就绪应答 |
| wfifo_rd_water_level | 输入 | 写FIFO中有效数据数量 |
| wfifo_rd_req | 输出 | 写FIFO读请求 |
WRITE_ADDR阶段:
verilog
// 地址握手条件
if (M_AXI_AWVALID && M_AXI_AWREADY)
begin
r_m_axi_awvalid <= 1'b0; // 清除有效标志
r_wr_addr_cnt <= r_wr_addr_cnt + M_AXI_BRUST_LEN * 8; // 地址+8
end
// 地址自动递增规则
// 每次传输突发长度×8 = 8组数据 = 256×8 = 2048bit = 256字节
WRITE_DATA阶段:
verilog
// 数据握手条件(硬件无握手,直接接连接)
assign wfifo_rd_req = M_AXI_WLAST ? 1'b0 : M_AXI_WREADY;
// 含义:
// - 当M_AXI_WLAST=0(未到最后)且M_AXI_WREADY=1时,继续读FIFO
// - 当M_AXI_WLAST=1(最后数据)时,停止读FIFO
// - 这形成了8个数据的突发传输
2.2.4 读流程 (DDR → 显示)
状态机: IDLE → READ_START → READ_ADDR → READ_DATA
关键特点:
verilog
// 读启动条件
if(DDR_INIT_DONE && r_fram_done) // 必须DDR初始化完 + 写帧完成
r_fifo_state <= READ_START;
// 读启动阈值
if(rfifo_wr_water_level < VIDEO_LENGTH*PIXEL_WIDTH/128)
r_fifo_state <= READ_ADDR;
// 含义: 读FIFO中数据少于1行时,向DDR申请新数据
// VIDEO_LENGTH*PIXEL_WIDTH/128 = 1920*32/128 = 480 (256bit单位)
2.2.5 页号管理 (帧缓冲)
双缓冲原理:
verilog
// 写端维护
r_wr_addr_page: 当前写入的页号(0-3)
r_wr_last_page: 上一次写完的页号
// 读端维护
r_rd_addr_page: 当前读取的页号
r_rd_last_page: 上一次读完的页号
// 页切换时机
if(r_wr_done) // 写完一帧后
begin
r_wr_last_page <= r_wr_addr_page;
r_wr_addr_page <= r_wr_addr_page + 1; // 切换到下一页
if(r_wr_addr_page == r_rd_addr_page) // 不能覆盖正在读的页
r_wr_addr_page <= r_wr_addr_page + 1;
end
// 读端切换逻辑
if(r_rd_done) // 读完一帧后
begin
r_rd_addr_page <= r_wr_last_page; // 切换到最新写完的页
if(r_rd_addr_page == r_wr_addr_page) // 如果即将写入该页
r_rd_addr_page <= r_rd_last_page; // 保持在旧页
end
2.2.6 VS同步复位
verilog
// 竖同步信号处理
always @(posedge M_AXI_ACLK)
begin
r_vs_in_d0 <= vs_in;
r_vs_in_d1 <= r_vs_in_d0;
end
// 上升沿检测
if(r_vs_in_d0 && (!r_vs_in_d1)) // 上升沿
r_wr_rst <= 1'b1;
// 复位释放
if(r_wr_addr_cnt == wr_addr_min) // 地址计数器回到最小值
r_wr_rst <= 1'b0;
// 说明: 每帧开始时重置地址和状态,形成帧同步机制
2.3 axi_m_arbitration.v (仲裁层)
功能: 4个AXI主机的仲裁 + 4组FIFO的统一管理
2.3.1 仲裁原理
写仲裁 (轮询): M0 → M1 → M2 → M3 → M0
verilog
// 写状态机
case(arbitration_wr_state)
M0_WRITE:
begin
if(M0_AXI_WLAST) // 第一个主机写完
arbitration_wr_state <= M1_WRITE; // 切换到第二个
else if((!(wfifo0_state == 'd3)) && // 写FIFO不在写数据阶段
(wfifo0_rd_water_level < M_AXI_BRUST_LEN) && // 数据不足
(wr_addr_cnt0 < wr_addr_max - M_AXI_BRUST_LEN * 8)) // 未到末尾
arbitration_wr_state <= M1_WRITE; // 提前切换
end
...
end
读仲裁 (更复杂):
verilog
// 分为两个阶段
// 阶段1: 预初始化 (rfifo_pre_write_init == 0)
// 轮流向4个读FIFO写入第一行数据
if(!rfifo_pre_write_init)
begin
if(rfifo0_wr_water_level < ZOOM_VIDEO_LENGTH*PIXEL_WIDTH/256*2)
arbitration_rd_state <= M0_READ;
else if(rfifo1_wr_water_level < ...)
arbitration_rd_state <= M1_READ;
...
else
rfifo_pre_write_init <= 1'd1; // 全部预写完毕
end
// 阶段2: 正常传输 (rfifo_pre_write_init == 1)
// 根据显示模块的读取请求分配读FIFO
else if(r_video0_rd_en_d0) // 象限0需要读
arbitration_rd_state <= M0_READ;
else if(r_video1_rd_en_d0) // 象限1需要读
arbitration_rd_state <= M1_READ;
2.3.2 仲裁信号多选
verilog
// 写地址信号多选
assign M_AXI_AWVALID = (arbitration_wr_state == M0_WRITE) ? M0_AXI_AWVALID :
(arbitration_wr_state == M1_WRITE) ? M1_AXI_AWVALID :
(arbitration_wr_state == M2_WRITE) ? M2_AXI_AWVALID :
(arbitration_wr_state == M3_WRITE) ? M3_AXI_AWVALID : 1'b0;
// 写地址
assign M_AXI_AWADDR = (arbitration_wr_state == M0_WRITE) ? M0_AXI_AWADDR :
(arbitration_wr_state == M1_WRITE) ? M1_AXI_AWADDR :
...
// 从机反馈给主机
assign M0_AXI_AWREADY = (arbitration_wr_state == M0_WRITE) ? M_AXI_AWREADY : 1'b0;
// 说明: 只有被选中的主机才能与从机通信,其他主机收到'0'信号
2.3.3 核心信号连接
verilog
// 写FIFO → DDR
wfifo0_rd_req ───────> AXI_FULL_M0 ──> M_AXI_WDATA ──> AXI总线 ──> DDR
wfifo1_rd_req ───────> AXI_FULL_M1 ─┐
wfifo2_rd_req ───────> AXI_FULL_M2 ─┼> 仲裁器多选
wfifo3_rd_req ───────> AXI_FULL_M3 ─┘
// DDR → 读FIFO
DDR ──> AXI总线 ──> M_AXI_RDATA ──> 仲裁器多选 ──> rfifo0_wr_req ──> 读FIFO0
rfifo1_wr_req ──> 读FIFO1
rfifo2_wr_req ──> 读FIFO2
rfifo3_wr_req ──> 读FIFO3
三、AXI协议详解
3.1 AXI总线信号汇总
3.1.1 写地址通道 (Write Address Channel)
| 信号名 | 位宽 | 方向 | 含义 | 说明 |
|---|---|---|---|---|
| AWID | 4 | M→S | 写事务ID | 区分不同写请求 |
| AWADDR | 28 | M→S | 写地址 | DDR目标地址 |
| AWLEN | 4 | M→S | 突发长度-1 | 本代码未用 |
| AWSIZE | 3 | M→S | 数据宽度 | 本代码未用 |
| AWBURST | 2 | M→S | 突发类型 | 本代码未用 |
| AWUSER | 1 | M→S | 用户信号 | 本代码=0 |
| AWVALID | 1 | M→S | 地址有效 | 握手信号 |
| AWREADY | 1 | S→M | 从机就绪 | 握手信号 |
握手时序:
时钟边界: │ │ │ │ │
AWVALID: ───┬────────┬────────────────┬───────
│ │ │
AWREADY: ───────┬────────┬───────────────────
传输发生: ↑握手1 ↑握手2
说明:
- AWVALID=1 && AWREADY=1: 地址成功传输
- 最少传输1个地址,最多传输4个地址(4页缓冲)
3.1.2 写数据通道 (Write Data Channel)
| 信号名 | 位宽 | 方向 | 含义 | 说明 |
|---|---|---|---|---|
| WID | 4 | M→S | 数据ID | 可选 |
| WDATA | 256 | M→S | 写数据 | 256bit = 8×32bit |
| WSTRB | 32 | M→S | 字节使能 | 本代码全1 |
| WLAST | 1 | M→S | 最后数据 | 突发控制 |
| WUSER | 4 | M→S | 用户信号 | 本代码未用 |
| WVALID | 1 | M→S | 数据有效 | 握手信号 |
| WREADY | 1 | S→M | 从机就绪 | 握手信号 |
数据握手时序:
突发长度 = 8
时钟边界: │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │
WVALID: ──────────────────────────────────────────────────
WREADY: ───────┬──────┬──────┬──────┬──────┬──────┬──────┬──
WLAST: 0 0 0 0 0 0 0 1
数据编号: #1 #2 #3 #4 #5 #6 #7 #8
说明:
- 每个时钟周期传1个256bit数据
- WLAST=1标记最后一个数据
- 8个数据后自动回到IDLE准备下一次突发
3.1.3 读地址通道 (Read Address Channel)
与写地址通道类似,信号为ARID/ARADDR/ARVALID/ARREADY
3.1.4 读数据通道 (Read Data Channel)
| 信号名 | 位宽 | 方向 | 含义 |
|---|---|---|---|
| RID | 4 | S→M | 数据ID |
| RDATA | 256 | S→M | 读数据 |
| RRESP | 2 | S→M | 响应(OK/错误) |
| RLAST | 1 | S→M | 最后数据 |
| RVALID | 1 | S→M | 数据有效 |
| RREADY | 1 | M→S | 主机就绪(本代码自动=1) |
3.2 写流程完整时序
┌─────────────────────────────────────────┐
│ 主机侧: AXI_FULL_M │
│ 写FIFO数据 ↓ │
└──────────────┬────────────────────────┘
│ wfifo_rd_water_level > 8
▼
┌─────────────────┐
│ WRITE_START │
│ 状态机 │
└────────┬────────┘
│ 条件满足
▼
┌──────────────────────┐
│ WRITE_ADDR 状态 │
│ 1. r_m_axi_awvalid │
│ <= 1'b1 │
└────────┬─────────────┘
│
│ 地址握手:
│ M_AXI_AWVALID && M_AXI_AWREADY
▼
┌──────────────────────┐
│ WRITE_DATA 状态 │
│ 2. 开始发送数据 │
│ wfifo_rd_req = 1 │
└────────┬─────────────┘
│ 8个数据传输完(M_AXI_WLAST=1)
▼
┌──────────────────────┐
│ 返回WRITE_START │
│ 准备下一批数据 │
└──────────────────────┘
3.3 关键握手机制
写地址握手
verilog
if(M_AXI_AWVALID && M_AXI_AWREADY) begin
r_m_axi_awvalid <= 1'b0;
r_wr_addr_cnt <= r_wr_addr_cnt + 64; // 8个256bit = 2048bit = 256字节
end
写数据握手
write_ddr_fifo FIFO的内部处理:
- 当 wfifo_rd_req = 1 时,每个时钟周期输出1个256bit数据
- 同时产生 M_AXI_WVALID = 1
- 当接收到 M_AXI_WREADY = 1 时,完成1个数据握手
WLAST 由 AXI从机产生,标记8个数据的末尾
四、数据流转完整描述
4.1 发送流程 (摄像头 → 显示)
第1步: 摄像头采集
┌─────────────┐
│ CMOS摄像头 │ 16bit/像素 @ 27MHz
│ 1920×1080 │ HREF/VSYNC
└──────┬──────┘
│
第2步: 图像预处理 (4路)
┌──────────────────────────────────────┐
│ 4个预处理模块 (并行处理) │
│ - cam1_filter: 降噪 │
│ - cam2_bin: 二值化 │
│ - cam3_filter: 滤波 │
│ - cam4_gamma: 伽马校正 │
│ 输出: 16bit/像素 @ 各自的像素时钟 │
└──────┬───────────────────────────────┘
│
第3步: 写入写FIFO (4组独立FIFO)
┌──────────────────────────────────────┐
│ rw_fifo_ctrl (4组) │
│ 输入: 32bit @ 像素时钟 │
│ 输出: 256bit @ DDR时钟 │
│ 功能: 32→256宽度转换 + 时钟域转换 │
└──────┬───────────────────────────────┘
│ wfifo_rd_water_level
第4步: AXI主机仲裁
┌──────────────────────────────────────┐
│ axi_m_arbitration │
│ - 写仲裁 (M0→M1→M2→M3) │
│ - 地址管理 (4页循环) │
│ - 状态机 (WRITE_ADDR/WRITE_DATA) │
└──────┬───────────────────────────────┘
│
第5步: AXI总线写入DDR
┌──────────────────────────────────────┐
│ AXI总线握手 │
│ AWADDR: 写地址 (28bit) │
│ WDATA: 写数据 (256bit×8 = 突发) │
│ 每个主机写完1帧后轮换 │
└──────┬───────────────────────────────┘
│ 存储到DDR
第6步: DDR读取
┌──────────────────────────────────────┐
│ 当写完1帧后 (r_fram_done=1) │
│ 开始读取上一帧数据 │
│ 读地址自动循环: 0→1→2→3→0 │
│ 保证写入和读取不冲突 │
└──────┬───────────────────────────────┘
│
第7步: 写入读FIFO
┌──────────────────────────────────────┐
│ rw_fifo_ctrl 读FIFO │
│ 输入: 256bit @ DDR时钟 │
│ 输出: 32bit @ 像素时钟 │
│ 256→32宽度转换 │
└──────┬───────────────────────────────┘
│
第8步: 时序转换
┌──────────────────────────────────────┐
│ sync_generator │
│ 生成4分屏时序信号 │
│ - VS, HS, DE 同步脉冲 │
│ - 数据路由到4个象限 │
└──────┬───────────────────────────────┘
│
第9步: HDMI输出
┌──────────────────────────────────────┐
│ 4个象限并行输出 @ 27MHz │
│ HDMI驱动生成最终视频信号 │
└──────────────────────────────────────┘
4.2 关键时序点
| 时间点 | 事件 | 信号变化 |
|---|---|---|
| 帧开始 | VSYNC上升沿 | vs_in上升 |
| 帧内 | 写地址握手 | AWVALID && AWREADY |
| 帧内 | 数据握手 | WVALID && WREADY (×8) |
| 帧内 | WLAST=1 | 突发结束 |
| 帧末 | 写完成 | r_wr_done=1 |
| 帧末 | 页号切换 | r_wr_addr_page++ |
| 帧末 | r_fram_done=1 | 允许读取 |
| 后续帧 | 读启动 | r_fifo_state → READ_START |
五、地址与页号管理
5.1 地址计算
总地址28bit = [27:22 保留] + [21:20 页号] + [19:0 页内偏移]
每帧存储空间:
1920×1080×16bit = 33,177,600 bits = 4,147,200字节 = 1,036,800×4字节
= 0xF_D20_0 (20bit地址)
页号循环:
页0: 地址 0x0000000 ~ 0x0F_D1FF
页1: 地址 0x0100000 ~ 0x0FE_D1FF
页2: 地址 0x0200000 ~ 0x0FE_D1FF
页3: 地址 0x0300000 ~ 0x0FE_D1FF
页内偏移递增规则:
每次AXI握手 → r_wr_addr_cnt += 64 (=M_AXI_BRUST_LEN × 8)
64个地址单位 = 64×4字节 = 256字节 = 8×256bit = 8个AXI数据
5.2 双缓冲机制
同时有4个页面:
当前写入 下一帧将写 已完成 等待读
┌──────────────┬──────────────┬──────────────┬──────────────┐
│ 写端指针 │ 准备页 │ 完成页 │ 读端指针 │
│ wr_addr_page │ │ wr_last_page │ rd_addr_page │
└──────────────┴──────────────┴──────────────┴──────────────┘
安全机制:
- 写端不能覆盖读端正在读的页
- 读端不能读未写入的页
- 总是读"上一次写完的页" (wr_last_page)
示例:
第1帧: 写→页0 读→等待
第2帧: 写→页1 读→页0
第3帧: 写→页2 读→页1
第4帧: 写→页3 读→页2
第5帧: 写→页0 读→页3
六、控制流程和约束条件
6.1 写流程状态转移
初始化后:
IDLE ──(DDR_INIT_DONE=1)──> WRITE_START
WRITE_START 等待条件:
1. wfifo_rd_water_level > 8 (至少8个256bit数据)
OR
2. (接近末尾) && (wfifo_rd_water_level >= 7)
满足条件 → WRITE_ADDR
WRITE_ADDR:
发送第一个地址,等待握手
M_AXI_AWVALID && M_AXI_AWREADY → WRITE_DATA
WRITE_DATA:
持续发送数据,直到WLAST=1 → 返回WRITE_START
当 r_wr_addr_cnt >= wr_addr_max - 64:
最后一批数据,写完后:
- r_wr_addr_cnt 回到 wr_addr_min
- r_wr_done = 1 (一帧完成标志)
- r_fram_done = 1 (允许读取信号)
- 页号递增
6.2 读流程状态转移
前提条件:
DDR_INIT_DONE = 1 && r_fram_done = 1 (至少有一帧已写入)
IDLE ──> READ_START (首次有效数据时)
READ_START 等待条件:
rfifo_wr_water_level < 1行数据量
说明: 当读FIFO中数据少于1行时,向DDR申请新行数据
满足条件 → READ_ADDR
READ_ADDR:
发送读地址,等待握手
M_AXI_ARVALID && M_AXI_ARREADY → READ_DATA
READ_DATA:
接收数据,直到RLAST=1 → 返回READ_START
当 r_rd_addr_cnt >= wr_addr_max - 64:
最后一批数据,读完后:
- r_rd_addr_cnt 回到 wr_addr_min
- r_rd_done = 1
- 页号递增
七、关键参数计算
verilog
// FIFO水位阈值 (多少数据后开始传输)
wfifo_rd_water_level > M_AXI_BRUST_LEN
= wfifo_rd_water_level > 8
意义: 至少累积8个256bit数据(2048bit=256字节)后开始写DDR
// 读FIFO启动条件
rfifo_wr_water_level < VIDEO_LENGTH * PIXEL_WIDTH / 128
= 1920 * 32 / 128
= 480 (以256bit为单位)
意义: 当读FIFO中数据少于1行时,申请新行
// 地址递增量
M_AXI_BRUST_LEN * 8
= 8 * 8 = 64
意义: 每次突发传输地址增加64 (256字节)
// 末尾判断
r_wr_addr_cnt >= wr_addr_max - M_AXI_BRUST_LEN * 8
= r_wr_addr_cnt >= wr_addr_max - 64
意义: 剩余少于64个地址时,本次传输后回零
// 读启动延迟
r_fram_done = 1: 至少1帧写入DDR
rfifo_wr_water_level < 1行: 读FIFO不满
这两个条件确保有足够数据供读取
八、常见问题解析
Q1: 为什么需要4个页面?
A: 两个理由:
1. 防止冲突: 读写独立操作,需要分离的存储区域
2. 流水处理: 4页允许最多4路摄像头独立存储,不会相互等待
Q2: WLAST信号如何产生?
A: 由DDR从机产生:
- 主机声明突发长度(AWLEN/ARLEN)
- 从机根据长度在第N个数据后自动产生WLAST/RLAST
- 本设计固定突发长度=8,所以第8个数据时WLAST=1
Q3: 为什么地址增量是64?
A: 64 = M_AXI_BRUST_LEN × 8
- 突发长度 = 8
- 每个地址代表4字节
- 总传输 = 8 × 256bit = 8 × 32字节 = 256字节 = 64个地址单位
Q4: 如何确保先写后读?
A: 通过以下机制:
1. r_fram_done: 写完一帧才允许读
2. 页号分离: 读取上一帧(wr_last_page),写入当前帧(wr_addr_page)
3. 防护检查: if(r_wr_addr_page == r_rd_addr_page) 阻止覆盖
九、总结
这个系统是一个典型的流水线视频处理架构:
- 采集阶段: 双摄像头 → 预处理 → 4路写FIFO
- 传输阶段: 仲裁选择 → AXI协议 → DDR存储
- 回读阶段: DDR读取 → 仲裁路由 → 4路读FIFO
- 输出阶段: 时序转换 → 4分屏合成 → HDMI输出
核心特点:
- ✅ 异步双缓冲: 读写独立进行,无冲突
- ✅ AXI突发传输: 高效DDR数据交互
- ✅ 动态仲裁: 智能分配总线资源
- ✅ 帧同步机制: VS/HS精确对齐
- ✅ 可扩展性: 易于添加更多处理模块