I am hoping to get audio support for my custom Zynq-7000 development board. After a little digging into options, I am currently focusing on the WM8960 CODEC. In this blog post, I will share my progress; I will update this post as I have updates, so check back.
I previously researched a simple PWM solution like that in the Digilent Arty Z7. I also researched a Cirrus CS5343 + CS4344 CODEC solution, packaged in the Digilent Pmod I2S2. Unfortunately, I struggled to find PetaLinux drivers and support resources to get these to work in PetaLinux.
My initial objective is to get audio output using the aplay utility in PetaLinux 2024.2. I am using my custom Zynq-7000 board (see Xilinx XC7Z020-1CLG484I (Zynq-7000 SoC, Artix-7 FPGA)). For the WM8960, I am trying to get the Waveshare WM8960 Audio HAT working (see WM8960 Audio HAT - Waveshare Wiki).
I have found these two blogs to be helpful as I've gotten into this:
So here's the mess I have right now:
![](https://static.wixstatic.com/media/66a162_758d6e1bb31a4bf3ac157c7c3e7055a4~mv2.jpg/v1/fill/w_147,h_114,al_c,q_80,usm_0.66_1.00_0.01,blur_2,enc_auto/66a162_758d6e1bb31a4bf3ac157c7c3e7055a4~mv2.jpg)
![](https://static.wixstatic.com/media/66a162_1ab42317b6e94135a8983e7b7cce217f~mv2.png/v1/fill/w_110,h_55,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/66a162_1ab42317b6e94135a8983e7b7cce217f~mv2.png)
My main FPGA board has a couple of expansion ports. The right port is connected to a PCB that simply takes the signals to pin headers. Using those headers, I am connecting a Waveshare WM8960 Audio HAT. Below are the key sections of the HAT schematic.
One modification I made to the HAT is to connect the I2S_MCLK signal to an unused pin, ID_SD (27), on the pin header. This will allow me to get the MCLK from the 24 MHz oscillator and bring it into my block design in Vivado.
Here is my current Vivado block design:
The relevant portion of my constraints file:
![](https://static.wixstatic.com/media/66a162_d31fe7a25d0f4e01b5b5f0b139429704~mv2.png/v1/fill/w_49,h_8,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/66a162_d31fe7a25d0f4e01b5b5f0b139429704~mv2.png)
The pullups on the two I2C lines are required.
I am using PetaLinux 2024.2. I am working on a user module to create a custom sound card driver for my setup. I started with Yuhei Horibe's example.
Custom driver code: FPGA/PetaLinux 2024.2 Audio/wm8960-snddrv.c at main · rehsd/FPGA.
Setting WM8960 as master
PetaLinux device tree (dtsi): FPGA/PetaLinux 2024.2 Audio/system-user.dtsi at main · rehsd/FPGA.
WM8960 configured as part of AXI_IIC. Reg set to 0x1a.
audio-codec set for I2S transmitter and receiver
In the PetaLinux image, I have created ~/.asoundrc with these contents:
pcm.!default {
type hw
card 0
}
ctl.!default {
type hw
card 0
}
I have added ALSA support to PetaLinux. I did not add the xlnx_pl_snd_card.c driver (• SND_SOC_XILINX_PL_SND_CARD), as I am using my custom driver instead.
Latest Status
I am able to load the driver and see the sound card in PetaLinux (aplay, alsamixer, speaker-test). For now, I am manually loading the driver with one of the following:
insmod /lib/modules/6.6.40-xilinx-g2b7f6f70a62a/updates/wm8960-snddrv.ko
modprobe wm8960-snddrv
Ways I testing / troubleshooting:
I2C
i2cdetect -l
i2cdetect -r "xiic-i2c 41600000.i2c" 0x1a 0x1a
i2cget -y -f 2 0x1a 0x00
i2cset -y -f 2 0x1a 0x00 0x55
Logs
dmesg | grep snd
dmesg | grep sound
dmesg | grep audio
dmesg | grep i2c
dmesg | grep rehsd
aplay -l
speaker-test
aplay /usr/bin/rehsd/sample.wav
alsamixer
arecord -l
Oscilloscope
I2C lines
I2S lines
dtsi review
a. Generate dtsi from Vivado hardware
/xilinx/Vitis/2024.2/bin/xsct
sdtgen set_dt_param -dir sdt_out -xsa ~/petalinux20242/rehsdZynq/rehsdZynq_BD_wrapper.xsa
sdtgen generate_sdt
I am currently running into a write error.
speaker-test -c 2
speaker-test 1.2.11
Playback device is default
Stream parameters are 48000Hz, S16_LE, 2 channels
Using 16 octaves of pink noise
Rate set to 48000Hz (requested 48000Hz)
Buffer size range from 96 to 76800
Period size range from 48 to 12800
Periods = 4 was set
period_size = 12000 was set
buffer_size = 48000 0 -
Front Left
Write error: -5
Input/output error
xrun_recovery failed: -5,
Input/output error
Transfer failed: Input/output error
Using an oscilloscope, I am seeing I2C traffic, but I am not seeing I2S traffic. I expect this is related to improper configuration of the WM8960 codec.
Update - 27 January 2025
I have updated the Vivado design. I am bringing in MCLK 24MHz from the WM8960 board into the Zynq-7000 board and then using the I2S Transmitter IP block to generate the other I2S clocks (which go back to the WM8960 board). From what I can tell, clocks are all working now. I have also done a bunch of updates to the custom sound driver and am thinking it's close to where it needs to be. I am still getting the -5 Write Error. I am not seeing any traffic on the I2S data out (DAC) line. My next step is to take another run at the Vivado design, separating the I2S supporting components from other existing components I had in Vivado. I'll post an update video after I get through that. I posted updated Vivado block design PDF, dtsi, and sound driver code files to FPGA/PetaLinux 2024.2 Audio/update 2025-01-27 at main · rehsd/FPGA.
Update - 05 February 2025
I now have audio output working! See the video below and corresponding content on my GitHub.
I grabbed another I/O expansion board and setup a "fly wire free" version for the WM8960. This feels so much better, and I don't need to worry about accidentally disconnecting wires. This I/O board includes headers for SPI (previous YouTube video) and additional headers for yet-to-be-used Zynq-7000 I/O pins.
![](https://static.wixstatic.com/media/66a162_d11fca8e0d8c4232b640f65cc4c026a9~mv2.jpg/v1/fill/w_147,h_80,al_c,q_80,usm_0.66_1.00_0.01,blur_2,enc_auto/66a162_d11fca8e0d8c4232b640f65cc4c026a9~mv2.jpg)
More to come!
Additional Notes
![](https://static.wixstatic.com/media/66a162_e064293e99a541ea9fb1cab67ccbd349~mv2.png/v1/fill/w_87,h_69,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_auto/66a162_e064293e99a541ea9fb1cab67ccbd349~mv2.png)
I see Waveshare has a simpler board available, too. I have ordered one of these to try out. For this specific audio project, this board looks to be a better option. It doesn't have unecessary header pins and gives easy access to mclk -- input or output. WM8960 Audio Board - Waveshare Wiki
WM8960 supported formats
SNDRV_PCM_FMTBIT_S16_LE (Signed Little Endian)
SNDRV_PCM_FMTBIT_S20_3LE
SNDRV_PCM_FMTBIT_S24_LE
SNDRV_PCM_FMTBIT_S32_LE