FPGA实现cameralink接口图像传输

  1. 硬件芯片实现cameralink图像传输

常用的cameralink收发芯片有DS90CR287和288,287发送288接收。只需要向芯片提供像素时钟和cameralink协议中的28位数据信号就可以实现基本的图像数据传输非常方便。关于cameralink协议的常识详见http://t.csdn.cn/XtFud

同样地,接收方可以直接接收28位数据还原位图像数据信号。

发送端代码:

示例是之前做的16位红外相机上使用cameralink发送接收模块,使用的是287、288芯片,base模式


/* Document info
document class : RES
module name    : CameraLink_Out
module purpose : video out
version        : V1.0
author         : mayidianzi
*/
///
`timescale 1ns / 1ps


module Clink(
    input I_img_frame,
    input I_img_line,
    input[15:0] I_img_data, 
    input  I_img_clk,
    output O_img_clk,
    output[27:0] O_tx_data
    );
    
/  parameter set  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

  internal signal  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//wire S_data_vld       ;
//wire S_data_vld_1     ;
//wire S_img_clk        ;
//wire S_img_fram       ;
//wire S_img_line       ;
//wire[15:0] S_img_data ;
//reg[2:0] S_count_t    ;

assign O_img_clk = I_img_clk; 
//assign S_data_vld = (S_count_t==1) ? 1 : 0;
//assign S_data_vld_1 = S_data_vld & I_img_line;

wire[7:0] S_port_a,S_port_b,S_port_c;
assign  S_port_a = I_img_data[7:0];
assign  S_port_b = I_img_data[15:8];
assign  S_port_c = 8'h0000;

assign  O_tx_data[4:0]   =  S_port_a[4:0];
assign  O_tx_data[5]     =  S_port_a[7];
assign  O_tx_data[6]     =  S_port_a[5];          
assign  O_tx_data[9:7]   =  S_port_b[2:0];
assign  O_tx_data[11:10] =  S_port_b[7:6];
assign  O_tx_data[14:12] =  S_port_b[5:3];          
assign  O_tx_data[15]    =  S_port_c[0];
assign  O_tx_data[17:16] =  S_port_c[7:6];
assign  O_tx_data[22:18] =  S_port_c[5:1];
assign  O_tx_data[23]    =  0;             //spare
assign  O_tx_data[24]    =  I_img_line;    //LVAL,line valid                                 
assign  O_tx_data[25]    =  I_img_frame;    //FVAL,frame valid
assign  O_tx_data[26]    =  1;             //DVAL,data valid
assign  O_tx_data[27]    =  S_port_a[6];
      instance       \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
 ila_0 ila_0_i(
   .clk(I_img_clk),
   .probe0(I_img_data),
   .probe1(I_img_line),
   .probe2(I_img_frame)
   );
    main programe    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\



endmodule

接收端代码


/* Document info
document class : RES
module name    : CameraLink_Out
module purpose : video out
version        : V1.0
author         : mayidianzi
*/
///
`timescale 1ns / 1ps


module Clink_B(
    input[27:0]            I_tx_data,    //
    input                I_reset,
    input                I_img_clk,
    output reg[15:0]    O_img_data, //S_sensor_data 
    output reg            O_img_frame, //S_sensor_FS 
    output reg            O_img_line //S_sensor_LINE 
    );
    
/  parameter set  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

  internal signal  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//wire S_data_vld       ;
//wire S_data_vld_1     ;
//wire S_img_clk        ;
wire S_img_frame       ;
wire S_img_line       ;
wire[15:0] S_img_data ;
//reg[2:0] S_count_t    ;

//assign S_data_vld = (S_count_t==1) ? 1 : 0;
//assign S_data_vld_1 = S_data_vld & I_img_line;

wire[7:0] S_port_a,S_port_b,S_port_c;
assign  S_img_data[7:0]    =    S_port_a ; 
assign  S_img_data[15:8]=    S_port_b ; 

assign  S_port_a[4:0]    =     I_tx_data[4:0]    ;
assign  S_port_a[7]        =     I_tx_data[5]      ;
assign  S_port_a[5]          =     I_tx_data[6]      ;        
assign  S_port_b[2:0]    =     I_tx_data[9:7]    ;
assign  S_port_b[7:6]    =     I_tx_data[11:10]  ;
assign  S_port_b[5:3]    =     I_tx_data[14:12]  ;          
assign  S_port_c[0]        =     I_tx_data[15]     ;
assign  S_port_c[7:6]    =     I_tx_data[17:16]  ;
assign  S_port_c[5:1]    =     I_tx_data[22:18]  ;
assign  S_img_line       =     I_tx_data[24]     ; //LVAL,line valid                                 
assign  S_img_frame      =     I_tx_data[25]     ;  //FVAL,frame valid
assign  S_port_a[6]        =     I_tx_data[27]     ;
      instance       \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

 ila_4 ila_4_i(
   .clk(I_img_clk),
   .probe0(O_img_data),
   .probe1(O_img_line),
   .probe2(O_img_frame),
   .probe3(I_img_clk)
   );
    main programe    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

