本文参考自: 原文地址
设计两个可综合的电路模块:第一个模块(M1)接受四位并行数据,并将其转化为简化I2C传输格式。sclk为输入主钟,data[3:0]为输入的四位数据,ack为请求发送数据信号(请求后才有数据发送到data[3:0]),数据流用scl和sda两条线传输。第二个模块(M2)接收以简化I2C协议通过scl和sda传输来的数据,并转化为相应16条信号线上的高电平,若数据为1,则第一条线路为高电平,数据为n,则第N条线路为高电平。模块如下图所示。
本文引用自https://blog.youkuaiyun.com/llxxyy507/article/details/81046981
简化的I2C通信协议如下:scl为时钟信号,当scl为高电平的时候,sda从高电平变为低电平,表示串行数据流开始传输;当scl为高电平,sda从低电平变为高电平的时候,表示串行数据流结束。sda信号只能在scl为低电平的时候变化,在scl为高电平期间应该维持稳定。
上图中,sda信号在scl为高时从高变低,为数据流的开始。在scl为低电平时传输第一位数据(MSB),并在整个scl为高的期间都维持信号的稳定,接着传递剩下的数据。sda信号在scl为高时从低变高,表示数据流的结束。
模块M1的verilog代码(ptosda.v)如下:
module ptosda(sclk,rst,data,ack,scl,sda);
input sclk,rst,data;
wire [3:0]data;
output scl,sda,ack;
reg scl,ack,link_sda,sdabuf;
reg [3:0]databuf;
reg [7:0]state;
out16hi m2(.scl(scl), .sda(sda), .outhigh() ); //调用M2模块
assign sda = link_sda ? sdabuf : 1'b0; //link_sda控制sdabuf输出到串行总线上
parameter ready = 8'b0000_0000,
start = 8'b0000_0001,
bit1 = 8'b0000_0010,
bit2 = 8'b0000_0100,
bit3 = 8'b0000_1000,
bit4 = 8'b0001_0000,
bit5 = 8'b0010_0000,
stop = 8'b0100_0000,
IDLE = 8'b1000_0000;
always @(posedge sclk or negedge rst) //主钟sclk产生串行输出时钟clk
begin
if (!rst)
scl <= 1