1. MIPI CSI-2 协议层解析与数据包捕获

MIPI CSI-2 协议层解析与数据包捕获 学习卡片

任务说明

本案例用 FPGA 抓取 MIPI CSI-2 的 D-PHY 字节流,按 CSI-2 协议解析出短包(帧同步 FS、帧结束 FE)和长包(图像行数据),最终把一帧原始像素数据写入 BRAM 并导出为二进制文件。核心是包边界识别与字节重组,不涉及 D-PHY 电气层解码。

协议结构

CSI-2 数据包由包头、可选数据、包尾组成。短包固定 4 字节,长包在包头后跟 WC 字节数据,再跟 2 字节 CRC。包头首字节低 6 位是 Data ID(VC + 数据类型),高 2 位是虚拟通道;第二字节是字计数 WC 低 8 位,第三字节是 WC 高 8 位,第四字节是 ECC。FS 的 Data ID 为 0x00,FE 为 0x01,RAW8 为 0x2A。

短包 (4B): [DataID][WC_L][WC_H][ECC] FS: DataID=0x00 FE: DataID=0x01 长包: [DataID][WC_L][WC_H][ECC] + WC 字节数据 + [CRC_L][CRC_H] RAW8: DataID=0x2A, WC = 行宽 数据段即原始像素字节 解析流程: 字节流 → 包头识别 → 短包/长包分流 → 长包数据写入 BRAM → 帧结束导出 状态机: IDLE → HEADER → DATA → CRC → IDLE

关键实现

下面给出解析状态机的核心 Verilog 代码。输入为 D-PHY 解串后的 8 位字节流 byte_in 与有效标志 byte_valid,输出为写 BRAM 的像素数据与帧完成脉冲。为便于仿真验证,用一段预置字节流作为激励。

module csi2_parser (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [7:0]  byte_in,
    input  wire        byte_valid,
    output reg  [7:0]  pix_data,
    output reg         pix_we,
    output reg  [15:0] pix_addr,
    output reg         frame_done
);
    localparam S_IDLE=0, S_HDR=1, S_DATA=2, S_CRC=3;
    reg [2:0]  state;
    reg [1:0]  hdr_cnt;
    reg [7:0]  data_id;
    reg [15:0] wc;
    reg [15:0] data_cnt;
    reg [1:0]  crc_cnt;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state<=S_IDLE; hdr_cnt<=0; data_cnt<=0; crc_cnt<=0;
            pix_we<=0; frame_done<=0; pix_addr<=0;
        end else begin
            pix_we<=0; frame_done<=0;
            if (byte_valid) begin
                case (state)
                    S_IDLE: begin
                        data_id<=byte_in; hdr_cnt<=1; state<=S_HDR;
                    end
                    S_HDR: begin
                        if (hdr_cnt==1) begin wc[7:0]<=byte_in; hdr_cnt<=2; end
                        else if (hdr_cnt==2) begin wc[15:8]<=byte_in; hdr_cnt<=3; end
                        else begin
                            // 第4字节 ECC,忽略校验
                            if (data_id[5:0]==6'h00 || data_id[5:0]==6'h01) begin
                                // 短包,直接结束
                                if (data_id[5:0]==6'h01) frame_done<=1;
                                state<=S_IDLE;
                            end else begin
                                data_cnt<=0; state<=S_DATA;
                            end
                        end
                    end
                    S_DATA: begin
                        pix_data<=byte_in; pix_we<=1;
                        pix_addr<=pix_addr+1;
                        data_cnt<=data_cnt+1;
                        if (data_cnt+1>=wc) begin crc_cnt<=0; state<=S_CRC; end
                    end
                    S_CRC: begin
                        if (crc_cnt==1) state<=S_IDLE;
                        else crc_cnt<=crc_cnt+1;
                    end
                endcase
            end
        end
    end
endmodule

仿真验证

用一段包含 FS、一行 RAW8 长包、FE 的字节流作为激励,观察 pix_we 是否在长包数据段拉高、frame_done 是否在 FE 后产生脉冲。下面给出 testbench 关键片段。

module tb_csi2_parser;
    reg clk=0, rst_n=0, byte_valid=0;
    reg [7:0] byte_in;
    wire [7:0] pix_data;
    wire pix_we, frame_done;
    wire [15:0] pix_addr;

    csi2_parser uut(.clk(clk),.rst_n(rst_n),.byte_in(byte_in),
        .byte_valid(byte_valid),.pix_data(pix_data),.pix_we(pix_we),
        .pix_addr(pix_addr),.frame_done(frame_done));

    always #5 clk=~clk;

    task send(input [7:0] b);
        begin byte_in=b; byte_valid=1; @(posedge clk); byte_valid=0; @(posedge clk); end
    endtask

    integer i;
    initial begin
        #20 rst_n=1;
        // FS 短包: DataID=0x00, WC=0, ECC=0
        send(8'h00); send(8'h00); send(8'h00); send(8'h00);
        // 长包 RAW8, WC=4: DataID=0x2A
        send(8'h2A); send(8'h04); send(8'h00); send(8'h00);
        send(8'h11); send(8'h22); send(8'h33); send(8'h44);
        send(8'h00); send(8'h00); // CRC
        // FE 短包: DataID=0x01
        send(8'h01); send(8'h00); send(8'h00); send(8'h00);
        #50 $finish;
    end
endmodule

运行与判定

使用 Icarus Verilog 编译运行:iverilog -o sim tb_csi2_parser.v csi2_parser.v && vvp sim。通过条件:长包数据段 pix_we 连续拉高 4 个周期,pix_data 依次为 0x11、0x22、0x33、0x44,pix_addr 递增;FE 后 frame_done 出现一个周期脉冲。若用真实逻辑分析仪抓包,需先将 D-PHY 差分信号解串为字节流再送入本模块。