原创单总线传输协议b2s (附全部verilog源码)

一、b2s协议背景介绍

本单总线传输协议为精橙FPGA团队原创,含传送端(transmitter)和接收端(receiver)两部分,基于verilog语言,仅使用单个I/O口进行多位数据的传输,传输方向为单向,用于I/O不够用的情况,已上板验证通过,大家可直接使用。

二、b2s协议Verilog源码

ps. 带★号处可根据需要进行修改.

发送端源码:

/******************************************************************************************
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

接收端源码:

/******************************************************************************************
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数据:

/******************************************************************************************
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数据:

/******************************************************************************************
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. 由于单线,无其他控制信号,发送端和接收端会一直处于工作状态(发送端一直发,接收端一直接)。

 

如您有此功能的定制开发或其他的FPGA设计需求,请查看下面这篇文章了解我们的业务范围和联系方式,我们将竭诚为您服务。

精橙FPGA,一个承接FPGA代码设计的资深工程师团队。

 

posted @ 2024-12-06 17:29  精橙FPGA刘工  阅读(13)  评论(0编辑  收藏  举报