]> git.the-white-hart.net Git - vhdl/commitdiff
Wrap up I2S blocks for Digilent stereo audio pmod
authorrs <>
Fri, 19 Dec 2025 02:58:41 +0000 (20:58 -0600)
committerrs <>
Fri, 19 Dec 2025 02:58:41 +0000 (20:58 -0600)
libraries/dsp/i2s_pmod.vhd [new file with mode: 0644]

diff --git a/libraries/dsp/i2s_pmod.vhd b/libraries/dsp/i2s_pmod.vhd
new file mode 100644 (file)
index 0000000..984cfaf
--- /dev/null
@@ -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;