【基于FPGA的圖像處理工程】邊緣檢測工程之sccb傳輸模塊代碼解析
【基于FPGA的圖像處理工程】
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?—邊緣檢測工程:sccb傳輸模塊代碼解析
本文為明德?lián)P原創(chuàng)文章,轉(zhuǎn)載請注明出處!
Sccb傳輸模塊的功能: 按照sccb傳輸協(xié)議的時序,傳輸上游模塊的攝像頭配置指令。
?一、? ?? ???設(shè)計架構(gòu)
???下圖是官方中給出的SCCB時序圖,雖然是三線的但是我們也可以用來學(xué)習(xí)二線的時序。

?1.? ?協(xié)議開始:在SIO_C高電平期間,SIO_D由高變低,表示傳輸?shù)拈_始。如上圖所示,在開始數(shù)據(jù)傳輸時,SIO_C要先處于高電平,由SIO_D(即本模塊中的 sio_d_w 信號)先保持一段時間高電平并產(chǎn)生下降沿來標(biāo)志傳輸開始,其中SIO_D 變低到 SIO_C 變低,最少 100ns。

2.? ?? ???協(xié)議結(jié)束:在SIO_C高電平期間,SIO_D由高變低,表示數(shù)據(jù)傳輸?shù)耐V?。如上圖所示,在停止數(shù)據(jù)傳輸時,SIO_C也要首先置于高電平,由SIO_D(即本模塊中的sio_d_w信號)產(chǎn)生上升沿并保持一段時間來標(biāo)志傳輸結(jié)束,其中 SIO_C 變高到 SIO_D 變高,最少100ns。

? ?? 3.? ?? ???其他時候 ,SIO_D 只能在 SIO_C=0 時才變化。

? 4.? ?? ???時序圖中的 SIO_D 和 SIO_C,分別是本模塊中的 sio_d_w 和 sio_c 信號。
??5.? ?? ???寫寄存器的過程:a.協(xié)議開始;b.發(fā)送設(shè)備ID編號,等待;c. 發(fā)送要存入的寄存器地址,等待;d.發(fā)送要寫入的數(shù)據(jù);e.協(xié)議結(jié)束。

?6.? ?? ???讀寄存器的時序:a.協(xié)議開始;b.發(fā)送設(shè)備ID編號,等待;c. 發(fā)送要讀取的寄存器地址,等待;d. 協(xié)議結(jié)束;e.協(xié)議開始;f. 發(fā)送設(shè)備ID編號,等待;g. 讀取Byte數(shù)據(jù),NACK=1;h. 協(xié)議結(jié)束。


本模塊計數(shù)器的架構(gòu)圖如下所示

A、Count_sck:時鐘計數(shù)器。使用此計數(shù)器,來對傳輸1位數(shù)據(jù)時鐘進(jìn)行計數(shù)。本模塊時鐘是25M,周期為40ns,而SCCB傳輸1bit本模塊設(shè)定為 120*40ns,所以此計數(shù)器每次要數(shù)120個。
B、Count_bit:位計數(shù)器。使用此計數(shù)器,要對傳輸1個階段的位進(jìn)行計數(shù)。根據(jù)sccb傳輸協(xié)議,讀寄存器時序和寫寄存器時序的位長度都是不一樣的,可以通過變量bit_num來確定。C、Count_duan:階段計數(shù)器。使用此計數(shù)器,對讀或者寫的階段進(jìn)行計數(shù)。根據(jù)sccb傳輸協(xié)議,讀寄存器狀態(tài)需要兩個階段,而寫寄存器狀態(tài)只有一個階段,所以通過變量duan_num來確定。
?二、? ?? ???舉例說明
收到寫使能 wen=1(同一時刻過來了 寫數(shù)據(jù)wdata 和 寄存器地址數(shù)據(jù)sub_addr )時,產(chǎn)生如下波形。

