原創單匯流排傳輸協議b2s (附全部verilog原始碼)

精橙FPGA刘工發表於2024-12-06

一、b2s協議背景介紹

本單匯流排傳輸協議為精橙FPGA團隊原創,含傳送端(transmitter)和接收端(receiver)兩部分,基於verilog語言,僅使用單個I/O口進行多位資料的傳輸,傳輸方向為單向,用於I/O不夠用的情況,已上板驗證透過,大家可直接使用。

二、b2s協議Verilog原始碼

ps. 帶★號處可根據需要進行修改.

傳送端原始碼:

原創單匯流排傳輸協議b2s (附全部verilog原始碼)
/******************************************************************************************
File Name:    b2s_transmitter.v
Function:     b2s傳送端,預設傳送32bit資料
********************************************************************************************/
 
module    b2s_transmitter
(
    clk,            //時鐘基準,不限頻率大小,但必須與接收端一致
    din,            //待傳送資料
    b2s_dout        //b2s資料輸出埠
);
parameter    WIDTH=32;    //★設定b2s傳送資料位數

input                clk;
input    [WIDTH-1:0]    din;
output                b2s_dout;


//==============================================================
//b2s資料傳送時序
//==============================================================
reg            b2s_dout_r;
reg    [3:0]    state;
reg    [9:0]    cnt;
reg    [4:0]    count;    //★與傳送資料位數保持一致(如傳送32bit資料時,count寬度為5;傳送8bit時,count寬度為4)
always @ (posedge clk)
begin
    case(state)
//初始化
    0:    begin
            count<=0;
            b2s_dout_r<=1;
            if(cnt==19)        //b2s_dout_r高電平持續20個時鐘
                begin
                    state<=1;
                    cnt<=0;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end

//開始訊號時序
    1:    begin
            b2s_dout_r<=0;
            if(cnt==19)        //b2s_dout_r低電平持續20個時鐘
                begin
                    state<=2;
                    cnt<=0;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end
    2:    begin
            b2s_dout_r<=1;
            if(cnt==19)        //b2s_dout_r高電平持續20個時鐘
                begin
                    cnt<=0;
                    state<=3;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end

//待傳送資料的邏輯電平判斷
    3:    begin
            if(din[count]==1)
                state<=4;
            else
                state<=8;
        end

//邏輯1的傳送時序
    4:    begin
            b2s_dout_r<=0;
            if(cnt==9)        //b2s_dout_r低電平持續10個時鐘
                begin
                    cnt<=0;
                    state<=5;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end
    5:    begin
            b2s_dout_r<=1;
            if(cnt==29)        //b2s_dout_r高電平持續30個時鐘
                begin
                    cnt<=0;
                    state<=6;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end

//邏輯0的傳送時序
    8:    begin
            b2s_dout_r<=0;
            if(cnt==29)        //b2s_dout_r低電平持續30個時鐘
                begin
                    cnt<=0;
                    state<=9;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end
    9:    begin
            b2s_dout_r<=1;
            if(cnt==9)        //b2s_dout_r高電平持續10個時鐘
                begin
                    cnt<=0;
                    state<=6;
                end
            else
                begin
                    cnt<=cnt+1;
                end
        end

//統計已傳送資料位數
    6:    begin
            count<=count+1'b1;
            state<=7;
        end
    7:    begin
            if(count==WIDTH)    //當一組資料所有位傳送完畢,返回並繼續下一次傳送
                begin
                    b2s_dout_r<=1;
                    if(cnt==999)    //b2s_dout_r高電平持續1000個時鐘
                        begin
                            cnt<=0;
                            state<=0;
                        end
                    else
                        begin
                            cnt<=cnt+1;
                        end
                end
            else                //當一組資料未傳送完畢,則繼續此組下一位資料的傳送
                state<=3;
        end
        
//default值設定
    default:    begin
                    state<=0;
                    cnt<=0;
                    count<=0;
                end
    endcase
end

assign    b2s_dout=b2s_dout_r;


endmodule    
View Code

接收端原始碼:

原創單匯流排傳輸協議b2s (附全部verilog原始碼)
/******************************************************************************************
File Name:    b2s_receiver.v
Function:     b2s接收端,預設接收32bit資料
********************************************************************************************/

module    b2s_receiver
(
    clk,        //時鐘基準,不限頻率大小,但必須與傳送端一致
    b2s_din,    //b2s傳送端傳送過來的訊號
    dout        //b2s接收端解碼出的資料
);
parameter    WIDTH=32;    //★設定b2s接收資料位數

input                clk;
input                b2s_din;
output    [WIDTH-1:0]    dout;


//==================================================
//b2s_din訊號邊沿檢測
//==================================================
reg    [1:0]    b2s_din_edge=2'b01;
always @ (posedge clk)
begin
    b2s_din_edge[0] <= b2s_din;
    b2s_din_edge[1] <= b2s_din_edge[0];
end


