]> git.the-white-hart.net Git - vhdl/commitdiff
Update I2S blocks after actually reading datasheet
authorrs <>
Thu, 18 Dec 2025 02:49:35 +0000 (20:49 -0600)
committerrs <>
Thu, 18 Dec 2025 02:49:35 +0000 (20:49 -0600)
libraries/dsp/i2s_ctrl.vhd
libraries/dsp/i2s_input.vhd
libraries/dsp/i2s_output.vhd
libraries/dsp/tests/test_i2s_ctrl.vhd
libraries/dsp/tests/test_i2s_input.vhd
libraries/dsp/tests/test_i2s_output.vhd

index 5b2f54969dac165406cb2fae35fbed1b06646b5a..13cf4065b0a3b63f0d640bd77264d3a287d9e2a3 100644 (file)
@@ -11,22 +11,33 @@ entity i2s_ctrl is
                rst_i:  in  std_logic;
                clk_50: in  std_logic;  -- 50 MHz
 
-               ws:     out std_logic;
-               sck:    out std_logic   -- 44.1028*16*2 kHz (good enough for government work)
+               -- For external use
+               mclk:   out std_logic;  -- MCLK, 256*LRCLK(WS)
+               ws:     out std_logic;  -- WS/LRCLK, 44.1028 kHz (good enough for government work)
+               sck:    out std_logic;
+
+               -- For internal use, rising and falling edges of SCK in MCLK domain
+               rise:   out std_logic;
+               fall:   out std_logic
        );
 end i2s_ctrl;
 
 
 architecture behavioral of i2s_ctrl is
 
-       signal clk_orig: std_logic;  -- Output from DCM
-       signal clk_int:  std_logic;  -- DCM output after clock buffer
+       signal mclk_orig: std_logic;  -- Output from DCM
+       signal mclk_int:  std_logic;  -- DCM output after clock buffer
+       signal sck_int:   std_logic;
+       signal sck_reg:   std_logic;
 
-       signal sck_orig: std_logic;  -- Further clock division
-       signal sck_int:  std_logic;  -- Final I2S SCK after clock buffer
+       signal ws_tick:   std_logic;  -- For WS generation
+       signal ws_carry:  std_logic;
+       signal ws_reg:    std_logic := '0';
 
-       signal ws_tick:  std_logic;  -- For WS generation
-       signal ws_reg:   std_logic := '0';
+       signal rise_int:  std_logic;
+       signal fall_int:  std_logic;
+       signal rise_reg:  std_logic;
+       signal fall_reg:  std_logic;
 
 begin
 
@@ -36,7 +47,7 @@ begin
                        --CLKDV_DIVIDE          => 1,
                        CLKFX_DIVIDE          => 31,
                        CLKFX_MULTIPLY        => 7,
-                       CLKIN_DIVIDE_BY_2     => true,
+                       CLKIN_DIVIDE_BY_2     => false,
                        CLKIN_PERIOD          => 20.0,
                        --CLKOUT_PHASE_SHIFT    => "NONE",
                        --DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",
@@ -63,42 +74,60 @@ begin
                        CLK2X    => open,
                        CLK2X180 => open,
                        CLKDV    => open,
-                       CLKFX    => clk_orig,
+                       CLKFX    => mclk_orig,
                        CLKFX180 => open,
                        LOCKED   => open,
                        STATUS   => open,
                        PSDONE   => open
                );
 
-       e_clkbuf: bufg
+       e_mclkbuf: bufg
                port map (
-                       I => clk_orig,
-                       O => clk_int
+                       I => mclk_orig,
+                       O => mclk_int
                );
 
        e_sck_gen: srl16
                generic map (INIT => x"0003")
                port map (
-                       D   => sck_orig,
-                       CLK => clk_int,
+                       D   => sck_int,
+                       CLK => mclk_int,
                        A0  => '1',
                        A1  => '1',
                        A2  => '0',
                        A3  => '0',
-                       Q   => sck_orig
+                       Q   => sck_int
                );
 
-       e_sck_buf: bufg
+       process (mclk_int, sck_int, sck_reg)
+       begin
+               if rising_edge(mclk_int) then
+                       sck_reg <= sck_int;
+               end if;
+       end process;
+       rise_int <= '1' when sck_reg = '0' and sck_int = '1' else '0';
+       fall_int <= '1' when sck_reg = '1' and sck_int = '0' else '0';
+
+       e_ws_count_0: srlc16e
+               generic map (INIT => x"0000")
                port map (
-                       I => sck_orig,
-                       O => sck_int
+                       D   => ws_tick,
+                       CE  => fall_int,
+                       CLK => mclk_int,
+                       A0  => '0',
+                       A1  => '0',
+                       A2  => '0',
+                       A3  => '0',
+                       Q   => open,
+                       Q15 => ws_carry
                );
 
