【发布时间】:2021-05-16 17:34:14
【问题描述】:
我正在尝试编写一个 I2C 从站并单独测试它。
当write_ack 很高时,我有一个模拟应该将SDA 拉低(也用红点突出显示)。但是,您可以看到 SDA 保持不变。
我的一部分认为这与我使用 force 方法和延迟进行测试的方式有关。
任何帮助表示赞赏。
我找到了关键字release 似乎有帮助。
下面的代码和 EDA Playground 在这里:https://edaplayground.com/x/6snM
/**
I2C Slave to Read/Write 8 bits of data only
*/
`timescale 1ns / 1ps
module Slave(
inout wire SDA,
input wire SCL);
reg [4:0] IDLE = 4'b0000;
reg [4:0] START = 4'b0001;
reg [4:0] READ_ADDRESS = 4'b0010;
reg [4:0] READ_WRITE = 4'b0011;
reg [4:0] DATA = 4'b0100;
reg [4:0] DATA_ACK = 4'b0101;
reg [4:0] STOP = 4'b0110;
reg [4:0] ADDRESS_ACK = 4'b0111;
reg [4:0] state = 4'b0010;
reg [6:0] slaveAddress = 7'b0001000;
reg [7:0] addr;
reg [6:0] addressCounter = 7'b0000000;
reg [7:0] data;
reg [6:0] dataCounter = 7'b0000000;
reg readWrite = 1'b0;
reg start = 0;
reg write_ack = 0;
assign SDA = (write_ack == 1) ? 0 : 'b1z;
always @(negedge SDA) begin
if ((start == 0) && (SCL == 1))
begin
start <= 1;
addressCounter <= 0;
dataCounter <= 0;
end
end
always @(posedge SDA) begin
if (state == DATA_ACK && SCL == 1)
begin
start <= 0;
state <= READ_ADDRESS;
end
end
always @(posedge SCL)
begin
if (start == 1)
begin
case (state)
READ_ADDRESS:
begin
addr[addressCounter] <= SDA;
addressCounter <= addressCounter + 1;
if (addressCounter == 6)
begin
state <= READ_WRITE;
end
end
READ_WRITE:
begin
readWrite <= SDA;
state <= ADDRESS_ACK;
end
ADDRESS_ACK:
begin
write_ack <= 1;
state <= DATA;
end
DATA:
begin
write_ack <= 0;
data[dataCounter] <= SDA;
dataCounter <= dataCounter + 1;
if (dataCounter == 8)
begin
state <= DATA_ACK;
write_ack <= 1;
end
end
DATA_ACK:
begin
write_ack <= 0;
state <= STOP;
end
STOP:
begin
start <= 0;
state <= READ_ADDRESS;
end
endcase
end
end
endmodule
测试代码
/**
Testing I2C Slace for reading/writing 8 bits of data only
*/
`timescale 1ns / 1ps
module Slave_TB ();
reg clk;
wire SDA;
wire SCL;
pullup(SDA);
pullup(SCL);
reg [6:0] addressToSend = 7'b0001000;
reg readWite = 1'b1;
reg [7:0] dataToSend = 8'b01100111;
integer ii=0;
initial begin
clk = 0;
force SCL = clk;
forever begin
clk = #1 ~clk;
force SCL = clk;
end
end
Slave #() UUT
(.SDA(SDA),
.SCL(SCL));
initial
begin
$display("Starting Testbench...");
clk = 0;
force SCL = clk;
#11
// Set SDA Low to start
force SDA = 0;
// Write address
for(ii=0; ii<7; ii=ii+1)
begin
$display("Address SDA %h to %h", SDA, addressToSend[ii]);
#2 force SDA = addressToSend[ii];
end
// Are we wanting to read or write to/from the device?
$display("Read/Write %h SDA: %h", readWite, SDA);
#2 force SDA = readWite;
$display("SDA: %h", SDA);
#2; // Wait for ACK bit
for(ii=0; ii<8; ii=ii+1)
begin
$display("Data SDA %h to %h", SDA, dataToSend[ii]);
#2 force SDA = dataToSend[ii];
end
#2; // Wait for ACK bit
// Force SDA high again, we are done
#2 force SDA = 1;
#100;
$finish();
end
initial
begin
// Required to dump signals to EPWave
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
【问题讨论】:
-
一旦您将 sda 强制为任何值,该值将一直持续到释放或直到下一次强制。常规操作无法更改该值。检查你的力量的使用。此外,您不应该从不同的 always 块驱动相同的信号,如“状态”、“开始”……。你在那里要求未定义的行为。
标签: verilog test-bench