always@(posedge I_img_clk or posedge I_reset)
begin
    if(I_reset)    
        begin
            O_img_data    <= 0;
            O_img_frame    <= 0;
            O_img_line     <= 0;
        end    
    else 
        begin
            O_img_data    <= S_img_data;
            O_img_frame    <= S_img_frame;
            O_img_line     <= S_img_line;
        end
end


endmodule
  1. FPGA编写cameralink接口模块传输

如果不使用芯片可以用verilog写一个发送接收模块,按照标准时序将28位数通过4条差分线输出,这里需要注意4条数据线的同步时钟是像素同步时钟的7倍,像素时钟不可太高。硬件布线方面注意所有的差分线要做等长。若接收端发现接收数据和采样时钟不同步可通过时钟模块适当调整同步时钟的相位。以上为调试过程的经验。

发送端代码:

同样是以16位红外相机为例,Base模式

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/22 08:31:08
// Design Name: 
// Module Name: Clink
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module Clink(
  input I_336M_CLK,
  input I_reset,
  input[15:0] I_video_data,
  input I_frame_valid,
  input I_line_valid,
  output reg O_X0,
  output reg O_X1,
  output reg O_X2,
  output reg O_X3,
  output reg O_XCLK
  );
  
//
reg[7:0] S_cnt;
reg[1:0] S_cnt0;
reg[27:0] S_tx_data;
reg S_frame_valid, S_line_valid;
reg[15:0] S_video_data;
wire[7:0] S_port_a,S_port_b,S_port_c;
assign  S_port_a = S_video_data[7:0];
assign  S_port_b = S_video_data[15:8];
assign  S_port_c = 8'h0000;
//

/*ila_0 ila_0_i(
   .clk(I_336M_CLK),
   .probe0(O_XCLK),
   .probe1(S_line_valid),
   .probe2(S_frame_valid),
   .probe3(O_X0),
   .probe4(O_X1),
   .probe5(O_X2),
   .probe6(O_X3),
   .probe7(S_cnt),
   .probe8(S_video_data)
   );*/
//
always @(posedge I_336M_CLK or negedge I_reset)
begin
    if(!I_reset)
        begin
            S_video_data     <= 0;
            S_frame_valid     <= 0;
            S_line_valid     <= 0;
        end
    else
        begin
            S_video_data     <= I_video_data;
            S_frame_valid     <= I_frame_valid;
            S_line_valid    <= I_line_valid;
        end
end

always @(posedge I_336M_CLK or negedge I_reset)
begin
    if(!I_reset)
        S_tx_data <= 0;
    else if(S_cnt == 0 & S_cnt0 == 0)
        begin
            S_tx_data[4:0]   <=  S_port_a[4:0];
            S_tx_data[5]     <=  S_port_a[7];
            S_tx_data[6]     <=  S_port_a[5];          
            S_tx_data[9:7]   <=  S_port_b[2:0];
            S_tx_data[11:10] <=  S_port_b[7:6];
            S_tx_data[14:12] <=  S_port_b[5:3];          
            S_tx_data[15]    <=  S_port_c[0];
            S_tx_data[17:16] <=  S_port_c[7:6];
            S_tx_data[22:18] <=  S_port_c[5:1];
            S_tx_data[23]    <=  0;             //spare
            S_tx_data[24]    <=  S_line_valid;    //LVAL,line valid                                 
            S_tx_data[25]    <=  S_frame_valid;    //FVAL,frame valid
            S_tx_data[26]    <=  1;             //DVAL,data valid
            S_tx_data[27]    <=  S_port_a[6];
        end
end
  
always @(posedge I_336M_CLK or negedge I_reset)
begin
    if(!I_reset)
        begin
            S_cnt0     <= 0;
            S_cnt     <= 0;    
        end
      else
        begin
            if(S_cnt0 == 1 & S_cnt == 6)
                begin
                    S_cnt0     <= 0;
                    S_cnt     <= 0;             
                end
            else if(S_cnt0 == 1)
                begin
                    S_cnt     <= S_cnt + 1;    
                    S_cnt0     <= 0;
                end
            else
                S_cnt0 <= S_cnt0 + 1;
        end
end

always @ (posedge I_336M_CLK or negedge I_reset)
begin
      if(!I_reset)
        O_XCLK <= 0;
    else if(S_cnt0 == 1)
        begin
            if(S_cnt == 5)
                O_XCLK <= 1;
            if(S_cnt == 2)
                O_XCLK <= 0;
        end