-       e_ws_count: srlc16
+       e_ws_count_1: srlc16e
                generic map (INIT => x"0001")
                port map (
-                       D   => ws_tick,
-                       CLK => sck_int,
+                       D   => ws_carry,
+                       CE  => fall_int,
+                       CLK => mclk_int,
                        A0  => '0',
                        A1  => '0',
                        A2  => '0',
@@ -107,16 +136,28 @@ begin
                        Q15 => ws_tick
                );
 
-       process (sck_int, ws_tick, ws_reg)
+       process (mclk_int, ws_tick, fall_int, ws_reg)
        begin
-               if falling_edge(sck_int) then
-                       if ws_tick = '1' then
+               if rising_edge(mclk_int) then
+                       if ws_tick = '1' and fall_int = '1' then
                                ws_reg <= not ws_reg;
                        end if;
                end if;
        end process;
 
-       ws  <= ws_reg;
-       sck <= sck_int;
+       mclk <= mclk_int;
+       sck  <= sck_reg;
+       ws   <= ws_reg;
+
+       process (mclk_int, rise_int, fall_int)
+       begin
+               if rising_edge(mclk_int) then
+                       rise_reg <= rise_int;
+                       fall_reg <= fall_int;
+               end if;
+       end process;
+
+       rise <= rise_reg;
+       fall <= fall_reg;
 
 end behavioral;
index 60c53af9243f33cfe4ac84d0580b27e0fe93d6df..43a0c4c10e7c77dfc67d2e2f44971de51dd238c3 100644 (file)
@@ -11,66 +11,77 @@ use unisim.vcomponents.all;
 
 
 entity i2s_input is
+       generic (WIDTH: positive := 32);
        port (
+               mclk:    in  std_logic;
                sck:     in  std_logic;
                ws:      in  std_logic;
                sd:      in  std_logic;
 
+               rise:    in  std_logic;
+               fall:    in  std_logic;
+
                stb_o:   out std_logic;
                rdy_i:   in  std_logic;
-               l_dat_o: out std_logic_vector(15 downto 0);
-               r_dat_o: out std_logic_vector(15 downto 0)
+               l_dat_o: out std_logic_vector(WIDTH-1 downto 0);
+               r_dat_o: out std_logic_vector(WIDTH-1 downto 0)
        );
 end i2s_input;
 
 
 architecture behavioral of i2s_input is
 
-       signal shift_reg:  std_logic_vector(15 downto 0);
+       signal shift_reg:  std_logic_vector(WIDTH-1 downto 0);
        signal ws_reg:     std_logic;
        signal ws2_reg:    std_logic;
 
        signal latch_l:    std_logic;
        signal latch_r:    std_logic;
 
-       signal samp_l_reg: std_logic_vector(15 downto 0);
-       signal samp_r_reg: std_logic_vector(15 downto 0);
+       signal samp_l_reg: std_logic_vector(WIDTH-1 downto 0);
+       signal samp_r_reg: std_logic_vector(WIDTH-1 downto 0);
 
        signal stb_reg:    std_logic;
 
 begin
 
-       process (sck, ws)
+       process (mclk, rise, ws)
        begin
-               if rising_edge(sck) then
-                       shift_reg <= shift_reg(14 downto 0) & sd;
-                       ws2_reg   <= ws_reg;
-                       ws_reg    <= ws;
+               if rising_edge(mclk) then
+                       if rise = '1' then
+                               shift_reg <= shift_reg(WIDTH-2 downto 0) & sd;
+                               ws2_reg   <= ws_reg;
+                               ws_reg    <= ws;
+                       end if;
                end if;
        end process;
 
        latch_l <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
        latch_r <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
 
-       process (sck, latch_l, latch_r, shift_reg)
+       process (mclk, rise, latch_l, latch_r, shift_reg)
        begin
-               if rising_edge(sck) then
-                       if latch_l = '1' then
-                               samp_l_reg <= shift_reg;
-                       end if;
-                       if latch_r = '1' then
-                               samp_r_reg <= shift_reg;
+               if rising_edge(mclk) then
+                       if rise = '1' then
+                               if latch_l = '1' then
+                                       samp_l_reg <= shift_reg;
+                               end if;
+                               if latch_r = '1' then
+                                       samp_r_reg <= shift_reg;
+                               end if;
                        end if;
                end if;
        end process;
 
