i2s rx tx

This commit is contained in:
Imants Pulkstenis
2019-10-13 00:30:42 +03:00
parent 8a9bab7603
commit 92dd9370ad
3 changed files with 182 additions and 70 deletions
+27 -27
View File
@@ -108,8 +108,8 @@ set_property PACKAGE_PIN W5 [get_ports clk]
##Buttons
#set_property PACKAGE_PIN U18 [get_ports btnC]
#set_property IOSTANDARD LVCMOS33 [get_ports btnC]
set_property PACKAGE_PIN U18 [get_ports btnC]
set_property IOSTANDARD LVCMOS33 [get_ports btnC]
#set_property PACKAGE_PIN T18 [get_ports btnU]
#set_property IOSTANDARD LVCMOS33 [get_ports btnU]
#set_property PACKAGE_PIN W19 [get_ports btnL]
@@ -121,31 +121,31 @@ set_property PACKAGE_PIN W5 [get_ports clk]
##Pmod Header JA
##Sch name = JA1
#set_property PACKAGE_PIN J1 [get_ports {JA[0]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[0]}]
##Sch name = JA2
#set_property PACKAGE_PIN L2 [get_ports {JA[1]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[1]}]
##Sch name = JA3
#set_property PACKAGE_PIN J2 [get_ports {JA[2]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[2]}]
##Sch name = JA4
#set_property PACKAGE_PIN G2 [get_ports {JA[3]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[3]}]
##Sch name = JA7
#set_property PACKAGE_PIN H1 [get_ports {JA[4]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[4]}]
##Sch name = JA8
#set_property PACKAGE_PIN K2 [get_ports {JA[5]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[5]}]
##Sch name = JA9
#set_property PACKAGE_PIN H2 [get_ports {JA[6]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[6]}]
##Sch name = JA10
#set_property PACKAGE_PIN G3 [get_ports {JA[7]}]
#set_property IOSTANDARD LVCMOS33 [get_ports {JA[7]}]
#Pmod Header JA
#Sch name = JA1
set_property PACKAGE_PIN J1 [get_ports {da_mclk}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_mclk}]
#Sch name = JA2
set_property PACKAGE_PIN L2 [get_ports {da_lrck}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_lrck}]
#Sch name = JA3
set_property PACKAGE_PIN J2 [get_ports {da_sclk}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_sclk}]
#Sch name = JA4
set_property PACKAGE_PIN G2 [get_ports {da_sdin}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_sdin}]
#Sch name = JA7
set_property PACKAGE_PIN H1 [get_ports {ad_mclk}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_mclk}]
#Sch name = JA8
set_property PACKAGE_PIN K2 [get_ports {ad_lrck}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_lrck}]
#Sch name = JA9
set_property PACKAGE_PIN H2 [get_ports {ad_sclk}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_sclk}]
#Sch name = JA10
set_property PACKAGE_PIN G3 [get_ports {ad_sdout}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_sdout}]
+98 -9
View File
@@ -9,19 +9,108 @@
// 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 i2c_transceiver #( parameter
sclk_ws_ratio = 64,
mclk_sclk_ratio = 4
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
)(
output sclk,
input mclk,
output ws,
input sd_rx,
output sd_tx );
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 [d_width-1: 0] l_data_tx, //left channel data to transmit
input [d_width-1: 0] r_data_tx, //right channel data to transmit
output [d_width-1: 0] l_data_rx, //left channel data received
output [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 [d_width-1: 0] l_data_rx_int = 0; //internal left channel rx data buffer
reg [d_width-1: 0] r_data_rx_int = 0; //internal right channel rx data buffer
reg [d_width-1: 0] l_data_tx_int = 0; //internal left channel tx data buffer
reg [d_width-1: 0] r_data_tx_int = 0; //internal right channel tx data buffer
reg r_sd_tx = 0; //internal register
reg [d_width-1: 0] reg_r_data_rx = 0;
reg [d_width-1: 0] reg_l_data_rx = 0;
reg [d_width-1: 0] reg_r_data_tx = 0;
reg [d_width-1: 0] reg_l_data_tx = 0;
reg sclk_cnt = 0; //counter of master clocks during half period of serial clock
reg ws_cnt = 0; //counter of serial clock toggles during half period of word select
always@(mclk || reset_n) begin
if (reset_n == 0) begin
sclk_cnt <= 0; //clear mclk/sclk counter
ws_cnt <= 0; //clear sclk/ws counter
sclk_int <= 0; //clear serial clock signal
ws_int <= 0; //clear word select signal
l_data_rx_int <= 'b0; //clear internal left channel rx data buffer
r_data_rx_int <= 'b0; //clear internal right channel rx data buffer
l_data_tx_int <= 'b0; //clear internal left channel tx data buffer
r_data_tx_int <= 'b0; //clear internal right channel tx data buffer
r_sd_tx <= 0; //clear serial data transmit output
reg_l_data_rx <= 'b0; //clear left channel received data output
reg_r_data_rx <= 'b0; //clear right channel received data output
end
else if (mclk == 1) 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_rx_int <= {r_data_rx_int[d_width-2 : 0] , 0}; //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_rx_int <= {l_data_rx_int[d_width-2 : 0] , 0}; //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_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;
endmodule
+57 -34
View File
@@ -10,53 +10,76 @@
// Fs = I2SxCLK / [(CF*2) * (2*I2SDIV+ODD)*8)]
// CF = channel frame (24 bits)
//
// `include "clock_divider_param.v"
// `include "clock_enable_param.v"
// `include "debounce_switch.v"
module top #( parameter
//enable signal parameters
WAIT = 1,
WAIT_WIDTH = 2
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 clk
input clk,
input btnC,
output da_mclk,
output ad_mclk,
output da_sclk,
output ad_sclk,
output da_lrck,
output ad_lrck,
input ad_sdout,
output da_sdin
);
//------internal wires and registers--------
// wire w_enable;
wire clk48k;
wire clk25M;
wire master_clk; // 11.29 MHz master clock
wire serial_clk;
wire word_select;
wire reset_n;
wire [d_width-1: 0] r_data_tx;
wire [d_width-1: 0] l_data_tx;
wire w_sd_tx; //internal wire
//-----sub modules--------------------------
// clock_enable_param #(
// .WAIT(WAIT),
// .WIDTH(WAIT_WIDTH)
// ) clock_enable1 (
// .clk(clk),
// .enable(w_enable)
// );
clock_divider #(
.DIVIDER(1042),
.WIDTH(11)
) clk48k_gen (
.clk(clk),
.clk_out(clk48k) // 48kHz clock
//declare PLL to create 11.29 MHz master clock from 100 MHz system clock
clk_wiz_0 m_clk(
.clk_in1(clk),
.clk_out1(master_clk)
);
clock_divider #(
.DIVIDER(2),
.WIDTH(2)
) clk25M_gen (
.clk(clk),
.clk_out(clk25M) // 25MHz clock
//instantiate I2S Transceiver component
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
) i2s_transceiver (
.reset_n(reset_n), //asynchronous active low reset
.mclk(master_clk), //master clock
.sclk(serial_clk), //serial clock (or bit clock)
.ws(word_select), //word select (or left-right clock)
.sd_rx(ad_sdout), //serial data transmit
.sd_tx(w_sd_tx), //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_tx), //left channel data received
.r_data_rx(r_data_tx) //right channel data received
);
// debounce_switch debounce_switch_reset(
// .clk(clk),
// .i_switch(),
// .o_switch()
// );
//debounce reset button
debounce_switch debounce_switch_reset(
.clk(clk),
.i_switch(btnC),
.o_switch(reset_n)
);
assign da_mclk = master_clk; //output master clock to ADC
assign ad_mclk = master_clk; //output master clock to DAC
assign da_sclk = serial_clk; //output serial clock (from I2S Transceiver) to ADC
assign ad_sclk = serial_clk; //output serial clock (from I2S Transceiver) to DAC
assign da_lrck = word_select; //output word select (from I2S Transceiver) to ADC
assign ad_lrck = word_select; //output word select (from I2S Transceiver) to DAC
assign da_sdin = w_sd_tx; //assign right channel received data to transmit (to playback out received data)
endmodule