From 398dca67b6b9fcfe1666b8afd15341e9ff700b6f Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Sat, 23 Apr 2016 00:26:21 +0200 Subject: [PATCH] Fix bugs in AC97 output for Atlys board. * Fix bugs in AC97 synchronization. * Fix bugs in AC97 reset. * Reduce audio volume to -12 dB. * Set correct voltage for reset button on Atlys board. --- synth/digilent_atlys/ac97out.vhdl | 101 +++++++++++++++++----- synth/digilent_atlys/atlys.ucf | 4 +- synth/digilent_atlys/test_sincos.gise | 16 ++-- synth/digilent_atlys/test_sincos.xise | 1 + synth/digilent_atlys/top_test_sincos.vhdl | 13 ++- 5 files changed, 97 insertions(+), 38 deletions(-) diff --git a/synth/digilent_atlys/ac97out.vhdl b/synth/digilent_atlys/ac97out.vhdl index 15342e7..511ea13 100644 --- a/synth/digilent_atlys/ac97out.vhdl +++ b/synth/digilent_atlys/ac97out.vhdl @@ -1,5 +1,8 @@ -- -- Simple core for AC97 audio output. +-- +-- Sets output volume to -12 dB, +-- then plays stereo PCM data at 48 kHz sample rate. -- Only tested with LM4550 on Digilent Atlys board. -- @@ -13,8 +16,8 @@ entity ac97out is -- AC97 bit clock. bitclk: in std_logic; - -- Synchronous reset, active high. - rst: in std_logic; + -- Asynchronous reset, active low. + resetn: in std_logic; -- Input samples for left and right channel. data_left: in signed(19 downto 0); @@ -25,6 +28,7 @@ entity ac97out is data_ready: out std_logic; -- AC97 interface signals. + ac97_sdi: in std_logic; ac97_sdo: out std_logic; ac97_sync: out std_logic ); @@ -37,12 +41,12 @@ architecture rtl of ac97out is constant init_table: init_table_type := ( -- write 0x0000 to register 0x00: soft reset x"000000", - -- write 0x0000 to register 0x02: set master volume to maximum - x"020000", - -- write 0x0000 to register 0x04: set headphone volume to maximum - x"040000", - -- write 0x0000 to register 0x06: set mono_out volume to maximum - x"060000", + -- write 0x0000 to register 0x02: set master volume to -12 dB + x"020808", + -- write 0x0000 to register 0x04: set headphone volume to -12 dB + x"040808", + -- write 0x0000 to register 0x06: set mono_out volume to -12 dB + x"060008", -- write 0x0808 to register 0x18: set PCM out volume to 0 dB x"180808", -- dummy read from register 0x00 @@ -51,15 +55,21 @@ architecture rtl of ac97out is x"800000" ); -- Output registers. + signal r_ready: std_logic; signal r_sdo: std_logic; signal r_sync: std_logic; + -- Reset synchronization. + signal r_rstsync: std_logic_vector(7 downto 0); + -- Bit counter. signal r_bitcnt: unsigned(7 downto 0); signal r_lastbit: std_logic; - signal r_firstbit: std_logic; + signal r_endsync: std_logic; -- Initialization state machine. + signal r_initwait: unsigned(5 downto 0); + signal r_initbusy: std_logic; signal r_initdone: std_logic; signal r_initstep: unsigned(2 downto 0); signal r_initword: std_logic_vector(23 downto 0); @@ -72,20 +82,46 @@ architecture rtl of ac97out is -- Frame data shift register (tag + slots 1 .. 4) signal r_sdoshift: std_logic_vector(95 downto 0); + -- AC97 bit input register + signal r_sdi: std_logic; + begin -- Drive outputs. - data_ready <= not r_datavalid; + data_ready <= r_ready; ac97_sdo <= r_sdo; ac97_sync <= r_sync; -- Synchronous process. + -- Sample AC97_SDI on falling edge of BITCLK. process (bitclk) is begin - if rising_edge(bitclk) then + if falling_edge(bitclk) then + r_sdi <= ac97_sdi; + end if; + end process; - -- Drive SYNC high on first bit of frame. - r_sync <= r_firstbit; + -- Synchronous process. + process (bitclk, resetn) is + begin + if resetn = '0' then + + -- Asynchronous reset. + r_rstsync <= (others => '0'); + r_ready <= '0'; + + -- Outputs to codec must be low during reset. + r_sdo <= '0'; + r_sync <= '0'; + + elsif rising_edge(bitclk) then + + -- Drive SYNC high for 16 cycles at start of frame. + if r_lastbit = '1' then + r_sync <= '1'; + elsif r_endsync = '1' then + r_sync <= '0'; + end if; -- Push next data bit to output. r_sdo <= r_sdoshift(r_sdoshift'high); @@ -108,8 +144,8 @@ begin r_sdoshift(95) <= '1'; -- Set slots 1 and 2 valid if we are initializing. - r_sdoshift(94) <= not r_initdone; - r_sdoshift(93) <= not r_initdone; + r_sdoshift(94) <= r_initbusy; + r_sdoshift(93) <= r_initbusy; -- Set slots 3 and 4 valid if we have valid data. r_sdoshift(92) <= r_datavalid; @@ -122,7 +158,7 @@ begin -- bit 19 = read (1) or write (0) -- bit 18:12 = address r_sdoshift(79 downto 72) <= r_initword(23 downto 16); - r_sdoshift(71 downto 0) <= (others => '0'); + r_sdoshift(71 downto 60) <= (others => '0'); -- Slot 2: Register write data. -- bit 19:4 = data @@ -130,42 +166,65 @@ begin r_sdoshift(43 downto 40) <= (others => '0'); -- Update init pointer. - r_initstep <= r_initstep + 1; + if r_initbusy = '1' then + r_initstep <= r_initstep + 1; + end if; if r_initstep = 7 then + r_initbusy <= '0'; r_initdone <= '1'; end if; + -- Update init delay counter (wait for 1.3 ms after reset). + r_initwait <= r_initwait - 1; + if r_initwait = 0 then + r_initstep <= (others => '0'); + r_initbusy <= not r_initdone; + end if; + -- Slots 3 and 4: left and right sample value. r_sdoshift(39 downto 20) <= r_dataleft; r_sdoshift(19 downto 0) <= r_dataright; -- Consume sample values. r_datavalid <= '0'; + r_ready <= '1'; end if; -- Update bit counter. r_bitcnt <= r_bitcnt - 1; - r_firstbit <= r_lastbit; if r_bitcnt = 1 then r_lastbit <= '1'; else r_lastbit <= '0'; end if; + if r_bitcnt = 241 then + r_endsync <= '1'; + else + r_endsync <= '0'; + end if; -- Capture input data. - if r_datavalid = '0' and data_valid = '1' then + if r_ready = '1' and data_valid = '1' then + r_ready <= '0'; r_datavalid <= '1'; r_dataleft <= std_logic_vector(data_left); r_dataright <= std_logic_vector(data_right); end if; + -- Release synchronous reset. + r_rstsync <= "1" & r_rstsync(7 downto 1); + -- Synchronous reset. - if rst = '1' then + if r_rstsync(0) = '0' then + r_ready <= '0'; + r_sdo <= '0'; + r_sync <= '0'; + r_initbusy <= '0'; r_initdone <= '0'; + r_initwait <= (others => '1'); r_initstep <= (others => '0'); r_bitcnt <= (others => '0'); - r_firstbit <= '0'; r_datavalid <= '0'; end if; diff --git a/synth/digilent_atlys/atlys.ucf b/synth/digilent_atlys/atlys.ucf index 82f36d2..39385f9 100644 --- a/synth/digilent_atlys/atlys.ucf +++ b/synth/digilent_atlys/atlys.ucf @@ -7,7 +7,7 @@ NET "clk" TNM_NET = "clk" ; TIMESPEC "TS_clk" = PERIOD "clk" 10 ns HIGH 50% ; # Reset button -NET "resetn" LOC = "T15" | IOSTANDARD = LVCMOS18 ; +NET "resetn" LOC = "T15" | IOSTANDARD = LVCMOS33 ; # LEDs NET "led<0>" LOC = "U18" | IOSTANDARD = LVCMOS33 | SLEW = QUIETIO ; @@ -21,7 +21,7 @@ NET "led<7>" LOC = "N12" | IOSTANDARD = LVCMOS33 | SLEW = QUIETIO ; # USB serial port J17 NET "uartrx" LOC = "A16" | IOSTANDARD = LVCMOS33 ; -NET "uarttx" LOC = "B16" | IOSTANDARD = LVCMOS33 ; +NET "uarttx" LOC = "B16" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ; # Audio NET "ac97_bitclk" LOC = "L13" | IOSTANDARD = LVCMOS33 ; diff --git a/synth/digilent_atlys/test_sincos.gise b/synth/digilent_atlys/test_sincos.gise index 37c1a56..547659c 100644 --- a/synth/digilent_atlys/test_sincos.gise +++ b/synth/digilent_atlys/test_sincos.gise @@ -103,7 +103,7 @@ - + @@ -121,11 +121,11 @@ - + - + @@ -134,10 +134,12 @@ - + + + @@ -148,7 +150,7 @@ - + @@ -163,7 +165,7 @@ - + @@ -176,7 +178,7 @@ - + diff --git a/synth/digilent_atlys/test_sincos.xise b/synth/digilent_atlys/test_sincos.xise index c7924ce..4bcda47 100644 --- a/synth/digilent_atlys/test_sincos.xise +++ b/synth/digilent_atlys/test_sincos.xise @@ -246,6 +246,7 @@ + diff --git a/synth/digilent_atlys/top_test_sincos.vhdl b/synth/digilent_atlys/top_test_sincos.vhdl index 85cda59..c57c5e6 100644 --- a/synth/digilent_atlys/top_test_sincos.vhdl +++ b/synth/digilent_atlys/top_test_sincos.vhdl @@ -73,7 +73,6 @@ architecture rtl of top_test_sincos is signal r_ac97_rstcnt: unsigned(7 downto 0); signal r_ac97_rst: std_logic; - signal r_ac97_rstsync: std_logic_vector(7 downto 0); signal r_ac97_phase: unsigned(19 downto 0); signal s_ac97_sine: signed(17 downto 0); signal s_ac97_dataleft: signed(19 downto 0); @@ -109,14 +108,16 @@ begin u2: entity work.ac97out port map ( bitclk => ac97_bitclk, - rst => r_ac97_rstsync(0), + resetn => r_ac97_rst, data_left => s_ac97_dataleft, data_right => s_ac97_dataright, data_valid => '1', data_ready => s_ac97_ready, + ac97_sdi => ac97_sdi, ac97_sdo => ac97_sdo, ac97_sync => ac97_sync ); + -- Pad 18-bit signed samples to 20-bit. s_ac97_dataleft <= s_ac97_sine & "00"; s_ac97_dataright <= s_ac97_sine & "00"; @@ -157,13 +158,9 @@ begin end process; -- Synchronous process in AC97 bitclock domain. - process (ac97_bitclk, r_ac97_rst) is + process (ac97_bitclk) is begin - if r_ac97_rst = '0' then - r_ac97_rstsync <= (others => '1'); - r_ac97_phase <= (others => '0'); - elsif rising_edge(ac97_bitclk) then - r_ac97_rstsync <= "0" & r_ac97_rstsync(7 downto 1); + if rising_edge(ac97_bitclk) then if s_ac97_ready = '1' then r_ac97_phase <= r_ac97_phase + tone_freq; end if;