原创单总线传输协议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
接收端源码:
/****************************************************************************************** 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
三、源码例化方法
调用发送端,通过单个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
调用接收端,解码发送端所发出的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
四、总结
本协议优缺点如下:
优点:
1. 仅使用单个I/O口进行多bit数据发送和接收(串行),可节省大量I/O口留作它用。
2. 传输频率不限,只需保证发送端和接收端工作频率一致即可。
3. 接收端所得到的信息始终是最新的,传输频率高时,近乎实时。
4. 发送和接收数据bit数量可根据需要进行增加/减少。
缺点:
1. 由于单线,无其他控制信号,发送端和接收端会一直处于工作状态(发送端一直发,接收端一直接)。
如您有此功能的定制开发或其他的FPGA设计需求,请查看下面这篇文章了解我们的业务范围和联系方式,我们将竭诚为您服务。
精橙FPGA,一个承接FPGA代码设计的资深工程师团队。