我正在尝试在verilog中实现I2S Transmitter。其数据表位于:https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf
我编写了代码,但是当我测试时,我的SD线延迟了1个时钟周期。 有人可以查看我的实施吗?
module Transmiter(
input signed [23:0] DLeft, input signed [23:0] DRight, input WS, input CLK,
output reg SD
);
wire PL;
reg Q1,Q2;
reg [23:0] shift_reg;
reg [23:0] Tdata;
assign PL = Q1^Q2;
always @(posedge CLK)
begin
Q1 <= WS;
Q2 <= Q1;
end
always @( Q1) begin
if (Q1)
begin
Tdata <= DRight;
end
else
begin
Tdata <= DLeft;
end
end
always @(negedge CLK)
begin
if(PL)
begin
shift_reg <= Tdata;
end
else begin
SD <= shift_reg[23];
shift_reg <= {shift_reg[22:0],1'b0};
end
end
endmodule
编辑:这是波形image
的图像TEST BENCH CODE:
module Transmitter_tb(
);
reg CLK, WS;
reg [23:0] dataL;
reg [23:0] dataR;
wire SDout;
Transmiter UT(dataL, dataR, WS, CLK, SDout);
initial begin
dataL = 24'hF0F0FF; #2;
dataR = 24'h0000F0; #2;
end
always begin
CLK=0; #20;
CLK=1; #20;
end;
always begin
WS=0; #1000;
WS=1; #1000;
end;
endmodule
答案 0 :(得分:1)
您的negedge
块包含if-else
结构,并且只能在单个时钟边沿计算一个或另一个。因此SD
在PL
为高时不会改变价值。
此外,您在代码中使用了非阻止分配(<=
)。这大致意味着在始终阻止结束之前不会评估变化。因此,即使在SD <= shift_reg[23]
之后shift_reg <= Tdata
,它也不会在shift_reg[23]
中使用新值,而是使用之前的值。如果您希望在SD
更改时立即更改shift_reg[23]
,则需要以组合方式执行此操作。
这应该有效:
always @(negedge CLK)
begin
if(PL)
begin
shift_reg <= Tdata;
end
else
shift_reg <= {shift_reg[22:0],1'b0};
end
assign SD = shift_reg[23];
工作示例:https://www.edaplayground.com/x/4bPv
另一方面,我仍然不相信DRight
和DLeft
实际上是常数,我可以看到它们在你的结核病中,但数据没有意义因为你的I2S是不变的。您当前的构造可能会生成一个锁存器(而不是MUX),我们通常不希望那些在我们的设计中。
答案 1 :(得分:0)
您应该清除阻塞与非阻止语句的使用:
始终在时钟语句中使用非阻塞分配,意思是“&lt; =”。
始终在组合(非时钟)语句中使用阻塞分配,即“=”。
这是一项行业范围的建议,而不是个人意见。您可以在许多地方找到此建议,例如:
http://web.mit.edu/6.111/www/f2007/handouts/L06.pdf
敏感性列表不完整(由@Hida指出)也可能导致问题。
尝试纠正这两件事,看看它是否按预期开始工作。
另请注意,您正在使用Q1(以及其他信号)来生成PL信号。如果WS输入与本地时钟不同步(我认为不是),则在开始使用输出之前需要再放一次(即两个串联),以避免亚稳态问题。但是你不会在RTL模拟中看到这一点。