//==================================================
//time_cnt - 儲存b2c_din訊號下降沿及其最近的下一個上升沿之間的時間
//==================================================
reg    [1:0]    state0;
reg    [5:0]    time_cnt_r;
always @ (posedge clk)
begin
    case(state0)
    0:    begin
            time_cnt_r<=0;
            state0<=1;
        end
    1:    begin
            if(b2s_din_edge==2'b10)
                state0<=2;
            else
                state0<=state0;
        end
    2:    begin
            if(b2s_din_edge==2'b01)
                begin
                    state0<=0;
                end
            else 
                time_cnt_r<=time_cnt_r+1'b1;
        end
    default:    begin
                    time_cnt_r<=0;
                    state0<=0;
                end
    endcase
end


wire [5:0]    time_cnt;
assign    time_cnt=(b2s_din_edge==2'b01)?time_cnt_r:'b0;    //當b2s_din上升沿瞬間,讀取time_cnt_r的值


//==================================================
//b2s解碼時序
//==================================================
reg    [2:0]        state;
reg    [4:0]        count;    //★與接收資料位數保持一致(如接收32bit資料時,count寬度為5;接收8bit時,count寬度為4)
reg    [WIDTH-1:0]    dout_r;
always @ (posedge clk)
begin
    case(state)
    0:    begin
            count<=WIDTH;
            if((time_cnt>15)&&(time_cnt<25))    //判斷起始訊號
                state<=1;
            else
                state<=state;
        end
    1:    begin
            if((time_cnt>5)&&(time_cnt<15))        //邏輯1的條件
                begin
                    dout_r[WIDTH-1]<=1;
                    state<=2;
                end
            else if((time_cnt>25)&&(time_cnt<35))//邏輯0的條件
                begin
                    dout_r[WIDTH-1]<=0;
                    state<=2;
                end
            else
                begin
                    state<=state;
                end
        end
    2:    begin
            count<=count-1'b1;    //每讀取一個bit,count減1
            state<=3;
        end
    3:    if(count==0)            //資料讀取完畢,返回並繼續下一組資料的讀取
            begin
                state<=0;
            end
        else
            state<=4;            //資料未讀取完畢,則進行移位
    4:    begin
            dout_r<=(dout_r>>1);//資料右移1位
            state<=1;
        end
    default:    begin
                    state<=0;
                    count<=WIDTH;
                end
    endcase
end

assign    dout=(count==0)?dout_r:dout;    //每當一組資料讀取完畢,則更新一次dout的值


endmodule    
View Code

三、原始碼例化方法

呼叫傳送端,透過單個I/O傳送出一組32bit資料:

原創單匯流排傳輸協議b2s (附全部verilog原始碼)
/******************************************************************************************
File Name:  b2s_transmitter_test.v
Function:   b2s功能測試:透過b2s transmitter模組將預置的32bit資料傳送出去
********************************************************************************************/
module b2s_transmitter_test
(
        input              clk,             //基準時鐘
        output             b2s_dout         //b2s資料輸出埠
);
parameter        WIDTH=32;        //★設定b2s傳送和接收資料位寬,此處可根據需要進行修改

//==============================================================
//預置待傳送資料
//==============================================================
wire        [WIDTH-1:0]        din;
assign     din='b01010101_00111100_11011100_11001111;    //★此處可根據需要進行修改,不限於固定數值

//================================
//呼叫b2s_transmitter模組
//================================
b2s_transmitter               
#
(
        .WIDTH(WIDTH)                   //例化傳送資料位寬
)
b2s_transmitter_isnt0
(
        .clk        (clk),              //時鐘基準,不限頻率大小,但必須與接收端一致
        .din        (din),              //待傳送資料
        .b2s_dout   (b2s_dout)          //b2s資料輸出埠
);


endmodule
View Code

呼叫接收端,解碼傳送端所發出的32bit資料:

原創單匯流排傳輸協議b2s (附全部verilog原始碼)
/******************************************************************************************
File Name:  b2s_receiver_test.v
Function:   b2s功能測試:透過b2s receiver模組進行對b2s transmitter傳送的資料進行接收解碼
********************************************************************************************/
module b2s_receiver_test
(
        input                      clk,                 //基準時鐘
        input                      b2s_dout,            //b2s傳送端傳送過來的訊號
        output        [31:0]       dout                 //解碼出的32bit資料
);
parameter         WIDTH=32;        //★設定b2s傳送和接收資料位數,此處可根據需要進行修改

//================================
//呼叫b2s_receiver模組
//================================
b2s_receiver               
#
(
        .WIDTH          (WIDTH)          //例化接收資料位寬
)
b2s_receiver_inst0
(
        .clk            (clk),           //時鐘基準,不限頻率大小,但必須與傳送端一致
        .b2s_din        (b2s_dout),      //b2s傳送端傳送過來的訊號
        .dout           (dout)           //b2s接收端解碼出的資料
);


endmodule        
View Code

四、總結

本協議優缺點如下:
優點:

1. 僅使用單個I/O口進行多bit資料傳送和接收(序列),可節省大量I/O口留作它用。
2. 傳輸頻率不限,只需保證傳送端和接收端工作頻率一致即可。
3. 接收端所得到的資訊始終是最新的,傳輸頻率高時,近乎實時。
4. 傳送和接收資料bit數量可根據需要進行增加/減少。
缺點:

1. 由於單線,無其他控制訊號,傳送端和接收端會一直處於工作狀態(傳送端一直髮,接收端一直接)。

原創單匯流排傳輸協議b2s (附全部verilog原始碼)

如您有此功能的定製開發或其他的FPGA設計需求,請檢視下面這篇文章瞭解我們的業務範圍和聯絡方式,我們將竭誠為您服務。

精橙FPGA,一個承接FPGA程式碼設計的資深工程師團隊。

相關文章