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.
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) ); endmodule 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; end else BitClkAccumulator <= BitClkAccumulator + 1; end 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; else 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; 2: i2sData <= sampleR; 16: i2sData <= sampleR[ 0]; 17: i2sData <= sampleL; 18: i2sData <= sampleL; endcase end assign LrClk = (audioClkGenAcc < 16); endmodule
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: