bram帧缓存模块&直方图拉伸 Verilog代码

1 摄像头数据分别传入两个bram中

`timescale 1ns / 1ps

//摄像头数据分别传入两个bram中
module camera_to_2bram (
    input reset_n,
    input camera_clk,
    input camera_frame_valid_i,
    input [13:0] camera_data_i,
    output reg [16:0] write_addr,
    output reg [13:0] camera_data_to_bram,
    output buffer0_write_en,
    output buffer1_write_en
);


  localparam PIXEL_SIZE = 320 * 256;  //输入的每帧像素数量

  reg buffer0_write_flag, buffer1_write_flag;
  reg camera_frame_valid_i_d0;

  reg [13:0] camera_data_i_d0;


  //对帧有效信号打一拍
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      camera_frame_valid_i_d0 <= 0;
    end else begin
      camera_frame_valid_i_d0 <= camera_frame_valid_i;
    end
  end

  //检测帧有效信号的上升沿
  assign frame_rise_edge = camera_frame_valid_i && !camera_frame_valid_i_d0;

  //每一帧开始换另一个bram写
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      buffer0_write_flag <= 0;
      buffer1_write_flag <= 1;
    end else begin
      if (frame_rise_edge == 1) begin
        buffer0_write_flag <= ~buffer0_write_flag;
        buffer1_write_flag <= ~buffer1_write_flag;
      end else begin
        buffer0_write_flag <= buffer0_write_flag;
        buffer1_write_flag <= buffer1_write_flag;
      end
    end
  end

  //对于每一个bram的写有效信号
  assign buffer0_write_en = buffer0_write_flag && camera_frame_valid_i_d0;
  assign buffer1_write_en = buffer1_write_flag && camera_frame_valid_i_d0;

  //计算写入地址
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      write_addr <= 0;
    end else begin
      if (camera_frame_valid_i_d0 == 0) begin
        write_addr <= 0;
      end else if (write_addr == PIXEL_SIZE - 1) begin
        write_addr <= 0;
      end else begin
        write_addr <= write_addr + 1;
      end
    end
  end



  //对写入数据打一拍
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      camera_data_to_bram <= 0;
    end else begin
      camera_data_to_bram <= camera_data_i;
    end
  end


endmodule

2 帧缓存代码

`timescale 1ns / 1ps