?如上圖所示,收到 wen=1,并且 sub_addr=8’h12 和 wdata=8’h04,這意味著要向地址為8’h12的寄存器寫數(shù)據(jù)8’h04因此各個信號如下變化:
sio_c 和 sio_d_w:波形首先產(chǎn)生了開始位。然后依次發(fā)送 8’h42(固定值)和 x=1,發(fā)送 8’h12(sub_addr)和 x=1,發(fā)送 8’h04(wdata)和 x=1。之后是結(jié)束位,最后是 2 個間隔位(固定發(fā) 11)。 至此整個過程結(jié)束。en_sio_d_w:在收到 wr_en=1 開始,en_sio_d_w 就為 1,直到最后結(jié)束。
收到讀使能ren=1(同一時刻過來了寄存器地址數(shù)據(jù)sub_addr,而wdata不關(guān)心)時,產(chǎn)生如下波形。

如上圖所示,收到ren=1,并且sub_addr=8’h12(注意要展開來看,看rd_en=1時刻) ,這意味著要讀地址為8’h12的寄存器的數(shù)據(jù),因此各個信號如下變化sio_c、sio_d_w、rdata和rdata_vld:波形首先產(chǎn)生了開始位;然后依次發(fā)送8’h42(固定值)和x=1;然后再發(fā)送8’h12(sub_addr)和x=1,然后是結(jié)束位和間隔位。之后又是開始位,發(fā)送8’h43(固定值)和x=1。之后在8個sio_c周期內(nèi),取sio_d_r的值并保存到rdata中(8個值保存后,就可以產(chǎn)生1個時鐘周期的rdata_vld=1脈沖)。最后是結(jié)束位和間隔位(固定發(fā)11)。 至此整個過程結(jié)束。en_sio_d_w:在收到rd_en=1開始,en_sio_d_w就為1,直到讀取數(shù)據(jù)為0,讀取數(shù)據(jù)后為1,整個過程結(jié)束后又為0。
本模塊準(zhǔn)備好指示信號rdy在整個波形產(chǎn)生期間,以及wen=1和ren=1時,均為0(rdy可以組合邏輯產(chǎn)生并輸出)。


? ?? ?
?三、? ?? ???信號意義

