Recently, I am working on cmos industrial camera. For some cmos chips, such as linear array cameras, pixel data of multiple channels will be output at the same time. However, in our actual use, these data are often written into the cpu memory in a serial way, and then processed in the next step. In this way, the pixel signals output by cmos need to be buffered and read out in order according to the needs of the back-end module.
Therefore, a multi-channel buffer processing and merging output module of cmos pixel effective signal is written and encapsulated into IP backup.
The format of this document is written according to the IP description of the work, and the complete code is given at the end of the text.
The usual format of cmos chip output signal
As shown in the figure above, when the frame is valid and the line is valid, it represents the output of valid data. Through the frame signal, we can know when a frame starts, and through the line signal, we can know when the output data is valid after the start of a frame. The pixel data can be correctly received by referring to and processing these signals.
1. Function overview
• It is used for cmos sensor video data acquisition. The effective signals of multi-channel cmos pixels are cached and combined for output
• It can carry out integrated output of 1 ~ 16 channels
• Software design based on vivado 18.3
2. Instructions
Figure 1 IP core port diagram
Table 1.DVP_AXI stream IP core port list
Port / parameter | type | explain |
sys_clk | input | Input clock, up to 100MHz |
rst | input | Reset signal, high level active |
en | input | Enable signal input, high level active |
cmos_signal | input | Single channel data valid signal input |
Out_channel | input | Multi channel data valid signal combined output |
Channels | / | Number of channels to output (1-16) |
Delay Line | / | Delay parameter between each line of output signal (unit: system clock) |
Num Lines | / | cmos_ Number of rows of valid data per frame of signal signal |
explain:
Figure 2. Schematic diagram of input signal
- CMOS for input signal_ Signal requirements.
The number of lines per frame should be consistent;
The line time of each line can be inconsistent, but the difference shall not be too large, and the difference shall be less than 100 clock cycles;
The "line spacing" of the signal shall not be too large, and shall not be greater than "line time";
The "frame spacing" of the signal shall be large enough and shall not be less than (line time X Channel+Delay Line) X Num Lines.
- Requirements for input signal en.
The en signal should be in CMOS_ The signal is raised before it is valid or within the frame interval, and should not be in the CMOS_ The valid period of signal is raised, which will make the multi-channel output of the current frame incomplete.
- Requirements for parameters.
The Channels parameter ranges from 1 to 16, that is, the module can output 16 channel signals at most and 1 channel signals at least.
Delay Line The setting value of the parameter shall not be less than the row time difference of adjacent rows.
Num Lines The parameter setting value should be the same as the actual input CMOS_ The line value of each frame of signal signal is consistent, that is, the line value of input signal shall be determined in advance before using this module.
3. Function simulation
Write the test module code, specifically to instantiate the IP module in the test module, and generate the corresponding PWM waveform as the signal input of the IP core. PWM wave reference codes are as follows:
always@(posedge clk ) begin if(rst) r_pwm_signal <= 1'b0; else begin case(cnt1) 0:r_pwm_signal <= 1'b1; 512:r_pwm_signal <= 1'b0; 1024:r_pwm_signal <= 1'b1; 1524:r_pwm_signal <= 1'b0; 2024:r_pwm_signal <= 1'b1; 2624:r_pwm_signal <= 1'b0; 3224:r_pwm_signal <= 1'b1; 3736:r_pwm_signal <= 1'b0; 4248:r_pwm_signal <= 1'b1; 4760:r_pwm_signal <= 1'b0; 5272:r_pwm_signal <= 1'b1; 5772:r_pwm_signal <= 1'b0; 6272:r_pwm_signal <= 1'b1; 6872:r_pwm_signal <= 1'b0; 7472:r_pwm_signal <= 1'b1; 7984:r_pwm_signal <= 1'b0; default:r_pwm_signal <= r_pwm_signal; endcase end end
Write testbench for simulation. Set the parameters Channel=16, Delay Line=100, Num Lines=8. The simulation waveform is shown in the figure below.
Figure 3. Function simulation waveform
Figure 4. Function simulation waveform
It can be seen that the enable signal is pulled high in the frame interval stage, and the multi-channel output starts after that. The output signal is 16 channel 8-line output, Out_channel signal is the combined output of multi-channel signals. The line time of each line of the output signal is consistent with the input signal, and the line interval of the input signal is consistent with the Delay Line setting.
Attached, main code:
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2021/10/17 20:54:24 // Design Name: // Module Name: mulitchannal_out // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module multichannel_out( input sys_clk, input rst, input en, input cmos_signal, output wire Out_channel ); //Parameter definition parameter NUM_lines=8; //Rows per (frame) parameter CHANNELS=16; //Number of output channels parameter DELAY_line=50; //n channel outputs, delay between each group parameter IDLE=2'b00; //Waiting state parameter WORK=2'b01; //Idle state //Internal register and connection definition reg [10:0]counter=11'd0; //High pulse counter for input signal reg [10:0]r_counter=11'd0; //The high pulse counter of the input signal takes a beat reg r_cmos_signal0=1'b0; reg r_cmos_signal=1'b0; //Input signal register reg f_vaild_cmos_signal=1'b0; //Input the falling edge flag of the signal, and store the counter in fifo at each falling edge wire [10:0]R_cnt; //fifo reads out the current pixel row width count value wire [10:0]R_cnt1; reg [10:0]r_R_cnt=11'd0; reg [1:0]state; //Status register reg [15:0]cnt=1; //Represents the duration of each multi-channel output task unit, and the initial value is changed to 1 reg [15:0]cnt1=1; reg [7:0]cnt_line_vaild=8'd0; //Each line in a frame is counted once reg fifo_rd_en; //fifo read enable reg r_pluse_out1; reg r_pluse_out2; reg r_pluse_out3; reg r_pluse_out4; reg r_pluse_out5; reg r_pluse_out6; reg r_pluse_out7; reg r_pluse_out8; reg r_pluse_out9; reg r_pluse_out10; reg r_pluse_out11; reg r_pluse_out12; reg r_pluse_out13; reg r_pluse_out14; reg r_pluse_out15; reg r_pluse_out16; wire out_channel1; /***************************************************************************************** ********************************** Logic Beginning ************************************ ******************************************************************************************/ /******First, count and cache the high pulse of the input signal (the duration of each peak of the input signal is different)******/ always@(posedge sys_clk )begin if (en) begin r_cmos_signal0<=cmos_signal; r_cmos_signal<=r_cmos_signal0; end else begin r_cmos_signal0<=1'b0; r_cmos_signal<=1'b0; end end always@(posedge sys_clk )begin if(rst) counter<=11'd0; else if (r_cmos_signal0) counter<=counter+1'd1; else counter<=11'd0; end always@(posedge sys_clk )begin r_counter<=counter; end //Get R_ cmos_ The falling edge flag of signal0 signal is used to enable fifo to write the count value of counter always@(posedge sys_clk )begin //Extract the falling edge of the input signal if(rst) f_vaild_cmos_signal<=1'd0; else if ({r_cmos_signal0,r_cmos_signal}==2'b01) f_vaild_cmos_signal<=1'd1; else f_vaild_cmos_signal<=1'd0; end //Instantiate fifo, r_counter cache and read it in time fifo_generator_0 u_fifo_generator_0 ( .clk(sys_clk), // input wire clk .rst(rst), // input wire rst .din(r_counter), // input wire [10 : 0] din .wr_en(f_vaild_cmos_signal), // input wire wr_en .rd_en(fifo_rd_en), // input wire rd_en .dout(R_cnt), // output wire [10 : 0] dout .full(), // output wire full .empty() // output wire empty ); assign R_cnt1=(R_cnt==0)?1:R_cnt; /******************************************State transition******************************************/ always@(posedge sys_clk )begin //Synchronous reset if(rst) begin state<=IDLE; fifo_rd_en<=1'b0;end else begin case(state) IDLE: begin if(f_vaild_cmos_signal)begin // When the falling edge of the input signal arrives, it switches to the working state fifo_rd_en<=1'b1; state<=WORK;end else begin fifo_rd_en<=1'b0; state<=IDLE;end end WORK:begin begin if ((cnt_line_vaild==NUM_lines)) //When all lines in a frame are output, it transitions to the idle state state<=IDLE; else state<=state; end begin if(cnt==(r_R_cnt*CHANNELS+DELAY_line)) fifo_rd_en<=1'b1; else fifo_rd_en<=1'b0; end end default: state<=IDLE; endcase end end /******************************************State related logic******************************************/ always @(posedge sys_clk)begin //In WORK status, r_R_cnt1 deposit if(state==WORK) r_R_cnt<=R_cnt1; else r_R_cnt<=11'd0; end always @(posedge sys_clk)begin //In WORK status, the signal is output by channel if (rst)begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if (state==WORK) begin if((cnt1>0)&(cnt1<=r_R_cnt)) begin r_pluse_out1<=1'b1; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt)&(cnt1<=r_R_cnt*2)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b1; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*2)&(cnt1<=r_R_cnt*3)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b1; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*3)&(cnt1<=r_R_cnt*4)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b1; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*4)&(cnt1<=r_R_cnt*5)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b1; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*5)&(cnt1<=r_R_cnt*6)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b1; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*6)&(cnt1<=r_R_cnt*7)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b1; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*7)&(cnt1<=r_R_cnt*8)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b1; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*8)&(cnt1<=r_R_cnt*9)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b1; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*9)&(cnt1<=r_R_cnt*10)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b1; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*10)&(cnt1<=r_R_cnt*11)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b1; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*11)&(cnt1<=r_R_cnt*12)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b1; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*12)&(cnt1<=r_R_cnt*13)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b1; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*13)&(cnt1<=r_R_cnt*14)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b1; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*14)&(cnt1<=r_R_cnt*15)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b1; r_pluse_out16<=1'b0; end else if ((cnt1>r_R_cnt*15)&(cnt1<=r_R_cnt*16)) begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b1; end else begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end end else begin r_pluse_out1<=1'b0; r_pluse_out2<=1'b0; r_pluse_out3<=1'b0; r_pluse_out4<=1'b0; r_pluse_out5<=1'b0; r_pluse_out6<=1'b0; r_pluse_out7<=1'b0; r_pluse_out8<=1'b0; r_pluse_out9<=1'b0; r_pluse_out10<=1'b0; r_pluse_out11<=1'b0; r_pluse_out12<=1'b0; r_pluse_out13<=1'b0; r_pluse_out14<=1'b0; r_pluse_out15<=1'b0; r_pluse_out16<=1'b0; end end always@(posedge sys_clk )begin //When it is in WORK state, count and delay after one row of pixel output is completed, if (rst) cnt<=16'd1; else if(state==WORK)begin if(cnt==(r_R_cnt*CHANNELS+DELAY_line)) cnt<=16'd1; else cnt<=cnt+1'd1; end else cnt<=16'd1; end always@(posedge sys_clk )begin cnt1<=cnt; end always@(posedge sys_clk )begin //End of each line CNT_ line_ Void plus one if (rst) cnt_line_vaild<=8'd0; else if (state==WORK) begin if((cnt1==(r_R_cnt*CHANNELS)))begin if (cnt_line_vaild==NUM_lines) cnt_line_vaild<=8'd0; else cnt_line_vaild<=cnt_line_vaild+1'd1;end else cnt_line_vaild<=cnt_line_vaild;end else cnt_line_vaild<=0; end //Multi channel signal combined output assign out_channel1=r_pluse_out1||(r_pluse_out2&(CHANNELS>=2))||(r_pluse_out3&(CHANNELS>=3))||(r_pluse_out4&(CHANNELS>=4))|| (r_pluse_out5&(CHANNELS>=5))||(r_pluse_out6&(CHANNELS>=6))||(r_pluse_out7&(CHANNELS>=7))||(r_pluse_out8&(CHANNELS>=8))|| (r_pluse_out9&(CHANNELS>=9))||(r_pluse_out10&(CHANNELS>=10))||(r_pluse_out11&(CHANNELS>=11))||(r_pluse_out12&(CHANNELS>=12))|| (r_pluse_out13&(CHANNELS>=13))||(r_pluse_out14&(CHANNELS>=14))||(r_pluse_out15&(CHANNELS>=15))||(r_pluse_out16&(CHANNELS>=16)); assign Out_channel=(CHANNELS==1)?r_cmos_signal0:out_channel1; endmodule
That's all for today! These modules will be further upgraded and optimized in the future. At present, I am not mature in all aspects. I welcome criticism and correction. Let's discuss together~