//帧缓存模块,可以对输入的连续摄像头数据进行一帧的缓存,缓存完再输出出去
module image_frame_buffer (
    input reset_n,
    input camera_clk,
    input camera_frame_valid_i,
    input [13:0] camera_data_i,
    output camera_frame_valid_o,
    output [13:0] camera_data_o
);

  localparam PIXEL_SIZE = 320 * 256;  //输入的每帧像素数量&每个bram深度

  reg buffer0_write_flag, buffer1_write_flag;
  wire buffer0_write_en, buffer1_write_en;
  reg [16:0] write_addr;
  reg camera_frame_valid_i_d0;
  wire frame_rise_edge;
  reg [13:0] camera_data_to_bram;


  //对帧有效信号打一拍
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      camera_frame_valid_i_d0 <= 0;
    end else begin
      camera_frame_valid_i_d0 <= camera_frame_valid_i;
    end
  end

  //检测帧有效信号的上升沿
  assign frame_rise_edge = camera_frame_valid_i && !camera_frame_valid_i_d0;

  //每一帧开始换另一个bram写
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      buffer0_write_flag <= 0;
      buffer1_write_flag <= 1;
    end else begin
      if (frame_rise_edge == 1) begin
        buffer0_write_flag <= ~buffer0_write_flag;
        buffer1_write_flag <= ~buffer1_write_flag;
      end else begin
        buffer0_write_flag <= buffer0_write_flag;
        buffer1_write_flag <= buffer1_write_flag;
      end
    end
  end

  //对于每一个bram的写有效信号
  assign buffer0_write_en = buffer0_write_flag && camera_frame_valid_i_d0;
  assign buffer1_write_en = buffer1_write_flag && camera_frame_valid_i_d0;

  //计算写入地址
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      write_addr <= 0;
    end else begin
      if (camera_frame_valid_i_d0 == 0) begin
        write_addr <= 0;
      end else if (write_addr == PIXEL_SIZE - 1) begin
        write_addr <= 0;
      end else begin
        write_addr <= write_addr + 1;
      end
    end
  end



  //写入bram的数据要打一拍,对齐写使能和写地址
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      camera_data_to_bram <= 0;
    end else begin
      camera_data_to_bram <= camera_data_i;
    end
  end

  //伪双端口bram,a写b读,宽度14,深度320*256,输出数据延迟一拍
  image_buffer_bram_0 bram_0 (
      .clka(camera_clk),  // input wire clka
      .ena(1),  // input wire ena
      .wea(buffer0_write_en),  // input wire [0 : 0] wea
      .addra(write_addr),  // input wire [16 : 0] addra
      .dina(camera_data_to_bram),  // input wire [13 : 0] dina

      .clkb(camera_clk),  // input wire clkb
      .addrb(read_addr),  // input wire [16 : 0] addrb
      .doutb(buffer0_read_data)  // output wire [13 : 0] doutb
  );

  image_buffer_bram_1 bram_1 (
      .clka(camera_clk),  // input wire clka
      .ena(1),  // input wire ena
      .wea(buffer1_write_en),  // input wire [0 : 0] wea
      .addra(write_addr),  // input wire [16 : 0] addra
      .dina(camera_data_to_bram),  // input wire [13 : 0] dina

      .clkb(camera_clk),  // input wire clkb
      .addrb(read_addr),  // input wire [16 : 0] addrb
      .doutb(buffer1_read_data)  // output wire [13 : 0] doutb
  );


  reg [16:0] read_addr;
  reg buffer0_read_flag, buffer1_read_flag;
  wire [13:0] buffer0_read_data;
  wire [13:0] buffer1_read_data;
  reg frame_valid_o;


  //设置对每块bram的读标志,读标志和读地址对齐,比读出的数据和帧有效信号早一拍
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      buffer0_read_flag <= 0;
      buffer1_read_flag <= 0;
    end else begin
      if (read_addr == PIXEL_SIZE) begin
        buffer0_read_flag <= 0;
        buffer1_read_flag <= 0;
      end else if (write_addr == PIXEL_SIZE - 1 && buffer0_write_flag == 1) begin
        buffer0_read_flag <= 1;
        buffer1_read_flag <= 0;
      end else if (write_addr == PIXEL_SIZE - 1 && buffer1_write_flag == 1) begin
        buffer0_read_flag <= 0;
        buffer1_read_flag <= 1;
      end else begin
        buffer0_read_flag <= buffer0_read_flag;
        buffer1_read_flag <= buffer1_read_flag;
      end
    end
  end

  //计算读地址,因为bram读出数据要在地址延后一拍才出,所以要把读地址+1,让数据全部从bram出来再清零
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      read_addr <= 0;
    end else begin
      if (buffer0_read_flag == 0 && buffer1_read_flag == 0) begin
        read_addr <= 0;
      end else if (read_addr == PIXEL_SIZE) begin
        read_addr <= 0;
      end else begin
        read_addr <= read_addr + 1;
      end
    end
  end


  //设置帧有效标志
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      frame_valid_o <= 0;
    end else begin
      if (buffer0_read_flag == 0 && buffer1_read_flag == 0) begin
        frame_valid_o <= 0;
      end else if (read_addr == PIXEL_SIZE) begin
        frame_valid_o <= 0;
      end else begin
        frame_valid_o <= 1;
      end
    end
  end

  //输出帧有效标志
  assign camera_frame_valid_o = frame_valid_o;

  //设置两个bram的输出标志
  wire bram0_out_flag, bram1_out_flag;
  assign bram0_out_flag = (buffer0_read_flag == 1) && (frame_valid_o == 1);
  assign bram1_out_flag = (buffer1_read_flag == 1) && (frame_valid_o == 1);

  //输出读到的数据
  assign camera_data_o = bram0_out_flag ? buffer0_read_data : (bram1_out_flag ? buffer1_read_data : 0);


endmodule

3 帧缓存模块,并统计最大值最小值代码