? ?四、參考代碼
? 下面展出本模塊的設(shè)計,歡迎進(jìn)一步交流,如果需要源代碼,歡迎與本人聯(lián)系。
module sccb(
? ? clk? ?? ? ,
? ? rst_n? ???,
? ? ren? ?? ? ,
? ? wen? ?? ? ,
? ? sub_addr??,
? ? rdata? ???,
? ? rdata_vld ,
? ? wdata? ???,
? ? rdy? ?? ? ,
? ? sio_c? ???,
? ? sio_d_r? ?,
? ? en_sio_d_w,
? ? sio_d_w? ?? ?? ?
);
? ? //參數(shù)定義
? ? parameter? ?? ?SIO_C??= 120 ;
? ? //輸入信號定義
? ? input? ?? ?? ?? ?? ?clk? ?? ?;//25m
? ? input? ?? ?? ?? ?? ?rst_n? ? ;
? ? input? ?? ?? ?? ?? ?ren? ?? ?;
? ? input? ?? ?? ?? ?? ?wen? ?? ?;
? ? input [7:0]? ?? ?? ?sub_addr ;
? ? input [7:0]? ?? ?? ?wdata? ? ;
? ? //輸出信號定義
? ? output[7:0]? ?? ?? ?rdata? ? ;
? ? output? ?? ?? ?? ???rdata_vld;
? ? output? ?? ?? ?? ???sio_c? ? ;//208kHz
? ? output? ?? ?? ?? ???rdy? ?? ?;
? ? input? ?? ?? ?? ?? ?sio_d_r? ?;
? ? output? ?? ?? ?? ???en_sio_d_w;
? ? output? ?? ?? ?? ???sio_d_w? ?;
? ? reg? ?? ?? ?? ?? ???en_sio_d_w;
? ? reg? ?? ?? ?? ?? ???sio_d_w? ?;
? ? //輸出信號reg定義
? ? reg [7:0]? ?? ?? ???rdata? ? ;
? ? reg? ?? ?? ?? ?? ???rdata_vld;
? ? reg? ?? ?? ?? ?? ???sio_c? ? ;
? ? reg? ?? ?? ?? ?? ???rdy? ?? ?;
? ? //中間信號定義
? ? reg??[7:0]? ?? ?? ? count_sck? ???;
? ? reg??[4:0]? ?? ?? ? count_bit? ???;
? ? reg??[1:0]? ?? ?? ? count_duan? ? ;
? ? reg? ?? ?? ?? ?? ???flag_add? ?? ?;
? ? reg? ?? ?? ?? ?? ???flag_sel? ?? ???;
? ? reg??[4:0]? ?? ?? ? bit_num? ?? ? ;
? ? reg??[1:0]? ?? ?? ? duan_num? ?? ?;
? ? reg??[29:0]? ?? ?? ?out_data? ?? ?;
? ? wire? ?? ?? ?? ?? ? add_count_sck ;
? ? wire? ?? ?? ?? ?? ? end_count_sck ;
? ? wire? ?? ?? ?? ?? ? add_count_bit ;
? ? wire? ?? ?? ?? ?? ? end_count_bit ;
? ? wire? ?? ?? ?? ?? ? add_count_duan;
? ? wire? ?? ?? ?? ?? ? end_count_duan;
? ? wire? ?? ?? ?? ?? ? sio_c_h2l? ???;
? ? wire? ?? ?? ?? ?? ? sio_c_l2h? ???;
? ? wire? ?? ?? ?? ?? ? out_data_time ;
? ? wire? ?? ?? ?? ?? ? rdata_time? ? ;
? ? wire [7:0]? ?? ?? ? rd_com? ?? ???;
? ?
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?count_sck <= 0;
? ?? ???end
? ?? ???else if(add_count_sck)begin
? ?? ?? ?? ?if(end_count_sck)begin
? ?? ?? ?? ?? ? count_sck <= 0;
? ?? ?? ?? ?end
? ?? ?? ?? ?else begin
? ?? ?? ?? ?? ? count_sck <= count_sck + 1;
? ?? ?? ?? ?end
? ?? ???end
? ? end
? ? assign add_count_sck = flag_add??;
? ? assign end_count_sck = add_count_sck && count_sck == SIO_C-1;
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?count_bit <= 0;
? ?? ???end
? ?? ???else if(add_count_bit)begin
? ?? ?? ?? ?if(end_count_bit)begin
? ?? ?? ?? ?? ? count_bit <= 0;
? ?? ?? ?? ?end
? ?? ?? ?? ?else begin
? ?? ?? ?? ?? ? count_bit <= count_bit + 1;
? ?? ?? ?? ?end
? ?? ???end
? ? end
? ? assign add_count_bit = end_count_sck;
? ? assign end_count_bit = add_count_bit && count_bit == bit_num+2-1;
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?count_duan <= 0;
? ?? ???end
? ?? ???else if(add_count_duan)begin
? ?? ?? ?? ?if(end_count_duan)begin
? ?? ?? ?? ?? ? count_duan <= 0;
? ?? ?? ?? ?end
? ?? ?? ?? ?else begin
? ?? ?? ?? ?? ? count_duan <= count_duan + 1;
? ?? ?? ?? ?end
? ?? ???end
? ? end
? ? assign add_count_duan = end_count_bit;
? ? assign end_count_duan = add_count_duan && count_duan == duan_num-1;
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?flag_add <= 0;
? ?? ???end
? ?? ???else if(ren || wen)begin
? ?? ?? ?? ?flag_add <= 1;
? ?? ???end
? ?? ???else if(end_count_duan)begin
? ?? ?? ?? ?flag_add <= 0;
? ?? ???end
? ? end
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?flag_sel <= 0;
? ?? ???end
? ?? ???else if(wen)begin
? ?? ?? ?? ?flag_sel <= 0;
? ?? ???end
? ?? ???else if(ren)begin
? ?? ?? ?? ?flag_sel <= 1;
? ?? ???end
? ? end
? ? always??@(*)begin
? ?? ???if(flag_sel==1)begin
? ?? ?? ?? ?bit_num = 21;
? ?? ?? ?? ?duan_num = 2;
? ?? ???end
? ?? ???else begin
? ?? ?? ?? ?bit_num = 30;
? ?? ?? ?? ?duan_num = 1;
? ?? ???end
? ? end
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?sio_c <= 1;
? ?? ???end
? ?? ???else if(sio_c_h2l)begin
? ?? ?? ?? ?sio_c <= 0;
? ?? ???end
? ?? ???else if(sio_c_l2h)begin
? ?? ?? ?? ?sio_c <= 1;
? ?? ???end
? ? end
? ? assign sio_c_h2l = count_bit >= 0 && count_bit < (bit_num-2) && add_count_sck && count_sck == SIO_C-1;
? ? assign sio_c_l2h = add_count_sck && count_sck == SIO_C/2-1;
? ? always @ (*)begin
? ?? ???if(flag_sel==1)begin
? ?? ?? ?? ?out_data <= {1'h0,rd_com,1'h1,sub_addr,1'h1,1'h0,1'h1,9'h0};
? ?? ???end
? ?? ???else begin
? ?? ?? ?? ?out_data <= {1'h0,8'h42,1'h1,sub_addr,1'h1,wdata,1'h1,1'h0,1'h1};
? ?? ???end
? ? end
? ? assign rd_com = (flag_sel==1 && count_duan == 0)? 8'h42 : 8'h43;
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?en_sio_d_w <= 0;
? ?? ???end
? ?? ???else if(ren || wen)begin
? ?? ?? ?? ?en_sio_d_w <= 1;
? ?? ???end
? ?? ???else if(end_count_duan)begin
? ?? ?? ?? ?en_sio_d_w <= 0;
? ?? ???end
? ?? ???else if(flag_sel==1 && count_duan == 1 && count_bit == 10 && add_count_sck && count_sck == 1-1)begin
? ?? ?? ?? ?en_sio_d_w <= 0;
? ?? ???end
? ?? ???else if(flag_sel==1 && count_duan == 1 && count_bit == 18 && add_count_sck && count_sck == 1-1)begin
? ?? ?? ?? ?en_sio_d_w <= 1;
? ?? ???end
? ? end
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?sio_d_w <= 1;
? ?? ???end
? ?? ???else if(out_data_time)begin
? ?? ?? ?? ?sio_d_w <= out_data[30-count_bit-1];
? ?? ???end
? ? end
? ? assign out_data_time = count_bit >= 0 && count_bit < bit_num && add_count_sck && count_sck == SIO_C/4-1;
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?rdata <= 0;
? ?? ???end
? ?? ???else if(rdata_time)begin
? ?? ?? ?? ?rdata[17-count_bit] <= sio_d_r;
? ?? ???end
? ? end
? ? assign rdata_time = flag_sel==1 && count_duan==1 && count_bit>=10 && count_bit<18 && add_count_sck && count_sck==SIO_C/4*3-1;
? ? always??@(posedge clk or negedge rst_n)begin
? ?? ???if(rst_n==1'b0)begin
? ?? ?? ?? ?rdata_vld <= 0;
? ?? ???end
? ?? ???else if(flag_sel==1 && end_count_duan)begin
? ?? ?? ?? ?rdata_vld <= 1;
? ?? ???end
? ?? ???else begin
? ?? ?? ?? ?rdata_vld <= 0;
? ?? ???end
? ? end
? ? always??@(*)begin
? ?? ???if(ren || wen || flag_add)begin
? ?? ?? ?? ?rdy = 0;
? ?? ???end
? ?? ???else begin
? ?? ?? ?? ?rdy = 1;
? ?? ???end
? ? end
endmodule
?復(fù)制代碼
明德?lián)P專注FPGA研究,我司正在連載兩本書籍:《基于FPGA至簡設(shè)計法實現(xiàn)的圖像邊緣檢測系統(tǒng)》(http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=691)、《ASIC和FPGA時序約束理論與應(yīng)用》(http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=705),有興趣點擊觀看。