-       process (sck, latch_r, rdy_i)
+       process (mclk, rise, latch_r, rdy_i)
        begin
-               if rising_edge(sck) then
-                       if latch_r = '1' then
-                               stb_reg <= '1';
-                       elsif rdy_i = '1' then
-                               stb_reg <= '0';
+               if rising_edge(mclk) then
+                       if rise = '1' then
+                               if latch_r = '1' then
+                                       stb_reg <= '1';
+                               elsif rdy_i = '1' then
+                                       stb_reg <= '0';
+                               end if;
                        end if;
                end if;
        end process;
index 7d1703f8469b4574b3f89673c9d8001329793e4d..11fda1b9c758a8ec8b34f53b58e6d67cdb5229b8 100644 (file)
@@ -11,15 +11,20 @@ use unisim.vcomponents.all;
 
 
 entity i2s_output is
+       generic (WIDTH: positive := 32);
        port (
+               mclk:    in  std_logic;
                sck:     in  std_logic;
                ws:      in  std_logic;
                sd:      out std_logic;
 
+               rise:    in  std_logic;
+               fall:    in  std_logic;
+
                stb_i:   in  std_logic;
                rdy_o:   out std_logic;
-               l_dat_i: in  std_logic_vector(15 downto 0);
-               r_dat_i: in  std_logic_vector(15 downto 0)
+               l_dat_i: in  std_logic_vector(WIDTH-1 downto 0);
+               r_dat_i: in  std_logic_vector(WIDTH-1 downto 0)
        );
 end i2s_output;
 
@@ -27,38 +32,44 @@ end i2s_output;
 architecture behavioral of i2s_output is
 
        signal ws_reg:    std_logic;
-       signal shift_reg: std_logic_vector(15 downto 0);
+       signal ws2_reg:   std_logic;
+       signal shift_reg: std_logic_vector(WIDTH-1 downto 0);
 
        signal latch_l:   std_logic;
        signal latch_r:   std_logic;
 
 begin
 
-       sd <= shift_reg(15);
+       sd <= shift_reg(WIDTH-1);
 
-       process (sck, ws)
+       process (mclk, fall, ws, ws_reg)
        begin
-               if falling_edge(sck) then
-                       ws_reg <= ws;
+               if rising_edge(mclk) then
+                       if fall = '1' then
+                               ws2_reg <= ws_reg;
+                               ws_reg <= ws;
+                       end if;
                end if;
        end process;
 
-       latch_l <= '1' when ws = '0' and ws_reg = '1' else '0';
-       latch_r <= '1' when ws = '1' and ws_reg = '0' else '0';
+       latch_l <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
+       latch_r <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
 
-       process (sck, latch_l, latch_r, l_dat_i, r_dat_i, shift_reg)
+       process (mclk, fall, latch_l, latch_r, l_dat_i, r_dat_i, shift_reg)
        begin
-               if falling_edge(sck) then
-                       if latch_l = '1' then
-                               shift_reg <= l_dat_i;
-                       elsif latch_r = '1' then
-                               shift_reg <= r_dat_i;
-                       else
-                               shift_reg <= shift_reg(14 downto 0) & '0';
+               if rising_edge(mclk) then
+                       if fall = '1' then
+                               if latch_l = '1' then
+                                       shift_reg <= l_dat_i;
+                               elsif latch_r = '1' then
+                                       shift_reg <= r_dat_i;
+                               else
+                                       shift_reg <= shift_reg(WIDTH-2 downto 0) & '0';
+                               end if;
                        end if;
                end if;
        end process;
 
-       rdy_o <= latch_r;
+       rdy_o <= latch_r and fall;
 
 end behavioral;
index 755af5adbfa4acb7bf618c7c68109e6768c6d4de..108c589e243c09b51cf4665ae30b008c09075b3b 100644 (file)
@@ -15,8 +15,12 @@ architecture behavior of test_i2s_ctrl is
        signal rst_i:  std_logic;
        signal clk_i:  std_logic;
 
-       signal ws:     std_logic;
+       signal mclk:   std_logic;
        signal sck:    std_logic;
+       signal ws:     std_logic;
+
+       signal rise:   std_logic;
+       signal fall:   std_logic;
 
 begin
 
@@ -36,8 +40,12 @@ begin
                        rst_i  => rst_i,
                        clk_50 => clk_i,
 
+                       mclk   => mclk,
+                       sck    => sck,
                        ws     => ws,
