Audio Clock and Data

There’s just no escaping clocks. The 49.152MHz aux clock that was configured within the replay.ini is left unchanged by the Replay_ClockGen (in Replay_Top) and will need reducing down to a 48kHz clock to match the 48kHz PCM frequency.

The Replay_Audio entity that handles output to the on-board DAC uses one sample every 256 input clocks i.e @192kHz therefore the user core will need to provide a soft clock that toggles once in every 4 aux clock transitions in order to meet the 48kHz clock requirement.

Core_Top has access to two clock records from the framework, i_ctrl and o_ctrl.

i_ctrl exposes the frameworks clocks to the core and o_ctrl is used to provide the framework with an audio clock and to optionally enable/disable the video clock (see r_Ctrl_to_core and r_Ctrl_fm\core in replay_lib_wrap_pack)

Producing an audio clock that is the aux clock / 4 can be done just as the “loader” core does, via a counter.

  --
  -- Audio clock mapping
  --
  clk_aud <= i_ctrl.clk_aux; -- soft assign (could be sys clock)
  rst_aud <= i_ctrl.rst_aux;

  p_audio_ena_cnt : process
  begin
    wait until rising_edge(clk_aud);
    aud_cnt <= aud_cnt + "1";
    ena_aud <= '0';
    if (aud_cnt = "10") then
      ena_aud <= '1'; -- 1 in 4 to get 48K
    end if;
  end process;

  o_ctrl.clk_aud <= clk_aud;
  o_ctrl.ena_aud <= ena_aud;
  o_ctrl.rst_aud <= rst_aud;

Add the above to the Core_Top after the o_ctrl.ena_vid <= ‘1’; line.

The getting started default Core_Top ties the o_ctrl.*_aud to the corresponding sys entries. Those three lines need removing to allow the 1 in 4 clk_aud to be used instead and finally add four audio signals

signal clk_aud                : bit1;
signal ena_aud                : bit1;
signal rst_aud                : bit1;
signal aud_cnt                : word(1 downto 0);

In order to make use of the audio clock within Example_Audio_Top add to the port section

-- Audio Clocking
i_clk_aud             : in    bit1;
i_ena_aud             : in    bit1;
i_rst_aud             : in    bit1;

and then in Core_Top where the u_core entity is instantiated, tie those ports to the three corresponding audio signals.

i_clk_aud             => clk_aud,
i_ena_aud             => ena_aud,
i_rst_aud             => rst_aud,

The core should now build without error.

If you have access to an oscilloscope, the output of clk_aud can be verified by outputting it to one of the aux io pins. It should produce a frequency of 49.152MHz, whilst if you output the ena_aud entry this should be stepped down by four and show as 12.288MHz.

This can be done by changing the bottom of Core_Top

  b_aux_io(39 downto 0) <= (others => 'Z');

to

  b_aux_io(39 downto 12) <= (others => 'Z');
  b_aux_io(9 downto 0) <= (others => 'Z');

  b_aux_io(11) <= clk_aud;
  b_aux_io(10) <= ena_aud;

Using the aux io pins in this way can be useful for debugging in many cases.

Audio Data

The audio data needs to be provided from somewhere, it might be generated based on tones and lookup tables as with pacman or just playing back PCM data at a specific sampling frequency.

That PCM data could come from two places, SRAM which could be pre-loaded via the arm/loader into a specific memory location just as ROMs are loaded by setting the “[UPLOAD]” entry in the ini file.

Or, the way the “loader” core does it, which is to let the ARM cpu stream data off of the SD card and provide that to the FPGA via one of the two Fileio channels.

For both cases, see r_IO_to_core.

For this example, we’ll be replicating the “loader” way.

The format of the PCM data to load via the OSD can be obtained by exporting any stereo audio file using audacity as “other uncompressed file” with “RAW (header-less)” and “Signed 16bit-PCM” little endian.

Be sure to first re-sample to 48kHz if the audio file is not already 48kHz, such as the more usual 44.1kHz.

Failing that, you can use the loop.pcm that ships with the loader core which is already in a suitable format.

Next section OSD Menu

Back to index