- 硬件芯片实现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
- 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
之前的领导脑子不好,天天催,代码写的很随意,将就看吧。
写的很累,给个关注可以不。
版权归原作者 mayidianzi 所有, 如有侵权,请联系我们删除。