-                       sck    => sck
+
+                       rise   => rise,
+                       fall   => fall
                );
 
        p_clk: process
index 8268ef72bcbd329824835bd081c6c9389ad02f25..59b5d9bbafcae1f4f690c12cb3eb9a4aa1b9b1c6 100644 (file)
@@ -17,14 +17,18 @@ architecture behavior of test_i2s_input is
        signal rst_i:  std_logic;
        signal clk_50: std_logic;
 
+       signal mclk:   std_logic;
        signal sck:    std_logic;
        signal ws:     std_logic;
        signal sd:     std_logic;
 
+       signal rise:   std_logic;
+       signal fall:   std_logic;
+
        signal stb:    std_logic;
        signal rdy:    std_logic;
-       signal l_dat:  std_logic_vector(15 downto 0);
-       signal r_dat:  std_logic_vector(15 downto 0);
+       signal l_dat:  std_logic_vector(31 downto 0);
+       signal r_dat:  std_logic_vector(31 downto 0);
 
 begin
 
@@ -46,10 +50,14 @@ begin
 
        e_uut: entity work.i2s_input
                port map (
+                       mclk    => mclk,
                        sck     => sck,
                        ws      => ws,
                        sd      => sd,
 
+                       rise    => rise,
+                       fall    => fall,
+
                        stb_o   => stb,
                        rdy_i   => rdy,
                        l_dat_o => l_dat,
@@ -67,8 +75,13 @@ begin
                port map (
                        rst_i  => rst_i,
                        clk_50 => clk_50,
+
+                       mclk   => mclk,
+                       sck    => sck,
                        ws     => ws,
-                       sck    => sck
+
+                       rise   => rise,
+                       fall   => fall
                );
 
        p_clk50: process
index 1ef06a1e1def126a9dafaa5ca7eab5fdd47fdacb..48faab75fc54314ccca83aab99b5b5f9f482a2a3 100644 (file)
@@ -15,18 +15,22 @@ architecture behavior of test_i2s_output is
        signal rst_i:    std_logic;
        signal clk_50:   std_logic;
 
+       signal mclk:     std_logic;
        signal sck:      std_logic;
        signal ws:       std_logic;
        signal sd:       std_logic;
 
+       signal rise:     std_logic;
+       signal fall:     std_logic;
+
        signal stb:      std_logic;
        signal rdy:      std_logic;
-       signal l_dat:    std_logic_vector(15 downto 0);
-       signal r_dat:    std_logic_vector(15 downto 0);
+       signal l_dat:    std_logic_vector(31 downto 0);
+       signal r_dat:    std_logic_vector(31 downto 0);
 
        signal rx_stb:   std_logic;
-       signal rx_l_dat: std_logic_vector(15 downto 0);
-       signal rx_r_dat: std_logic_vector(15 downto 0);
+       signal rx_l_dat: std_logic_vector(31 downto 0);
+       signal rx_r_dat: std_logic_vector(31 downto 0);
 
 begin
 
@@ -49,26 +53,37 @@ begin
                port map (
                        rst_i  => rst_i,
                        clk_50 => clk_50,
+
+                       mclk   => mclk,
                        sck    => sck,
-                       ws     => ws
+                       ws     => ws,
+
+                       rise   => rise,
+                       fall   => fall
                );
 
        e_src: entity work.src_counter
                generic map (WIDTH => 16)
                port map (
                        rst_i => rst_i,
-                       clk_i => sck,
+                       clk_i => mclk,
                        stb_o => stb,
                        rdy_i => rdy,
-                       dat_o => l_dat
+                       dat_o => l_dat(31 downto 16)
                );
+       l_dat(15 downto 0) <= (others => '0');
        r_dat <= l_dat;
 
        e_uut: entity work.i2s_output
                port map (
+                       mclk    => mclk,
                        sck     => sck,
                        ws      => ws,
                        sd      => sd,
+
+                       rise    => rise,
+                       fall    => fall,
+
                        stb_i   => stb,
                        rdy_o   => rdy,
                        l_dat_i => l_dat,
@@ -80,9 +95,12 @@ begin
        -- Not a big deal for streaming audio, so not worth fixing now.
        e_rx: entity work.i2s_input
                port map (
+                       mclk    => mclk,
                        sck     => sck,
                        ws      => ws,
                        sd      => sd,
+                       rise    => rise,
+                       fall    => fall,
                        stb_o   => rx_stb,
                        rdy_i   => '1',
                        l_dat_o => rx_l_dat,