`timescale 1ns / 1ps

//帧缓存模块,可以对输入的连续摄像头数据进行一帧的缓存,并统计最大值最小值,缓存完再和最大值最小值一起输出出去
module image_frame_buffer (
    input reset_n,
    input camera_clk,
    input camera_frame_valid_i,
    input [13:0] camera_data_i,
    output camera_frame_valid_o,
    output [13:0] camera_data_o,
    output [13:0] data_max,
    output [13:0] data_min
);

  localparam PIXEL_SIZE = 320 * 256;  //输入的每帧像素数量&每个bram深度

  reg buffer0_write_flag, buffer1_write_flag;
  wire buffer0_write_en, buffer1_write_en;
  reg [16:0] write_addr;
  reg camera_frame_valid_i_d0;
  wire frame_rise_edge;
  reg [13:0] camera_data_to_bram;


  //对帧有效信号打一拍
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      camera_frame_valid_i_d0 <= 0;
    end else begin
      camera_frame_valid_i_d0 <= camera_frame_valid_i;
    end
  end

  //检测帧有效信号的上升沿
  assign frame_rise_edge = camera_frame_valid_i && !camera_frame_valid_i_d0;

  //每一帧开始换另一个bram写
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      buffer0_write_flag <= 0;
      buffer1_write_flag <= 1;
    end else begin
      if (frame_rise_edge == 1) begin
        buffer0_write_flag <= ~buffer0_write_flag;
        buffer1_write_flag <= ~buffer1_write_flag;
      end else begin
        buffer0_write_flag <= buffer0_write_flag;
        buffer1_write_flag <= buffer1_write_flag;
      end
    end
  end

  //对于每一个bram的写有效信号
  assign buffer0_write_en = buffer0_write_flag && camera_frame_valid_i_d0;
  assign buffer1_write_en = buffer1_write_flag && camera_frame_valid_i_d0;

  //计算写入地址
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      write_addr <= 0;
    end else begin
      if (camera_frame_valid_i_d0 == 0) begin
        write_addr <= 0;
      end else if (write_addr == PIXEL_SIZE - 1) begin
        write_addr <= 0;
      end else begin
        write_addr <= write_addr + 1;
      end
    end
  end



  //写入bram的数据要打一拍,对齐写使能和写地址
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      camera_data_to_bram <= 0;
    end else begin
      camera_data_to_bram <= camera_data_i;
    end
  end

  //伪双端口bram,a写b读,宽度14,深度320*256,输出数据延迟一拍
  image_buffer_bram_0 bram_0 (
      .clka(camera_clk),  // input wire clka
      .ena(1),  // input wire ena
      .wea(buffer0_write_en),  // input wire [0 : 0] wea
      .addra(write_addr),  // input wire [16 : 0] addra
      .dina(camera_data_to_bram),  // input wire [13 : 0] dina

      .clkb(camera_clk),  // input wire clkb
      .addrb(read_addr),  // input wire [16 : 0] addrb
      .doutb(buffer0_read_data)  // output wire [13 : 0] doutb
  );

  image_buffer_bram_1 bram_1 (
      .clka(camera_clk),  // input wire clka
      .ena(1),  // input wire ena
      .wea(buffer1_write_en),  // input wire [0 : 0] wea
      .addra(write_addr),  // input wire [16 : 0] addra
      .dina(camera_data_to_bram),  // input wire [13 : 0] dina

      .clkb(camera_clk),  // input wire clkb
      .addrb(read_addr),  // input wire [16 : 0] addrb
      .doutb(buffer1_read_data)  // output wire [13 : 0] doutb
  );


  reg [16:0] read_addr;
  reg buffer0_read_flag, buffer1_read_flag;
  wire [13:0] buffer0_read_data;
  wire [13:0] buffer1_read_data;
  reg frame_valid_o;


  //设置对每块bram的读标志,读标志和读地址对齐,比读出的数据和帧有效信号早一拍
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      buffer0_read_flag <= 0;
      buffer1_read_flag <= 0;
    end else begin
      if (read_addr == PIXEL_SIZE) begin
        buffer0_read_flag <= 0;
        buffer1_read_flag <= 0;
      end else if (write_addr == PIXEL_SIZE - 1 && buffer0_write_flag == 1) begin
        buffer0_read_flag <= 1;
        buffer1_read_flag <= 0;
      end else if (write_addr == PIXEL_SIZE - 1 && buffer1_write_flag == 1) begin
        buffer0_read_flag <= 0;
        buffer1_read_flag <= 1;
      end else begin
        buffer0_read_flag <= buffer0_read_flag;
        buffer1_read_flag <= buffer1_read_flag;
      end
    end
  end

  //计算读地址,因为bram读出数据要在地址延后一拍才出,所以要把读地址+1,让数据全部从bram出来再清零
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      read_addr <= 0;
    end else begin
      if (buffer0_read_flag == 0 && buffer1_read_flag == 0) begin
        read_addr <= 0;
      end else if (read_addr == PIXEL_SIZE) begin
        read_addr <= 0;
      end else begin
        read_addr <= read_addr + 1;
      end
    end
  end


  //设置帧有效标志
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      frame_valid_o <= 0;
    end else begin
      if (buffer0_read_flag == 0 && buffer1_read_flag == 0) begin
        frame_valid_o <= 0;
      end else if (read_addr == PIXEL_SIZE) begin
        frame_valid_o <= 0;
      end else begin
        frame_valid_o <= 1;
      end
    end
  end

  //输出帧有效标志
  assign camera_frame_valid_o = frame_valid_o;


  //设置两个bram的输出标志
  wire bram0_out_flag, bram1_out_flag;
  assign bram0_out_flag = (buffer0_read_flag == 1) && (frame_valid_o == 1);
  assign bram1_out_flag = (buffer1_read_flag == 1) && (frame_valid_o == 1);

  //输出读到的数据
  assign camera_data_o = bram0_out_flag ? buffer0_read_data : (bram1_out_flag ? buffer1_read_data : 0);


  reg [13:0] bram0_max, bram0_min;
  reg [13:0] bram1_max, bram1_min;

  reg [13:0] bram0_buffer_max, bram0_buffer_min;
  reg [13:0] bram1_buffer_max, bram1_buffer_min;

  //计算此时输入的图像数据的最大值最小值
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      bram0_max <= 0;
      bram0_min <= 16383;
    end else begin
      if (buffer0_write_en == 0) begin
        bram0_max <= 0;
        bram0_min <= 16383;
      end else begin
        bram0_max <= (camera_data_to_bram > bram0_max) ? camera_data_to_bram : bram0_max;
        bram0_min <= (camera_data_to_bram < bram0_min) ? camera_data_to_bram : bram0_min;
      end
    end
  end

  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      bram1_max <= 0;
      bram1_min <= 16383;
    end else begin
      if (buffer1_write_en == 0) begin
        bram1_max <= 0;
        bram1_min <= 16383;
      end else begin
        bram1_max <= (camera_data_to_bram > bram1_max) ? camera_data_to_bram : bram1_max;
        bram1_min <= (camera_data_to_bram < bram1_min) ? camera_data_to_bram : bram1_min;
      end
    end
  end

  //缓存最大值最小值
  always @(posedge camera_clk or negedge reset_n) begin
    if (!reset_n) begin
      bram0_buffer_max <= 0;
      bram0_buffer_min <= 0;
      bram1_buffer_max <= 0;
      bram1_buffer_min <= 0;
    end else begin
      if (write_addr == PIXEL_SIZE - 1) begin
        bram0_buffer_max <= bram0_max;
        bram0_buffer_min <= bram0_min;
        bram1_buffer_max <= bram1_max;
        bram1_buffer_min <= bram1_min;
      end else begin
        bram0_buffer_max <= bram0_buffer_max;
        bram0_buffer_min <= bram0_buffer_min;
        bram1_buffer_max <= bram1_buffer_max;
        bram1_buffer_min <= bram1_buffer_min;
      end
    end
  end


  //输出最大值和最小值
  assign data_max = bram0_out_flag ? bram0_buffer_max : bram1_out_flag ? bram1_buffer_max : 16383;
  assign data_min = bram0_out_flag ? bram0_buffer_min : bram1_out_flag ? bram1_buffer_min : 0;

endmodule

4 直方图拉伸代码

`timescale 1ns / 1ps

