FPGA视频4分屏项目 - 系统架构详细讲解

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的复位和数据流转

关键功能点:

  1. 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;
  2. 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) + 时钟域转换
  3. 信号说明

    信号 方向 位宽 说明
    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) 阻止覆盖

九、总结

这个系统是一个典型的流水线视频处理架构:

  1. 采集阶段: 双摄像头 → 预处理 → 4路写FIFO
  2. 传输阶段: 仲裁选择 → AXI协议 → DDR存储
  3. 回读阶段: DDR读取 → 仲裁路由 → 4路读FIFO
  4. 输出阶段: 时序转换 → 4分屏合成 → HDMI输出

核心特点:

  • 异步双缓冲: 读写独立进行,无冲突
  • AXI突发传输: 高效DDR数据交互
  • 动态仲裁: 智能分配总线资源
  • 帧同步机制: VS/HS精确对齐
  • 可扩展性: 易于添加更多处理模块
相关推荐
秋91 小时前
硬件工程师全岗位薪资全景解析(2026版):IC设计·嵌入式·板级硬件·FPGA·晶圆制造
fpga开发·制造
博览鸿蒙1 小时前
FPGA 工程师到底有哪些方向?每个岗位都在干什么?一篇给你讲清楚
fpga开发
怪奇云呼军6 小时前
知识库也会注入指令?闪电智能VoiceAgent 如何防住 Prompt Injection
人工智能·python·算法·云计算·音视频
EasyDSS6 小时前
开会不用装App:私有化音视频系统EasyDSS即时视频会议,浏览器点开就能聊,AI帮你写纪要
人工智能·音视频
公子小六7 小时前
基于.NET的Windows窗体编程之WinForms音频控件
windows·microsoft·c#·.net·音视频·winforms
见山是山-见水是水9 小时前
鸿蒙版 Flutter Video 视频播放组件:播放控制、全屏切换与倍速播放
flutter·音视频·harmonyos
Claire_8810 小时前
从视频字幕到知识图谱:基于大语言模型的自动思维导图生成工具调研
语言模型·音视频·知识图谱
hz5678910 小时前
视频会议远程终端选型要点与部署实践
硬件架构·音视频·信息与通信·智能硬件
乐橙开放平台10 小时前
监控开放平台是什么?从设备接入到视频能力开放一次讲清
网络·人工智能·音视频