]> git.the-white-hart.net Git - vhdl/commitdiff
Add I2S control signal generator
authorrs <>
Sun, 14 Dec 2025 22:38:59 +0000 (16:38 -0600)
committerrs <>
Sun, 14 Dec 2025 22:38:59 +0000 (16:38 -0600)
libraries/dsp/i2s_ctrl.vhd [new file with mode: 0644]

diff --git a/libraries/dsp/i2s_ctrl.vhd b/libraries/dsp/i2s_ctrl.vhd
new file mode 100644 (file)
index 0000000..32825a4
--- /dev/null
@@ -0,0 +1,122 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity i2s_ctrl is
+       port (
+               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)
+       );
+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 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_reg:   std_logic := '0';
+
+begin
+
+       e_dcm: dcm_sp
+               generic map (
+                       CLK_FEEDBACK          => "NONE",
+                       --CLKDV_DIVIDE          => 1,
+                       CLKFX_DIVIDE          => 31,
+                       CLKFX_MULTIPLY        => 7,
+                       CLKIN_DIVIDE_BY_2     => true,
+                       CLKIN_PERIOD          => 20.0,
+                       --CLKOUT_PHASE_SHIFT    => "NONE",
+                       --DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",
+                       --FACTORY_JF            =>
+                       --PHASE_SHIFT           => 0,
+                       DFS_FREQUENCY_MODE    => "LOW",
+                       --DLL_FREQUENCY_MODE    => "LOW",
+                       --DSS_MODE              => "NONE",
+                       --DUTY_CYCLE_CORRECTION => false,
+                       STARTUP_WAIT          => true
+               )
+               port map (
+                       CLKIN    => clk_50,
+                       CLKFB    => '0',
+                       DSSEN    => '0',
+                       RST      => rst_i,
+                       PSINCDEC => '0',
+                       PSEN     => '0',
+                       PSCLK    => '0',
+                       CLK0     => open,
+                       CLK90    => open,
+                       CLK180   => open,
+                       CLK270   => open,
+                       CLK2X    => open,
+                       CLK2X180 => open,
+                       CLKDV    => open,
+                       CLKFX    => clk_orig,
+                       CLKFX180 => open,
+                       LOCKED   => open,
+                       STATUS   => open,
+                       PSDONE   => open
+               );
+
+       e_clkbuf: bufg
+               port map (
+                       I => clk_orig,
+                       O => clk_int
+               );
+
+       e_sck_gen: srl16
+               generic map (INIT => x"0003")
+               port map (
+                       D   => sck_orig,
+                       CLK => clk_int,
+                       A0  => '1',
+                       A1  => '1',
+                       A2  => '0',
+                       A3  => '0',
+                       Q   => sck_orig
+               );
+
+       e_sck_buf: bufg
+               port map (
+                       I => sck_orig,
+                       O => sck_int
+               );
+
+       e_ws_count: srlc16
+               generic map (INIT => x"0001")
+               port map (
+                       D   => ws_tick,
+                       CLK => sck_int,
+                       A0  => '0',
+                       A1  => '0',
+                       A2  => '0',
+                       A3  => '0',
+                       Q   => open,
+                       Q15 => ws_tick
+               );
+
+       process (sck_int, ws_tick, ws_reg)
+       begin
+               if rising_edge(sck_int) then
+                       if ws_tick = '1' then
+                               ws_reg <= not ws_reg;
+                       end if;
+               end if;
+       end process;
+
+       ws  <= ws_reg;
+       sck <= sck_int;
+
+end behavioral;