From: rs <> Date: Thu, 18 Dec 2025 02:49:35 +0000 (-0600) Subject: Update I2S blocks after actually reading datasheet X-Git-Url: https://git.the-white-hart.net/?a=commitdiff_plain;h=87d3c128babc2b5a883c0a64230bd93fe984071d;p=vhdl Update I2S blocks after actually reading datasheet --- diff --git a/libraries/dsp/i2s_ctrl.vhd b/libraries/dsp/i2s_ctrl.vhd index 5b2f549..13cf406 100644 --- a/libraries/dsp/i2s_ctrl.vhd +++ b/libraries/dsp/i2s_ctrl.vhd @@ -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; diff --git a/libraries/dsp/i2s_input.vhd b/libraries/dsp/i2s_input.vhd index 60c53af..43a0c4c 100644 --- a/libraries/dsp/i2s_input.vhd +++ b/libraries/dsp/i2s_input.vhd @@ -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; diff --git a/libraries/dsp/i2s_output.vhd b/libraries/dsp/i2s_output.vhd index 7d1703f..11fda1b 100644 --- a/libraries/dsp/i2s_output.vhd +++ b/libraries/dsp/i2s_output.vhd @@ -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; diff --git a/libraries/dsp/tests/test_i2s_ctrl.vhd b/libraries/dsp/tests/test_i2s_ctrl.vhd index 755af5a..108c589 100644 --- a/libraries/dsp/tests/test_i2s_ctrl.vhd +++ b/libraries/dsp/tests/test_i2s_ctrl.vhd @@ -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 diff --git a/libraries/dsp/tests/test_i2s_input.vhd b/libraries/dsp/tests/test_i2s_input.vhd index 8268ef7..59b5d9b 100644 --- a/libraries/dsp/tests/test_i2s_input.vhd +++ b/libraries/dsp/tests/test_i2s_input.vhd @@ -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 diff --git a/libraries/dsp/tests/test_i2s_output.vhd b/libraries/dsp/tests/test_i2s_output.vhd index 1ef06a1..48faab7 100644 --- a/libraries/dsp/tests/test_i2s_output.vhd +++ b/libraries/dsp/tests/test_i2s_output.vhd @@ -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,