From: rs <> Date: Fri, 19 Dec 2025 02:58:41 +0000 (-0600) Subject: Wrap up I2S blocks for Digilent stereo audio pmod X-Git-Url: https://git.the-white-hart.net/?a=commitdiff_plain;h=85aec1df7f433d42693cecfc0151f0997df2709a;p=vhdl Wrap up I2S blocks for Digilent stereo audio pmod --- diff --git a/libraries/dsp/i2s_pmod.vhd b/libraries/dsp/i2s_pmod.vhd new file mode 100644 index 0000000..984cfaf --- /dev/null +++ b/libraries/dsp/i2s_pmod.vhd @@ -0,0 +1,174 @@ +library ieee; +use ieee.std_logic_1164.all; + +library utility; +library work; + + +entity i2s_pmod is + port ( + rst_50: in std_logic; + clk_50: in std_logic; + + stb_i: in std_logic; + rdy_o: out std_logic; + l_dat_i: in std_logic_vector(23 downto 0); + r_dat_i: in std_logic_vector(23 downto 0); + + stb_o: out std_logic; + rdy_i: in std_logic; + l_dat_o: out std_logic_vector(23 downto 0); + r_dat_o: out std_logic_vector(23 downto 0); + + pmod: inout std_logic_vector(7 downto 0) + ); +end i2s_pmod; + + +architecture behavioral of i2s_pmod is + + signal rst_i2s: std_logic; + signal mclk: std_logic; + signal sck: std_logic; + signal ws: std_logic; + signal txsd: std_logic; + signal rxsd: std_logic; + + signal rise: std_logic; + signal fall: std_logic; + + signal rx_stb: std_logic; + signal rx_rdy: std_logic; + signal rx_l_dat: std_logic_vector(31 downto 0); + signal rx_r_dat: std_logic_vector(31 downto 0); + + signal tx_stb: std_logic; + signal tx_rdy: std_logic; + signal tx_l_dat: std_logic_vector(31 downto 0); + signal tx_r_dat: std_logic_vector(31 downto 0); + + signal rx_head_dat: std_logic_vector(47 downto 0); + signal rx_tail_dat: std_logic_vector(47 downto 0); + + signal tx_head_dat: std_logic_vector(47 downto 0); + signal tx_tail_dat: std_logic_vector(47 downto 0); + +begin + + -- The ADC and DAC decide choose their modes based on the values of their + -- pins at powerup, so the rst_i2s signal is here to gate the pins and + -- leave them in an high-Z state after powerup for a couple MCLK cycles + -- to let them sense their settings. This is probably unnecessary, as the + -- FPGA will leave all its IO blocks disabled until configuration is + -- complete, but it doesn't hurt to be sure. + e_rst: entity utility.sync_sig + generic map (INIT => '1') + port map ( + rst_i => rst_50, + clk_i => mclk, + sig_i => '0', + sig_o => rst_i2s + ); + + e_ctrl: entity work.i2s_ctrl + port map ( + rst_i => rst_50, + clk_50 => clk_50, + + mclk => mclk, + sck => sck, + ws => ws, + + rise => rise, + fall => fall + ); + + e_rx: entity work.i2s_input + generic map (WIDTH => 32) + port map ( + mclk => mclk, + sck => sck, + ws => ws, + sd => rxsd, + + rise => rise, + fall => fall, + + stb_o => rx_stb, + rdy_i => rx_rdy, + l_dat_o => rx_l_dat, + r_dat_o => rx_r_dat + ); + + e_rx_fifo: entity utility.sync_fifo_16 + generic map (WIDTH => 48) + port map ( + head_rst_i => rst_i2s, + head_clk_i => mclk, + head_stb_i => rx_stb, + head_rdy_o => rx_rdy, + head_dat_i => rx_head_dat, + + tail_rst_i => rst_50, + tail_clk_i => clk_50, + tail_stb_o => stb_o, + tail_rdy_i => rdy_i, + tail_dat_o => rx_tail_dat + ); + rx_head_dat <= rx_r_dat(31 downto 8) & rx_l_dat(31 downto 8); + r_dat_o <= rx_tail_dat(47 downto 24); + l_dat_o <= rx_tail_dat(23 downto 0); + + e_tx: entity work.i2s_output + generic map (WIDTH => 32) + port map ( + mclk => mclk, + sck => sck, + ws => ws, + sd => txsd, + + rise => rise, + fall => fall, + + stb_i => tx_stb, + rdy_o => tx_rdy, + l_dat_i => tx_l_dat, + r_dat_i => tx_r_dat + ); + + e_tx_fifo: entity utility.sync_fifo_16 + generic map (WIDTH => 48) + port map ( + head_rst_i => rst_50, + head_clk_i => clk_50, + head_stb_i => stb_i, + head_rdy_o => rdy_o, + head_dat_i => tx_head_dat, + + tail_rst_i => rst_i2s, + tail_clk_i => mclk, + tail_stb_o => tx_stb, + tail_rdy_i => tx_rdy, + tail_dat_o => tx_tail_dat + ); + tx_head_dat <= r_dat_i & l_dat_i; + tx_r_dat <= tx_tail_dat(47 downto 24) & x"00"; + tx_l_dat <= tx_tail_dat(23 downto 0) & x"00"; + + -- pmod(3 downto 0) <= JA4 & JA3 & JA2 & JA1 -- TOP + -- pmod(7 downto 4) <= JA10 & JA9 & JA8 & JA7 -- BOTTOM + + -- Top row + pmod(0) <= 'Z' when rst_i2s = '1' else mclk; + pmod(1) <= 'Z' when rst_i2s = '1' else ws; + pmod(2) <= 'Z' when rst_i2s = '1' else sck; + pmod(3) <= 'Z' when rst_i2s = '1' else txsd; + + -- Bottom row + pmod(4) <= 'Z' when rst_i2s = '1' else mclk; + pmod(5) <= 'Z' when rst_i2s = '1' else ws; + pmod(6) <= 'Z' when rst_i2s = '1' else sck; + pmod(7) <= 'Z'; + rxsd <= pmod(7); + +end behavioral;