module image_histogram_stretch_14_to_8 (
    input reset_n,
    input camera_clk,
    input camera_frame_valid_i,
    input [13:0] camera_data_i,
    output camera_frame_valid_o,
    output [7:0] camera_data_o,
    output [13:0] img_data,
    output img_valid,
    output [16:0] bram_read_addr,
    output [13:0] data_max,
    output [13:0] data_min,
    output reg_img_valid
);


  wire [21:0] data_sub_min_m255;
  wire [13:0] data_sub_min;

  wire [13:0] max_sub_min;

  image_frame_buffer testuu1 (
      .reset_n(reset_n),
      .camera_clk(camera_clk),
      .camera_frame_valid_i(camera_frame_valid_i),
      .camera_data_i(camera_data_i),
      .camera_frame_valid_o(img_valid),
      .camera_data_o(img_data),
      .data_max(data_max),
      .data_min(data_min),
      .bram_read_addr(bram_read_addr)
  );


  直方图拉伸
  //g = 255*(f - min)/(max - min)
  assign data_sub_min = img_data - data_min;
  assign data_sub_min_m255 = {data_sub_min, 8'b0} - data_sub_min;
  assign max_sub_min = data_max - data_min;


  div_gen_0 div (
      .aclk(camera_clk),  // input wire aclk
      .s_axis_divisor_tvalid(img_valid),  // input wire s_axis_divisor_tvalid
      .s_axis_divisor_tdata(max_sub_min),  // input wire [15 : 0] s_axis_divisor_tdata
      .s_axis_dividend_tvalid(img_valid),  // input wire s_axis_dividend_tvalid
      .s_axis_dividend_tdata(data_sub_min_m255),  // input wire [23 : 0] s_axis_dividend_tdata
      .m_axis_dout_tvalid(camera_frame_valid_o),  // output wire m_axis_dout_tvalid
      .m_axis_dout_tdata(axis_dout_tdata)  // output wire [39 : 0] m_axis_dout_tdata
  );

  wire [39 : 0] axis_dout_tdata;
  assign camera_data_o = camera_frame_valid_o ? ((axis_dout_tdata[39:16]> 255) ? 255 : axis_dout_tdata[23:16]) : 0;

  reg [23:0] delay_valid;  //延时24个时钟单位

  always @(posedge camera_clk or reset_n) begin
    if (!reset_n) begin
      delay_valid <= 0;
    end else begin
      delay_valid <= {delay_valid[22:0], img_valid};
    end
  end
  assign reg_img_valid = delay_valid[23];


endmodule

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值