2. RAW图像数据打包模块
任务说明
本案例实现一个RAW Bayer图像数据打包模块,将传感器输出的RAW数据按指定格式(如RAW8/RAW10/RAW12)组织成字节流,供后续ISP流水线处理。模块需支持可配置的位宽转换与行缓冲输出,确保数据流格式与下游模块接口匹配。
核心实现
module raw_packer #(
parameter int RAW_WIDTH = 10, // RAW数据位宽: 8/10/12
parameter int PIX_PER_LINE = 128, // 每行像素数
parameter int LINES = 64 // 总行数
)(
input logic clk,
input logic rst_n,
// 输入: RAW像素流
input logic px_valid,
input logic [RAW_WIDTH-1:0] px_data,
// 输出: 打包字节流
output logic out_valid,
output logic [7:0] out_data,
output logic out_eol, // 行结束标志
output logic out_eof // 帧结束标志
);
// 像素计数与行计数
logic [15:0] px_cnt;
logic [15:0] line_cnt;
// 打包状态机
typedef enum logic [1:0] {IDLE, PACK, DONE} state_t;
state_t state;
// 移位寄存器: 按位宽累积像素
logic [23:0] shift_reg;
logic [4:0] bit_cnt; // 已累积有效位数
// 输出缓冲
logic [7:0] out_buf;
logic buf_valid;
// 像素计数与行计数
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
px_cnt <= 0;
line_cnt <= 0;
end else if (px_valid) begin
if (px_cnt == PIX_PER_LINE-1) begin
px_cnt <= 0;
line_cnt <= (line_cnt == LINES-1) ? 0 : line_cnt + 1;
end else begin
px_cnt <= px_cnt + 1;
end
end
end
// 打包逻辑: 将RAW_WIDTH位像素打包为8位字节流
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
shift_reg <= 0;
bit_cnt <= 0;
out_buf <= 0;
buf_valid <= 0;
state <= IDLE;
end else begin
// 默认输出无效
buf_valid <= 0;
case (state)
IDLE: begin
if (px_valid) begin
// 将像素移入移位寄存器
shift_reg <= (shift_reg << RAW_WIDTH) | px_data;
bit_cnt <= bit_cnt + RAW_WIDTH;
state <= PACK;
end
end
PACK: begin
// 当累积位数≥8时输出字节
if (bit_cnt >= 8) begin
out_buf <= shift_reg[bit_cnt-1 -: 8];
shift_reg <= shift_reg << 8;
bit_cnt <= bit_cnt - 8;
buf_valid <= 1;
// 若还有像素且移位寄存器空间足够,继续接收
if (px_valid && bit_cnt + RAW_WIDTH <= 24) begin
shift_reg <= (shift_reg << RAW_WIDTH) | px_data;
bit_cnt <= bit_cnt + RAW_WIDTH;
end
end else if (px_valid) begin
// 不足8位且有新像素到达
shift_reg <= (shift_reg << RAW_WIDTH) | px_data;
bit_cnt <= bit_cnt + RAW_WIDTH;
end
// 行结束处理
if (px_cnt == PIX_PER_LINE-1 && !px_valid) begin
// 行内像素已收完,清空剩余位(不足8位补零)
if (bit_cnt > 0) begin
out_buf <= shift_reg << (8 - bit_cnt);
buf_valid <= 1;
end
state <= DONE;
end
end
DONE: begin
state <= IDLE;
end
endcase
end
end
// 输出赋值
assign out_valid = buf_valid;
assign out_data = out_buf;
assign out_eol = (px_cnt == PIX_PER_LINE-1) && buf_valid;
assign out_eof = (line_cnt == LINES-1) && (px_cnt == PIX_PER_LINE-1) && buf_valid;
endmodule
运行与验证
环境依赖:Verilog仿真工具(如Vivado XSim、ModelSim、Icarus Verilog)。
仿真测试平台:
module tb_raw_packer;
logic clk = 0;
logic rst_n = 0;
logic px_valid = 0;
logic [9:0] px_data;
logic out_valid, out_eol, out_eof;
logic [7:0] out_data;
raw_packer #(.RAW_WIDTH(10), .PIX_PER_LINE(8), .LINES(2)) dut (
.clk(clk), .rst_n(rst_n),
.px_valid(px_valid), .px_data(px_data),
.out_valid(out_valid), .out_data(out_data),
.out_eol(out_eol), .out_eof(out_eof)
);
always #5 clk = ~clk;
initial begin
// 复位
#20 rst_n = 1;
// 输入2行,每行8个10bit像素: 值依次为0~7, 8~15
for (int line = 0; line < 2; line++) begin
for (int i = 0; i < 8; i++) begin
@(posedge clk);
px_valid = 1;
px_data = line*8 + i;
end
@(posedge clk);
px_valid = 0;
end
#50 $finish;
end
// 监控输出
always @(posedge clk) begin
if (out_valid)
$display("T=%0t out=%02h eol=%b eof=%b", $time, out_data, out_eol, out_eof);
end
endmodule
验证方法:
- 运行仿真,观察输出字节流。
- 通过条件:对于RAW10格式,每4个像素(40bit)应打包为5个字节;行末不足8bit时补零输出。测试平台中每行8个10bit像素共80bit,应输出10字节。检查输出数据与输入像素按位拼接结果一致,且
out_eol在行末字节处拉高,out_eof在末行末字节处拉高。
关键说明
- 模块通过移位寄存器累积像素位,达到8bit即输出一个字节,实现任意RAW位宽到字节流的转换。
- 行末不足8bit的残余数据左移补零输出,保证每行输出字节数为
ceil(PIX_PER_LINE * RAW_WIDTH / 8)。 - 参数
RAW_WIDTH可配置为8/10/12,PIX_PER_LINE与LINES按实际传感器分辨率设置。