Audio (WM8960) Test

This test will configure the WM8960 via I2C, read the audio data from the WM8960 (using Line In or MIC In as the input source), and then loop it back to the WM8960 for output through headphones or speakers.

Create Vivado Project

Create a new Vivado project. Follow the previous steps to configure the PS's Quad SPI FLASH, UART, and DDR controller. Since this experiment uses the I2C controller to configure the WM8960 via the I2C interface, note that the WM8960's I2C interface (scl and sda) is hardware-connected to the PL pins. Therefore, the PS's I2C controller needs to be connected to two PL pins via EMIO.

The configuration result is as follows:

image-20250806171244481

image-20250806171303802

image-20250806171216196

image-20250806171326701

image-20250806171358843

In the diagram, click to select the IIC_0 interface indicated by the arrow, then right-click and choose "Make External" from the pop-up menu to bring out the I2C interface. After bringing out the interface, rename it to "aud_iic", as shown below:

image-20250806171622699

Add a new IP core: Click the "+" symbol in the Diagram toolbar to add an IP. In the search box that pops up, enter "i2s". You will see two IP cores: I2S Receiver and I2S Transmitter. We need to add both to the design.

image-20250806171850164

Configure as shown below (the transmitter is configured similarly):

image-20250806171928581

Bring out the interfaces for communication between the two I2S IP cores and the WM8960 chip. The I2S Receiver module is responsible for capturing the audio data output from the WM8960, so the audio data input interface "sdata_0_in" needs to be brought out via "Make External". After bringing out the interface, rename it to "aud_adc_data".

Typically, the I2S Receiver and I2S Transmitter IP cores only support master mode. However, this experiment requires clock synchronization using the onboard clock of the WM8960 chip. Therefore, set the I2S Receiver to slave mode and the I2S Transmitter to master mode.

Double-click the I2S Receiver core and change the C_IS_MASTER value to 0, as shown below:

image-20250807165310764

After setting the I2S Receiver to slave mode and the I2S Transmitter to master mode, the Irclk_in/sclk_in of the Receiver end is provided by the Irclk_out/sclk_out of the Transmitter end.

image-20250807165224206

The I2S Transmitter module is responsible for outputting the audio data to be played to the WM8960. Similarly, bring out the audio data output interface "sdata_0_out" via "Make External", then rename this interface to "aud_dac_data". The diagram also shows an interface sclk_out brought out from the I2S Transmitter module, which is the bit clock BCLK in the I2S transmission protocol. To synchronize the bit clocks at both ends, connect this interface of the Transmitter to the sclk_in interface of the Receiver, as shown below:

image-20250807171416184

To achieve the audio loopback function, connect the m_axis_aud interface of the I2S Receiver module to the s_axis_aud interface of the I2S Transmitter module. This means directly outputting the AXI4-Stream format audio data from the receiver module to the transmitter module, as shown below:

image-20250806173957945

Search for and add the clock module:

image-20250806174122795

Configure the clock: On the Clocking Options page, set the input clock to be provided by the MCLK pin of the WM8960 module. The frequency of the MCLK output from the WM8960 module is 24MHz. Therefore, set the input frequency to manual ("MANUAL") and change the clock frequency to 24MHz.

image-20250807171533207

On the Output Clocks page, set the frequency of the output clock clk_out1 to 18.432MHz to provide MCLK for the I2S Receiver/I2S Transmitter modules. This clock frequency is an integer multiple of 128 * Fs, where Fs is the audio sampling rate. In this experiment, the audio sampling rate Fs used is 48KHz, so the clock frequency of clk_out1 is N × 128 × 48 KHz, where N is a positive integer. When N is 3, the calculated clock frequency is 3 × 128 × 48000 = 18432000Hz, i.e., 18.432MHz.

image-20250807171601937

At the bottom of the Output Clocks page, uncheck the clock module's reset interface "reset". After setting, click "OK" in the lower right corner of the diagram.

image-20250805141057418

Bring out the clk_in1 in the above diagram via "Make External" and rename it to "aud_mclk"; then connect clk_out1 to the I2S Receiver and I2S Transmitter. After setting, it looks like the following:

image-20250807171945298

image-20250807172319039

Search for "vector" and add the "Utility Vector Logic" IP core, configuring it as follows:

image-20250807102658734

Use this NOT gate to invert the "locked" signal output from the clock module, then connect the inverted signal to the aud_mrst interface of the I2S Receiver and I2S Transmitter modules. After the clock output from the clock module stabilizes, the locked signal will go high; while the aud_mrst signal is active high for reset, so a NOT gate is needed to invert the locked signal. As shown below:

image-20250807172417943

Next, click "Run Block Automation" and "Run Connection Automation" at the top of the Diagram window to let the tool automatically connect the remaining module interfaces:

image-20250807172445013

In the dialog that pops up after clicking "Run Connection Automation", check "All Automation" on the left to perform automatic connections. After connection is complete, press CTRL+S to save the project and proceed to generate the top-level HDL file.

Add pin constraints: Right-click Constraints --> Add Source

image-20250805142356667

Add the xdc file:

image-20250805142442674

Perform synthesis, implementation, and export the .xsa file.

Create Vitis Project

Create a new platform project, application project, import the xsa file, and create a .c file.

The core code is as follows, mainly involving register operations:

Compilation and Debugging

Connect one end of the audio cable to an audio playback device and the other end to the development board's LINE_IN interface;

Connect the computer to the JTAG interface on the bottom board using a USB cable.

Then, connect the USB_UART interface on the left side of the development board to the computer using a USB cable for serial communication.