This commit is contained in:
2025-05-11 23:43:59 +02:00
parent 9c20fe7e7c
commit 079d1ab0d5
21 changed files with 3372 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
`timescale 1ns / 1ps
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company: Digilent & Politecnico di Milano
// Engineer: Arthur Brown, Nicola Corna, Fabio Garzetti, Nicola Lusardi
//
// Create Date: 14/05/2019
// Module Name: axis_i2s
// Description: AXI-Stream I2S controller
// Generates clocks and select signals required to place each of the ICs on the Pmod I2S2 into slave mode.
// Data is 24-bit, shifted one serial clock right from the LRCK boundaries.
// This module only supports 44.1KHz sample rate, and expects the frequency of axis_clk to be approx 22.591MHz.
// At the end of each I2S frame, a 2-word packet is made available on the AXIS master interface. Further packets will be discarded
// until the current packet is accepted by an AXIS slave.
// Whenever a 2-word packet is received on the AXIS slave interface, it is transmitted over the I2S interface on the next frame.
// Each packet consists of two 3-byte words, starting with left audio channel data, followed by right channel data.
//
// Revision:
// Revision 0.01 - File Created
// Revision 0.02 - Use 24-bit interfaces
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module axis_dual_i2s (
input wire axis_clk, // require: approx 22.591MHz
input wire axis_resetn,
input wire [23:0] tx_axis_s_data,
input wire tx_axis_s_valid,
output reg tx_axis_s_ready = 1'b0,
input wire tx_axis_s_last,
output wire [23:0] rx_axis_m_data,
output reg rx_axis_m_valid = 1'b0,
input wire rx_axis_m_ready,
output reg rx_axis_m_last = 1'b0,
output wire tx_mclk,
output wire tx_lrck,
output wire tx_sclk,
output reg tx_sdout,
output wire rx_mclk,
output wire rx_lrck,
output wire rx_sclk,
input wire rx_sdin
);
reg [8:0] count = 9'd0;
localparam EOF_COUNT = 9'd455; // end of full I2S frame
always@(posedge axis_clk)
count <= count + 1;
wire lrck = count[8];
wire sclk = count[2];
wire mclk = axis_clk;
assign tx_lrck = lrck;
assign tx_sclk = sclk;
assign tx_mclk = mclk;
assign rx_lrck = lrck;
assign rx_sclk = sclk;
assign rx_mclk = mclk;
/* AXIS SLAVE CONTROLLER */
reg [23:0] tx_data_l = 0;
reg [23:0] tx_data_r = 0;
always@(posedge axis_clk)
if (axis_resetn == 1'b0)
tx_axis_s_ready <= 1'b0;
else if (tx_axis_s_ready == 1'b1 && tx_axis_s_valid == 1'b1 && tx_axis_s_last == 1'b1) // end of packet, cannot accept data until current one has been transmitted
tx_axis_s_ready <= 1'b0;
else if (count == 9'b0) // beginning of I2S frame, in order to avoid tearing, cannot accept data until frame complete
tx_axis_s_ready <= 1'b0;
else if (count == EOF_COUNT) // end of I2S frame, can accept data
tx_axis_s_ready <= 1'b1;
always@(posedge axis_clk)
if (axis_resetn == 1'b0) begin
tx_data_r <= 24'b0;
tx_data_l <= 24'b0;
end else if (tx_axis_s_valid == 1'b1 && tx_axis_s_ready == 1'b1)
if (tx_axis_s_last == 1'b1)
tx_data_r <= tx_axis_s_data;
else
tx_data_l <= tx_axis_s_data;
/* I2S TRANSMIT SHIFT REGISTERS */
reg [23:0] tx_data_l_shift = 24'b0;
reg [23:0] tx_data_r_shift = 24'b0;
always@(posedge axis_clk)
if (count == 3'b000000111) begin
tx_data_l_shift <= tx_data_l[23:0];
tx_data_r_shift <= tx_data_r[23:0];
end else if (count[2:0] == 3'b111 && count[7:3] >= 5'd1 && count[7:3] <= 5'd24) begin
if (count[8] == 1'b1)
tx_data_r_shift <= {tx_data_r_shift[22:0], 1'b0};
else
tx_data_l_shift <= {tx_data_l_shift[22:0], 1'b0};
end
always@(count, tx_data_l_shift, tx_data_r_shift)
if (count[7:3] <= 5'd24 && count[7:3] >= 4'd1)
if (count[8] == 1'b1)
tx_sdout = tx_data_r_shift[23];
else
tx_sdout = tx_data_l_shift[23];
else
tx_sdout = 1'b0;
/* SYNCHRONIZE DATA IN TO AXIS CLOCK DOMAIN */
reg [2:0] din_sync_shift = 3'd0;
wire din_sync = din_sync_shift[2];
always@(posedge axis_clk)
din_sync_shift <= {din_sync_shift[1:0], rx_sdin};
/* I2S RECEIVE SHIFT REGISTERS */
reg [23:0] rx_data_l_shift = 24'b0;
reg [23:0] rx_data_r_shift = 24'b0;
always@(posedge axis_clk)
if (count[2:0] == 3'b011 && count[7:3] <= 5'd24 && count[7:3] >= 5'd1)
if (lrck == 1'b1)
rx_data_r_shift <= {rx_data_r_shift, din_sync};
else
rx_data_l_shift <= {rx_data_l_shift, din_sync};
/* AXIS MASTER CONTROLLER */
reg [23:0] rx_data_l = 24'b0;
reg [23:0] rx_data_r = 24'b0;
always@(posedge axis_clk)
if (axis_resetn == 1'b0) begin
rx_data_l <= 24'b0;
rx_data_r <= 24'b0;
end else if (count == EOF_COUNT && rx_axis_m_valid == 1'b0) begin
rx_data_l <= {8'b0, rx_data_l_shift};
rx_data_r <= {8'b0, rx_data_r_shift};
end
assign rx_axis_m_data = (rx_axis_m_last == 1'b1) ? rx_data_r : rx_data_l;
always@(posedge axis_clk)
if (axis_resetn == 1'b0)
rx_axis_m_valid <= 1'b0;
else if (count == EOF_COUNT && rx_axis_m_valid == 1'b0)
rx_axis_m_valid <= 1'b1;
else if (rx_axis_m_valid == 1'b1 && rx_axis_m_ready == 1'b1 && rx_axis_m_last == 1'b1)
rx_axis_m_valid <= 1'b0;
always@(posedge axis_clk)
if (axis_resetn == 1'b0)
rx_axis_m_last <= 1'b0;
else if (count == EOF_COUNT && rx_axis_m_valid == 1'b0)
rx_axis_m_last <= 1'b0;
else if (rx_axis_m_valid == 1'b1 && rx_axis_m_ready == 1'b1)
rx_axis_m_last <= ~rx_axis_m_last;
endmodule

View File

@@ -0,0 +1,175 @@
`timescale 1ns / 1ps
`default_nettype none
module axis_i2s_wrapper (
input wire i2s_clk, // require: approx 22.591MHz
input wire i2s_resetn,
input wire aclk,
input wire aresetn,
input wire [23:0] s_axis_tdata,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
output wire [23:0] m_axis_tdata,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire tx_mclk,
output wire tx_lrck,
output wire tx_sclk,
output wire tx_sdout,
output wire rx_mclk,
output wire rx_lrck,
output wire rx_sclk,
input wire rx_sdin
);
wire [23:0] tx_axis_s_data;
wire tx_axis_s_valid;
wire tx_axis_s_ready;
wire tx_axis_s_last;
wire [23:0] rx_axis_m_data;
wire rx_axis_m_valid;
wire rx_axis_m_ready;
wire rx_axis_m_last;
xpm_fifo_axis #(
.CDC_SYNC_STAGES(2),
.CLOCKING_MODE("independent_clock"),
.ECC_MODE("no_ecc"),
.FIFO_DEPTH(1024),
.FIFO_MEMORY_TYPE("auto"),
.PACKET_FIFO("false"),
.PROG_EMPTY_THRESH(10),
.PROG_FULL_THRESH(10),
.RD_DATA_COUNT_WIDTH(1),
.RELATED_CLOCKS(0),
.SIM_ASSERT_CHK(1),
.TDATA_WIDTH(24),
.TDEST_WIDTH(1),
.TID_WIDTH(1),
.TUSER_WIDTH(1),
.USE_ADV_FEATURES("0000"),
.WR_DATA_COUNT_WIDTH(1)
)
rx_fifo (
.s_aclk(aclk),
.s_aresetn(aresetn),
.s_axis_tvalid(s_axis_tvalid),
.s_axis_tready(s_axis_tready),
.s_axis_tdata(s_axis_tdata),
.s_axis_tlast(s_axis_tlast),
.s_axis_tdest(1'b0),
.s_axis_tid(1'b0),
.s_axis_tkeep(1'b111),
.s_axis_tstrb(1'b111),
.s_axis_tuser(1'b0),
.m_aclk(i2s_clk),
.m_axis_tvalid(tx_axis_s_valid),
.m_axis_tready(tx_axis_s_ready),
.m_axis_tdata(tx_axis_s_data),
.m_axis_tlast(tx_axis_s_last),
.m_axis_tdest(),
.m_axis_tid(),
.m_axis_tkeep(),
.m_axis_tstrb(),
.m_axis_tuser(),
.almost_empty_axis(),
.almost_full_axis(),
.dbiterr_axis(),
.prog_empty_axis(),
.prog_full_axis(),
.rd_data_count_axis(),
.sbiterr_axis(),
.wr_data_count_axis(),
.injectdbiterr_axis(1'b0),
.injectsbiterr_axis(1'b0)
);
axis_dual_i2s axis_dual_i2s_inst (
.axis_clk(i2s_clk),
.axis_resetn(i2s_resetn),
.tx_axis_s_data(tx_axis_s_data),
.tx_axis_s_valid(tx_axis_s_valid),
.tx_axis_s_ready(tx_axis_s_ready),
.tx_axis_s_last(tx_axis_s_last),
.rx_axis_m_data(rx_axis_m_data),
.rx_axis_m_valid(rx_axis_m_valid),
.rx_axis_m_ready(rx_axis_m_ready),
.rx_axis_m_last(rx_axis_m_last),
.tx_mclk(tx_mclk),
.tx_lrck(tx_lrck),
.tx_sclk(tx_sclk),
.tx_sdout(tx_sdout),
.rx_mclk(rx_mclk),
.rx_lrck(rx_lrck),
.rx_sclk(rx_sclk),
.rx_sdin(rx_sdin)
);
xpm_fifo_axis #(
.CDC_SYNC_STAGES(2),
.CLOCKING_MODE("independent_clock"),
.ECC_MODE("no_ecc"),
.FIFO_DEPTH(1024),
.FIFO_MEMORY_TYPE("auto"),
.PACKET_FIFO("false"),
.PROG_EMPTY_THRESH(10),
.PROG_FULL_THRESH(10),
.RD_DATA_COUNT_WIDTH(1),
.RELATED_CLOCKS(0),
.SIM_ASSERT_CHK(1),
.TDATA_WIDTH(24),
.TDEST_WIDTH(1),
.TID_WIDTH(1),
.TUSER_WIDTH(1),
.USE_ADV_FEATURES("0000"),
.WR_DATA_COUNT_WIDTH(1)
)
tx_fifo (
.s_aclk(i2s_clk),
.s_aresetn(i2s_resetn),
.s_axis_tvalid(rx_axis_m_valid),
.s_axis_tready(rx_axis_m_ready),
.s_axis_tdata(rx_axis_m_data),
.s_axis_tlast(rx_axis_m_last),
.s_axis_tdest(1'b0),
.s_axis_tid(1'b0),
.s_axis_tkeep(1'b111),
.s_axis_tstrb(1'b111),
.s_axis_tuser(1'b0),
.m_aclk(aclk),
.m_axis_tvalid(m_axis_tvalid),
.m_axis_tready(m_axis_tready),
.m_axis_tdata(m_axis_tdata),
.m_axis_tlast(m_axis_tlast),
.m_axis_tdest(),
.m_axis_tid(),
.m_axis_tkeep(),
.m_axis_tstrb(),
.m_axis_tuser(),
.almost_empty_axis(),
.almost_full_axis(),
.dbiterr_axis(),
.prog_empty_axis(),
.prog_full_axis(),
.rd_data_count_axis(),
.sbiterr_axis(),
.wr_data_count_axis(),
.injectdbiterr_axis(1'b0),
.injectsbiterr_axis(1'b0)
);
endmodule