end
  
  
always @ (posedge I_336M_CLK or negedge I_reset)
begin
      if(!I_reset)
        begin
            O_X0 <= 0;
            O_X1 <= 0;
            O_X2 <= 0;
            O_X3 <= 0;
        end
      else if(S_cnt0 == 1)
        begin
            case(S_cnt)
                8'd0:
                begin
                    O_X0 <= S_tx_data[7];
                    O_X1 <= S_tx_data[18];
                    O_X2 <= S_tx_data[26];
                    O_X3 <= S_tx_data[23];
                end
                8'd1:
                begin
                    O_X0 <= S_tx_data[6];
                    O_X1 <= S_tx_data[15];
                    O_X2 <= S_tx_data[25];
                    O_X3 <= S_tx_data[17];
                  end
                8'd2:
                begin
                    O_X0 <= S_tx_data[4];
                    O_X1 <= S_tx_data[14];
                    O_X2 <= S_tx_data[24];
                    O_X3 <= S_tx_data[16];
                  end
                8'd3:
                begin
                    O_X0 <= S_tx_data[3];
                    O_X1 <= S_tx_data[13];
                    O_X2 <= S_tx_data[22];
                    O_X3 <= S_tx_data[11];
                end 
                8'd4:
                begin
                    O_X0 <= S_tx_data[2];
                    O_X1 <= S_tx_data[12];
                    O_X2 <= S_tx_data[21];
                    O_X3 <= S_tx_data[10];
                end
                8'd5:
                begin
                    O_X0 <= S_tx_data[1];
                    O_X1 <= S_tx_data[9];
                    O_X2 <= S_tx_data[20];
                    O_X3 <= S_tx_data[5];
                end
                8'd6:
                begin
                    O_X0 <= S_tx_data[0];
                    O_X1 <= S_tx_data[8];
                    O_X2 <= S_tx_data[19];
                    O_X3 <= S_tx_data[27];
                end
                default
                begin
                    O_X0 <= 0;
                    O_X1 <= 0;
                    O_X2 <= 0;
                    O_X3 <= 0;
                end     
            endcase
        end
end
endmodule

接受端

代码中含有图像数据行帧头校验内容,自行忽略


