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.
This commit is contained in:
		
							parent
							
								
									8bd2d389ef
								
							
						
					
					
						commit
						398dca67b6
					
				|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 ; | ||||
|  |  | |||
|  | @ -103,7 +103,7 @@ | |||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346689" xil_pn:in_ck="2072574044500593778" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="8668749107623387584" xil_pn:start_ts="1461346674"> | ||||
|     <transform xil_pn:end_ts="1461403854" xil_pn:in_ck="2072574044500593778" xil_pn:name="TRANEXT_xstsynthesize_spartan6" xil_pn:prop_ck="8668749107623387584" xil_pn:start_ts="1461403839"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="WarningsGenerated"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|  | @ -121,11 +121,11 @@ | |||
|       <outfile xil_pn:name="webtalk_pn.xml"/> | ||||
|       <outfile xil_pn:name="xst"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346689" xil_pn:in_ck="141509727442713" xil_pn:name="TRAN_compileBCD2" xil_pn:prop_ck="7075349975164966765" xil_pn:start_ts="1461346689"> | ||||
|     <transform xil_pn:end_ts="1461400807" xil_pn:in_ck="141509727442713" xil_pn:name="TRAN_compileBCD2" xil_pn:prop_ck="7075349975164966765" xil_pn:start_ts="1461400807"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346696" xil_pn:in_ck="-1047380743607608193" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="392032481918333458" xil_pn:start_ts="1461346689"> | ||||
|     <transform xil_pn:end_ts="1461403860" xil_pn:in_ck="-1047380743607608193" xil_pn:name="TRANEXT_ngdbuild_FPGA" xil_pn:prop_ck="392032481918333458" xil_pn:start_ts="1461403854"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|       <outfile xil_pn:name="_ngo"/> | ||||
|  | @ -134,10 +134,12 @@ | |||
|       <outfile xil_pn:name="top_test_sincos.ngd"/> | ||||
|       <outfile xil_pn:name="top_test_sincos_ngdbuild.xrpt"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346726" xil_pn:in_ck="-1047380743607608192" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="4245753365082497697" xil_pn:start_ts="1461346696"> | ||||
|     <transform xil_pn:end_ts="1461403888" xil_pn:in_ck="-1047380743607608192" xil_pn:name="TRANEXT_map_spartan6" xil_pn:prop_ck="4245753365082497697" xil_pn:start_ts="1461403860"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="WarningsGenerated"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|       <status xil_pn:value="OutOfDateForOutputs"/> | ||||
|       <status xil_pn:value="OutputChanged"/> | ||||
|       <outfile xil_pn:name="_xmsgs/map.xmsgs"/> | ||||
|       <outfile xil_pn:name="top_test_sincos.pcf"/> | ||||
|       <outfile xil_pn:name="top_test_sincos_map.map"/> | ||||
|  | @ -148,7 +150,7 @@ | |||
|       <outfile xil_pn:name="top_test_sincos_summary.xml"/> | ||||
|       <outfile xil_pn:name="top_test_sincos_usage.xml"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346754" xil_pn:in_ck="693365441136831385" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="-3829590541433901613" xil_pn:start_ts="1461346726"> | ||||
|     <transform xil_pn:end_ts="1461403915" xil_pn:in_ck="693365441136831385" xil_pn:name="TRANEXT_par_spartan6" xil_pn:prop_ck="-3829590541433901613" xil_pn:start_ts="1461403888"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="WarningsGenerated"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|  | @ -163,7 +165,7 @@ | |||
|       <outfile xil_pn:name="top_test_sincos_pad.txt"/> | ||||
|       <outfile xil_pn:name="top_test_sincos_par.xrpt"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346939" xil_pn:in_ck="4016941542054796675" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="97434230493978268" xil_pn:start_ts="1461346923"> | ||||
|     <transform xil_pn:end_ts="1461403932" xil_pn:in_ck="4016941542054796675" xil_pn:name="TRANEXT_bitFile_spartan6" xil_pn:prop_ck="97434230493978268" xil_pn:start_ts="1461403915"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="WarningsGenerated"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|  | @ -176,7 +178,7 @@ | |||
|       <outfile xil_pn:name="webtalk.log"/> | ||||
|       <outfile xil_pn:name="webtalk_pn.xml"/> | ||||
|     </transform> | ||||
|     <transform xil_pn:end_ts="1461346754" xil_pn:in_ck="-1047380743607608324" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416185" xil_pn:start_ts="1461346746"> | ||||
|     <transform xil_pn:end_ts="1461403915" xil_pn:in_ck="-1047380743607608324" xil_pn:name="TRAN_postRouteTrce" xil_pn:prop_ck="445577401284416185" xil_pn:start_ts="1461403907"> | ||||
|       <status xil_pn:value="SuccessfullyRun"/> | ||||
|       <status xil_pn:value="WarningsGenerated"/> | ||||
|       <status xil_pn:value="ReadyToRun"/> | ||||
|  |  | |||
|  | @ -246,6 +246,7 @@ | |||
|     <property xil_pn:name="Preferred Language" xil_pn:value="VHDL" xil_pn:valueState="non-default"/> | ||||
|     <property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/> | ||||
|     <property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/> | ||||
|     <property xil_pn:name="Project Generator" xil_pn:value="ProjNav" xil_pn:valueState="default"/> | ||||
|     <property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/> | ||||
|     <property xil_pn:name="RAM Extraction" xil_pn:value="true" xil_pn:valueState="default"/> | ||||
|     <property xil_pn:name="RAM Style" xil_pn:value="Auto" xil_pn:valueState="default"/> | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue