I2S 发送器 Verilog 实现不工作

I2S Transmitter Verilog Implementation not working

我正在尝试在 verilog 中实现 I2S 发送器。它的数据表位于: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

测试台代码:

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

您的 negedge 块包含一个 if-else 构造,并且只会在单个时钟边沿上计算一个或另一个。因此,当 PL 为高时,SD 不会更改值。

此外,您在代码中使用了非阻塞赋值 (<=)。这大致意味着直到 always 块结束时才会评估更改。因此,即使 SD <= shift_reg[23]shift_reg <= Tdata 之后,它也不会采用 shift_reg[23] 中的新值,而是使用以前的值。如果您希望 SDshift_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

附带说明一下,我仍然不相信 DRightDLeft 实际上是常量,我可以看到它们在您的 TB 中,但数据没有意义因为你的 I2S 是恒定的。您当前的构造可能会生成一个锁存器(而不是 MUX),而我们通常不希望在我们的设计中使用它们。

您应该清理阻塞语句与非阻塞语句的使用:

始终在时钟语句中使用非阻塞赋值,即“<=”。

始终在组合(非时钟)语句中使用阻塞赋值,即“=”。

这是全行业的建议,并非个人意见。您可以在很多地方找到此推荐,例如:

http://web.mit.edu/6.111/www/f2007/handouts/L06.pdf

不完整的敏感列表(正如@Hida 所指出的)也可能导致问题。

尝试纠正这两个问题,看看它是否开始按预期工作。

另请注意,您正在使用 Q1(以及其他信号)生成 PL 信号。如果 WS 输入与您的本地时钟不同步(我假设不是),您需要在开始使用输出之前再放置一个触发器(即两个串联),以避免亚稳态问题。但是您不会在 RTL 仿真中看到这一点。