I'm new to Verilog (and HDL at all) and working with a Cyclone II EP2C5 Mini Dev Board in Quartus II (version 13sp1 to be compatible with my cheap FPGA).

I use the below two modules (one mostly just a container) to try and generate an extremely basic i2s waveform. The output is a 1411200Hz bit clock signal (with expected jitter) and a rock solid 44.1kHz LRClk / Word select signal. See the below image and compare with the hard-coded sample values I'm using. expected behavior

module i2sTest(
    input           CLK50MHZ,       //crystal input
    output          BitClk,         //1.411200 MHz, or very close at least
    output          LrClk,          //44.1 kHz aligned with BitClk falling edge
    output          i2sData

i2sOutput i2s(
    .CLK50MHZ (CLK50MHZ),
    .sampleL    (16'b1000000000000000),
    .sampleR    (16'b1000000000000000),
    .LrClk      (LrClk),
    .i2sData    (i2sData),
    .BitClk     (BitClk)


module i2sOutput (
    input                           CLK50MHZ,
    input   [15:0]      sampleL,
    input       [15:0]      sampleR,
    output  wire            BitClk,
    output  wire            LrClk,
    output  reg             i2sData

//generate the bit clock
reg [7:0] BitClkAccumulator;    //counts up to alternating 35/36 master clock cycles
reg  BitClkAccToggle;                   //tracks the alternation
always @(posedge CLK50MHZ) begin
    if ((BitClkAccumulator + 1) == (35+BitClkAccToggle)) begin
        BitClkAccumulator <= 0;
        BitClkAccToggle <= ~BitClkAccToggle;
        BitClkAccumulator <= BitClkAccumulator + 1;
assign BitClk = (BitClkAccumulator < 18);   //50% duty cycle

//generate the lr clock
reg [7:0] audioClkGenAcc;       //counts up to 64
always @(negedge BitClk) begin
    if (audioClkGenAcc + 1 == 32)
        audioClkGenAcc <= 0;
        audioClkGenAcc <= audioClkGenAcc + 1;
    case (audioClkGenAcc + 1)
        32: i2sData <= sampleL[ 0];  //I know this isn't accounting for every bit of the inputs, please ignore this for now
         1: i2sData <= sampleR[15];
         2: i2sData <= sampleR[14];
        16: i2sData <= sampleR[ 0];
        17: i2sData <= sampleL[15];
        18: i2sData <= sampleL[14];
assign LrClk = (audioClkGenAcc < 16);

However, making one of any number of slight adjustments to this code, the LrClk frequency becomes extremely unstable. My favorite example of this is as follows: if I change the i2sTest module to connect this literal to the i2sOutput module:

.sampleR (16'b0000000000000000),

Then I get this output: enter image description here Have I discovered a bug in this older version of Quartus? Am I violating a Verilog rule? What's going on here?


BitClk upon which you condition an always block is not a legitimate clock, but a derived signal.

In simple terms, Don't do that that.

Instead, clock your output registers from an actual clock, using a clock enable.

Work out your code such that the I2S data changes based on the source clock, when enabled by a determination that you are at the appropriate phase of division thereof.

It's actually impressively useful that the hardware so beautifully and observably glitched in response to this classic design mistake, as that really focuses attention on the fact that it is a mistake.

  • \$\begingroup\$ I would like to learn more about my mistake and how to avoid it (and find other places I've done the same thing). Is there a term that I can search to learn more about this type of error? "Unregistered clock signal" or something? Additionally, you stress the term 'clock enable'. How can I learn more about the appropriate use of clock enable signals and where they're strictly required? \$\endgroup\$ – Bo Thompson Oct 12 '20 at 22:21
  • \$\begingroup\$ Using clock enables rather than derived or divided clocks is exactly the thing to be reading about \$\endgroup\$ – Chris Stratton Oct 12 '20 at 22:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.