某协议接收响应模块

最近一直在研究IIC和SPI协议,尝试用verilog写出来,前辈建议从SPI入手,因为相对简单,但是针对SPI的4种模式大框架搭起来了,但是内部并转串怎么写毫无头绪。刚好看到夏宇闻老师编写的《Verilog数字系统设计教程》一书中第15章有讲这类内容,就抄了一下代码大概感受了一下。

抄没用,得自己写。先从简单的接收模块写起,进行替代。

协议内容如下:

scl为不断输出的时钟信号,如果scl为高电平时,sda由高变低时刻,串行数据开始;如果scl为高电平时,sda由低变高,串行数据结束。sda信号的串行数据位必须在scl为低时变化,若变高则为1,否则为0.(接收模块在scl为高电平进行采样)

该接收模块接收到数据后转换为相应的16条信号线的高电平。即数据为1,则第一条线路为高电平;数据为n,则第n条路线为高电平。

这个协议是不是有点脸熟?简直就是简化版本的IIC协议啊。

将夏老师的代码逻辑看懂后,自己写的代码如下:

module echo(scl,sda,outhigh);
input scl;
input sda;
output [15:0] outhigh;

reg [15:0] outhigh;

reg startflag;
reg endflag;

reg [4:0] mstate;

reg [3:0] pdata;
reg [3:0] pdatabuf;

parameter sbit0 = 5'b0_0001,
sbit1 = 5'b0_0010,
sbit2 = 5'b0_0100,
sbit3 = 5'b0_1000,
sbit4 = 5'b1_0000;

always @ (negedge sda)
begin
if (scl)
startflag <= 1;
//else
if (endflag)
startflag <= 0;
end

always @ (posedge sda)
begin
if (scl)
begin
endflag <= 1;
pdata <= pdatabuf;
end
else
endflag <= 0;
end

always @ (pdata)
begin
case (pdata)
4'b0001: outhigh <= 16'b0000_0000_0000_0001;
4'b0010: outhigh <= 16'b0000_0000_0000_0010;
4'b0011: outhigh <= 16'b0000_0000_0000_0100;
4'b0100: outhigh <= 16'b0000_0000_0000_1000;
4'b0101: outhigh <= 16'b0000_0000_0001_0000;
4'b0110: outhigh <= 16'b0000_0000_0010_0000;
4'b0111: outhigh <= 16'b0000_0000_0100_0000;
4'b1000: outhigh <= 16'b0000_0000_1000_0000;
4'b1001: outhigh <= 16'b0000_0001_0000_0000;
4'b1010: outhigh <= 16'b0000_0010_0000_0000;
4'b1011: outhigh <= 16'b0000_0100_0000_0000;
4'b1100: outhigh <= 16'b0000_1000_0000_0000;
4'b1101: outhigh <= 16'b0001_0000_0000_0000;
4'b1110: outhigh <= 16'b0010_0000_0000_0000;
4'b1111: outhigh <= 16'b0100_0000_0000_0000;
4'b0000: outhigh <= 16'b1000_0000_0000_0000;
default: outhigh <= 16'b0000_0000_0000_0000;
endcase
end

always @ (posedge scl)
begin
if (startflag)
case (mstate)
sbit0: begin
mstate <= sbit1;
pdatabuf[3] <= sda;
end
sbit1: begin
mstate <= sbit2;
pdatabuf[2] <= sda;
end
sbit2: begin
mstate <= sbit3;
pdatabuf[1] <= sda;
end
sbit3: begin
mstate <= sbit4;
pdatabuf[0] <= sda;
end
sbit4: begin
mstate <= sbit0;
end
default: mstate <= sbit0;
endcase
else mstate <= sbit0;
end
endmodule


自己写的过程中,优化了状态机的位数,并增加了case语句的default项(虽然用不上)。


同时发现有以下几个注意事项:

1.MSB还是LSB在前取决于状态机中第一次采样放入的是数据寄存器的最高位还是最低位。

2.else mstate <= sbit0;这条语句不能省略,因为这条语句相当于在开始信号到来之前将状态机初始化为sbit0.缺了这句,会导致状态机要在开始信号到来之后的第一个时钟周期之后才能初始化为sbit0.

比如:信号  00010


不缺

信号源  00010

数据位 3210

状态机 0123

采样值 0001


信号源  00010

数据位 3210

状态机 0123

采样值 0010

结果会导致只在1,3,5。。。等位循环输出,达不到想要的效果。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值