/* Document info
document class : RES
module name    : CameraLink_Out
module purpose : video out
version        : V1.0
author         : mayidianzi
*/
///
`timescale 1ns / 1ps


module Cameralink_in(
    input I_CLINK_RxCLK, 
    input I_CLINK_RxCLKx7,
    input I_CLINK_RxCLKx7_n,
    input I_RESET,
    input I_X0,  
    input I_X1, 
    input I_X2, 
    input I_X3, 
    output O_img_clk,
    output O_img_frame,
    output reg O_img_line,
    output O_img_vblank,
    output O_img_hblank,
    output[15:0] O_img_data
    );
    
/  parameter set  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
reg [27:0] S_Rx_data;
reg [27:0] S_data, S_data_d0;
reg S_RxCLK_d0, S_RxCLK_d1, S_RxCLK_d2;
wire [15:0] S_img_data;
wire S_img_line, S_img_frame;

reg[15:0] S_imgdata_d0, S_imgdata_d1, S_imgdata_d2, S_imgdata_d3, S_cnt;
reg        S_img_frame_d0, S_img_frame_d1, S_img_frame_d2, S_img_frame_d3, S_false;
reg[3:0]    S_state;
parameter    C_idle = 0,
            C_valid = 1;
  internal signal  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
ila_4 ila_4_i(
    .clk (I_CLINK_RxCLK),
    .probe0(O_img_frame),
    .probe1(O_img_line),
    .probe2(S_RxCLK_d1),
    .probe3(S_RxCLK_d2),
    .probe4(O_img_data),
    .probe5(I_X0),
    .probe6(I_X1),
    .probe7(I_X2),
    .probe8(S_false),
    .probe9(S_Rx_data),
    .probe10(S_img_data)
    );

  internal signal  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
assign O_img_vblank = ~O_img_frame;
assign O_img_hblank = O_img_frame & (~O_img_line);
wire[7:0] S_port_a, S_port_b, S_port_c;
assign  S_img_data[7:0] = S_port_a;
assign  S_img_data[15:8] = S_port_b;

assign  S_port_a[4:0] = S_data_d0[4:0];    
assign  S_port_a[7]   = S_data_d0[5];      
assign  S_port_a[5]   = S_data_d0[6];              
assign  S_port_b[2:0] = S_data_d0[9:7];    
assign  S_port_b[7:6] = S_data_d0[11:10];  
assign  S_port_b[5:3] = S_data_d0[14:12];            
//assign  S_port_c[0]   = S_data[15];     
//assign  S_port_c[7:6] = S_data[17:16];  
//assign  S_port_c[5:1] = S_data[22:18];  
assign  S_img_line    = S_data_d0[24];      //LVAL,line valid                                 
assign  S_img_frame   = S_data_d0[25];      //FVAL,frame valid
assign  S_port_a[6]   = S_data_d0[27];    
assign  O_img_frame = S_img_frame_d3;
//assign  O_img_line = S_img_line;
assign  O_img_data = S_imgdata_d3;
//assign  O_img_clk = S_RxCLK_d2;
assign    O_img_clk = I_CLINK_RxCLK;
  internal signal  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

always @(posedge I_CLINK_RxCLKx7 or posedge I_RESET)//
begin
  if(I_RESET)
    begin
      S_RxCLK_d0 <= 0;
      S_RxCLK_d1 <= 0;
      S_RxCLK_d2 <= 0;
    end
  else
   begin
    S_RxCLK_d0 <= I_CLINK_RxCLK;
    S_RxCLK_d1 <= S_RxCLK_d0;
    S_RxCLK_d2 <= S_RxCLK_d1;
   end
end

always @(posedge S_RxCLK_d2 or posedge I_RESET)// 
begin
  if(I_RESET)
    S_data <= 0;
  else
    S_data[27:0] <= {S_Rx_data[21:18],S_Rx_data[27],S_Rx_data[17:13],S_Rx_data[26:25],
                     S_Rx_data[12:9],S_Rx_data[24:23],S_Rx_data[8:5],S_Rx_data[22],S_Rx_data[4:0]};
end

always @(posedge I_CLINK_RxCLKx7_n or posedge I_RESET)//
begin
  if(I_RESET)
    S_Rx_data <= 0;
  else
    begin
      S_Rx_data[27:21] <= {S_Rx_data[26:21],I_X3};
      S_Rx_data[20:14] <= {S_Rx_data[19:14],I_X2};
      S_Rx_data[13:7]  <= {S_Rx_data[12:7],I_X1};
      S_Rx_data[6:0]   <= {S_Rx_data[5:0],I_X0};
    end
end

always @(posedge I_CLINK_RxCLK or posedge I_RESET)// 
begin
  if(I_RESET)
    S_data_d0 <= 0;
  else
    S_data_d0[27:0] <= S_data;
end

always @(posedge I_CLINK_RxCLK or posedge I_RESET)// 
begin
  if(I_RESET)
    begin
        S_imgdata_d0 <= 0;
        S_imgdata_d1 <= 0;
        S_imgdata_d2 <= 0;
        S_imgdata_d3 <= 0;
        S_img_frame_d0 <= 0;
        S_img_frame_d1 <= 0;
        S_img_frame_d2 <= 0;
        S_img_frame_d3 <= 0;
    end
  else
    begin
        S_imgdata_d0 <= S_img_data;
        S_imgdata_d1 <= S_imgdata_d0;
        S_imgdata_d2 <= S_imgdata_d1;
        S_imgdata_d3 <= S_imgdata_d2;
        S_img_frame_d0 <= S_img_frame;
        S_img_frame_d1 <= S_img_frame_d0;
        S_img_frame_d2 <= S_img_frame_d1;
        S_img_frame_d3 <= S_img_frame_d2;
    end
end

always @(posedge I_CLINK_RxCLK or posedge I_RESET)// 
begin
  if(I_RESET)
    begin
        S_state <= C_idle;
        S_cnt <= 0;
    end
  else
    begin
        case(S_state)
            C_idle:
                if(S_imgdata_d0 == 16'haa || S_imgdata_d1 == 16'hbb)
                    begin
                        S_state <= C_valid;
                        S_cnt <= 0;
                    end
                else
                    S_cnt <= S_cnt + 1;
            C_valid:
                if(S_cnt >= 645)
                    begin
                        S_cnt <= 0;
                        S_state <= C_idle;
                    end
                else
                    S_cnt <= S_cnt + 1;
        endcase
    end
end

always @(posedge I_CLINK_RxCLK or posedge I_RESET)// 
begin
  if(I_RESET)
    begin
        O_img_line <= 0;
        S_false <= 0;
    end
  else
    begin
        case(S_state)
            C_idle:
                begin
                    O_img_line <= 0;
                    if(S_cnt > 2500)
                        S_false <= 1;
                end
            C_valid:
                O_img_line <= 1;
        endcase
    end
end

endmodule

之前的领导脑子不好,天天催,代码写的很随意,将就看吧。

写的很累,给个关注可以不。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年8月9日
下一篇 2023年8月9日

相关推荐