repaired i2s (loopback audio working)
This commit is contained in:
+2
-4
@@ -42,11 +42,9 @@ reg ws_int = 0; //internal word select wire
|
||||
reg signed [d_width-1: 0] l_data_rx_int = 'sb0; //internal left channel rx data buffer
|
||||
reg signed [d_width-1: 0] r_data_rx_int = 'sb0; //internal right channel rx data buffer
|
||||
|
||||
reg signed [d_width-1: 0] reg_r_data_rx = 'sb0;
|
||||
reg signed [d_width-1: 0] reg_l_data_rx = 'sb0;
|
||||
|
||||
|
||||
reg [2: 0] sclk_cnt = 0; //counter of master clocks during half period of serial clock
|
||||
reg [3: 0] sclk_cnt = 0; //counter of master clocks during half period of serial clock
|
||||
reg [7: 0] ws_cnt = 0; //counter of serial clock toggles during half period of word select
|
||||
|
||||
|
||||
@@ -61,7 +59,7 @@ always@(posedge mclk, posedge reset_n) begin
|
||||
l_data_rx_int <= 'sb0; //clear internal left channel rx data buffer
|
||||
r_data_rx_int <= 'sb0; //clear internal right channel rx data buffer
|
||||
end
|
||||
else begin //master clock rising edge
|
||||
else begin //master clock rising edge
|
||||
if (sclk_cnt < mclk_sclk_ratio/2-1) begin //less than half period of sclk
|
||||
sclk_cnt <= sclk_cnt + 1; //increment mclk/sclk counter
|
||||
end
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ always@(posedge mclk, posedge reset_n) begin
|
||||
if (ws_cnt < sclk_ws_ratio - 1) begin //less than half period of ws
|
||||
ws_cnt <= ws_cnt + 1; //increment sclk/ws counter
|
||||
|
||||
if (sclk_int == 1 && ws_cnt > 1 && ws_cnt < d_width*2+3) begin //falling edge of sclk during data word
|
||||
if (sclk_int == 1 && ws_cnt >= 1 && ws_cnt < d_width*2+3) begin //falling edge of sclk during data word
|
||||
if (ws_int == 1) begin //right channel
|
||||
sd_tx <= r_data_tx_int[d_width-1]; //transmit serial data bit
|
||||
r_data_tx_int <= {r_data_tx_int[d_width-2 : 0] , 1'b0}; //shift data of right channel tx data buffer
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
// This I2S Playback design uses the common 44.1 kHz
|
||||
// sampling frequency.
|
||||
// From Figure 2 in Section 4.1.1 of the CS5343
|
||||
// Datasheet, it is appropriate to use an SCLK/LRCK
|
||||
// ratio of 64 and a MCLK/LRCK ratio of 256.
|
||||
// Therefore, the I2S Transceiver’s generic
|
||||
// parameter sclk_ws_ratio is set to 64.
|
||||
// (LRCK, e.g. left-right clock, and ws,
|
||||
// e.g. word select, are synonymous.)
|
||||
// The generic parameter mclk_sclk_ratio is set to 4,
|
||||
// since MCLK/SCLK = (MCLK/LRCK) / (SCLK/LRCK) = 256/64 = 4.
|
||||
//
|
||||
// As such, the word select (or left-right clock) frequency
|
||||
// is 44.1 kHz, the serial clock frequency is 44.1 kHz * 64 = 2.82 MHz,
|
||||
// and the master clock frequency is 2.82 MHz * 4 = 11.29 MHz.
|
||||
// Table 1, Section 4.1 of the CS4344 Datasheet confirms this
|
||||
// selection, listing 11.29 MHz as a common frequency
|
||||
// for the master clock when the LRCK is 44.1 kHz.
|
||||
//
|
||||
// Module is created from sample provided by
|
||||
// Digilent
|
||||
//
|
||||
|
||||
|
||||
module i2s_transceiver #( parameter
|
||||
sclk_ws_ratio = 64, // number of sclk periods per word select period
|
||||
mclk_sclk_ratio = 4, // number of mclk periods per sclk period
|
||||
d_width = 24 // data width
|
||||
)(
|
||||
input reset_n, //asynchronous active low reset
|
||||
input mclk, //master clock
|
||||
output sclk, //serial clock (or bit clock)
|
||||
output ws, //word select (or left-right clock)
|
||||
output sd_tx, //serial data transmit
|
||||
input sd_rx, //serial data receive
|
||||
input signed [d_width-1: 0] l_data_tx, //left channel data to transmit
|
||||
input signed [d_width-1: 0] r_data_tx, //right channel data to transmit
|
||||
output reg signed [d_width-1: 0] l_data_rx, //left channel data received
|
||||
output reg signed [d_width-1: 0] r_data_rx //right channel data received
|
||||
|
||||
);
|
||||
|
||||
reg sclk_int = 0; //internal serial clock wire
|
||||
reg ws_int = 0; //internal word select wire
|
||||
reg signed [d_width-1: 0] l_data_rx_int = 'sb0; //internal left channel rx data buffer
|
||||
reg signed [d_width-1: 0] r_data_rx_int = 'sb0; //internal right channel rx data buffer
|
||||
reg signed [d_width-1: 0] l_data_tx_int = 'sb0; //internal left channel tx data buffer
|
||||
reg signed [d_width-1: 0] r_data_tx_int = 'sb0; //internal right channel tx data buffer
|
||||
|
||||
reg r_sd_tx = 0; //internal register
|
||||
reg signed [d_width-1: 0] reg_r_data_rx = 'sb0;
|
||||
reg signed [d_width-1: 0] reg_l_data_rx = 'sb0;
|
||||
|
||||
|
||||
reg [2: 0] sclk_cnt = 0; //counter of master clocks during half period of serial clock
|
||||
reg [7: 0] ws_cnt = 0; //counter of serial clock toggles during half period of word select
|
||||
|
||||
|
||||
|
||||
always@(posedge mclk, posedge reset_n) begin
|
||||
|
||||
if (reset_n == 1) begin
|
||||
sclk_cnt <= 'b0; //clear mclk/sclk counter
|
||||
ws_cnt <= 'b0; //clear sclk/ws counter
|
||||
sclk_int <= 0; //clear serial clock signal
|
||||
ws_int <= 0; //clear word select signal
|
||||
l_data_rx_int <= 'sb0; //clear internal left channel rx data buffer
|
||||
r_data_rx_int <= 'sb0; //clear internal right channel rx data buffer
|
||||
l_data_tx_int <= 'sb0; //clear internal left channel tx data buffer
|
||||
r_data_tx_int <= 'sb0; //clear internal right channel tx data buffer
|
||||
r_sd_tx <= 0; //clear serial data transmit output
|
||||
//reg_l_data_rx <= 'sb0; //clear left channel received data output
|
||||
//reg_r_data_rx <= 'sb0; //clear right channel received data output
|
||||
end
|
||||
else begin //master clock rising edge
|
||||
if (sclk_cnt < mclk_sclk_ratio/2-1) begin //less than half period of sclk
|
||||
sclk_cnt <= sclk_cnt + 1; //increment mclk/sclk counter
|
||||
end
|
||||
else begin //half period of sclk
|
||||
sclk_cnt <= 0; //reset mclk/sclk counter
|
||||
sclk_int <= ~sclk_int; //toggle serial clock
|
||||
if (ws_cnt < sclk_ws_ratio - 1) begin //less than half period of ws
|
||||
ws_cnt <= ws_cnt + 1; //increment sclk/ws counter
|
||||
if (sclk_int == 0 && ws_cnt > 1 && ws_cnt < d_width * 2 + 2) begin //rising edge of sclk during data word
|
||||
if (ws_int == 1) begin //right channel
|
||||
r_data_rx_int <= {r_data_rx_int[d_width-2 : 0] , sd_rx}; //shift data bit into right channel rx data buffer
|
||||
end else begin //left channel
|
||||
l_data_rx_int <= {l_data_rx_int[d_width-2 : 0] , sd_rx}; //shift data bit into left channel rx data buffer
|
||||
end
|
||||
end
|
||||
|
||||
if (sclk_int == 1 && ws_cnt > 1 && ws_cnt < d_width*2+3) begin //falling edge of sclk during data word
|
||||
if (ws_int == 1) begin //right channel
|
||||
r_sd_tx <= r_data_tx_int[d_width-1]; //transmit serial data bit
|
||||
r_data_tx_int <= {r_data_tx_int[d_width-2 : 0] , 1'b0}; //shift data of right channel tx data buffer
|
||||
end else begin //left channel
|
||||
r_sd_tx <= l_data_tx_int[d_width-1]; //ransmit serial data bit
|
||||
l_data_tx_int <= {l_data_tx_int[d_width-2 : 0] , 1'b0}; //shift data of left channel tx data buffer
|
||||
end
|
||||
end
|
||||
end else begin //half period of ws
|
||||
ws_cnt <= 0; //reset sclk/ws counter
|
||||
ws_int <= ~ws_int; //toggle word select
|
||||
// reg_r_data_rx <= r_data_rx_int; //output right channel received data
|
||||
// reg_l_data_rx <= l_data_rx_int; //output left channel received data
|
||||
r_data_rx <= r_data_rx_int; //output right channel received data
|
||||
l_data_rx <= l_data_rx_int; //output left channel received data
|
||||
r_data_tx_int <= r_data_tx; //latch in right channel data to transmit
|
||||
l_data_tx_int <= l_data_tx; //latch in left channel data to transmit
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign sclk = sclk_int; //output serial clock
|
||||
assign ws = ws_int; //output word select
|
||||
assign sd_tx = r_sd_tx; //assign sd_tx
|
||||
//assign r_data_rx = reg_r_data_rx;
|
||||
//assign l_data_rx = reg_l_data_rx;
|
||||
|
||||
//assign r_data_rx = ~(ws_cnt < sclk_ws_ratio - 1)? r_data_rx_int: r_data_rx ;
|
||||
//assign l_data_rx = ~(ws_cnt < sclk_ws_ratio - 1)? l_data_rx_int: l_data_rx ;
|
||||
|
||||
endmodule
|
||||
@@ -1,87 +0,0 @@
|
||||
// This file is Test Bench for top_vga_mem module
|
||||
//
|
||||
//
|
||||
|
||||
// 100MHz clock on Basys3 -> 10ns period
|
||||
// 50% duty cycle 5ns HIGH and 5ns LOW
|
||||
//`timescale [time unit] / [time precision]
|
||||
`timescale 10 ns / 1ns
|
||||
|
||||
|
||||
//top module
|
||||
`include "i2s_transceiver.v"
|
||||
|
||||
module i2s_transceiver_tb#( parameter
|
||||
sclk_ws_ratio = 48, // number of sclk periods per word select period
|
||||
mclk_sclk_ratio = 4, // number of mclk periods per sclk period
|
||||
d_width = 24 // data width
|
||||
)();
|
||||
|
||||
reg clk = 1'b0;
|
||||
reg reset_n = 0;
|
||||
reg sd_rx = 0;
|
||||
reg [d_width-1: 0] l_data_tx = 0;
|
||||
reg [d_width-1: 0] r_data_tx = 0;
|
||||
|
||||
wire sclk;
|
||||
wire ws;
|
||||
wire sd_tx;
|
||||
wire [d_width-1: 0] l_data_rx;
|
||||
wire [d_width-1: 0] r_data_rx;
|
||||
|
||||
// 50% duty cycle clock
|
||||
always #0.5 clk <= ~clk;
|
||||
|
||||
always #4 sd_rx <= ~sd_rx;
|
||||
|
||||
i2s_transceiver #(
|
||||
.mclk_sclk_ratio(mclk_sclk_ratio), //number of mclk periods per sclk period
|
||||
.sclk_ws_ratio(sclk_ws_ratio), //number of sclk periods per word select period
|
||||
.d_width(d_width) //data width
|
||||
) UUT(
|
||||
.reset_n(reset_n), //asynchronous active low reset
|
||||
.mclk(clk), //master clock
|
||||
.sclk(sclk), //serial clock (or bit clock)
|
||||
.ws(ws), //word select (or left-right clock)
|
||||
.sd_tx(sd_tx), //serial data transmit
|
||||
.sd_rx(sd_rx), //serial data receive
|
||||
.l_data_tx(l_data_tx), //left channel data to transmit
|
||||
.r_data_tx(r_data_tx), //right channel data to transmit
|
||||
.l_data_rx(l_data_rx), //left channel data received
|
||||
.r_data_rx(r_data_rx) //right channel data received
|
||||
);
|
||||
|
||||
|
||||
initial begin
|
||||
#0
|
||||
reset_n <= 0;
|
||||
// #200
|
||||
l_data_tx = 'hbbbbbb;
|
||||
r_data_tx = 'haaaaaa;
|
||||
// #20
|
||||
// sd_rx = 'h1;
|
||||
end
|
||||
|
||||
|
||||
|
||||
initial begin
|
||||
#3_000_000;
|
||||
$display("*");
|
||||
|
||||
$display(" ");
|
||||
$display("Use this command to open timing diagram:");
|
||||
$display("gtkwave -f wave.vcd");
|
||||
$display("----------------------------------------------");
|
||||
$finish();
|
||||
end
|
||||
|
||||
initial
|
||||
begin
|
||||
$display(" ");
|
||||
$display("----------------------------------------------");
|
||||
$display(" Starting Testbench...");
|
||||
$dumpfile("wave.vcd");
|
||||
$dumpvars(0);
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user