Signal distortion on the audio codec's headphone out

I have a Dahlia v1.1B board with the Verdin iMX8M Mini Quad 2GB WB IT V1.1B based. The image used is your Linux Multimedia Reference 5.6.0+build.18 . The audio signals from the “AAP_HP_CON L/R” output (connector X14) are distorted and the amplitudes from right and left channel are differents.

Your image comes with some audio files for testing. When testing with the 440hz_10s.wav file, it is observed that the right channel sounds louder than the left and also the right channel seems to have some kind of distortion. In this link you can find an audio file that allows you to better test what I say. I am using aplay to play the audio files.

I have tried with several WAV type audio files and the problem is always the same, the right channel is heard louder and the audio is distorting. I have tried modifying the alsamixer parameters and have not found any set of values that makes this unwanted effect go away. I have also tried with different headphones and the problem does not go away.

I hope someone can help me.

Thanks,
Julián

Dear @jbruno, how are you?

Thanks for reaching out. Could you please share with us the following information in order to better understand your issue?

  • Did you do any changes to the image or is it our pre-built one?
  • Which Kernel are you using? Downstream or upstream?
  • What is the output of the following command on your module fw_printenv fdt_board? This is important to know as by default, the Verdin images come configured to use the Development Board Device Tree and it uses a different codec.

Best regards,
Guilherme

Hi @gclaudino.tx ,
Thank you very much for your quick response. I answer between the lines.

  • Did you do any changes to the image or is it our pre-built one?

The only change has been that we have interrupted the u-boot and set the fdt_board variable with the value dahlia as follows: setenv fdt_board dahlia and then saveenv

  • Which Kernel are you using? Downstream or upstream?

Linux verdin-imx8mm-06902246 5.4.161-5.6.0+git.0f0011824921 #1 SMP PREEMPT Fri Mar 25 14:27:29 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux

*What is the output of the following command on your module fw_printenv fdt-board ?

I use the variable fdt_board because Rafael Beims indicated. I don’t know I think this affects the audio performance.
fdt_board=dahlia
During boot this output is observed:
[ 0.000000] Machine model: Toradex Verdin iMX8M Mini WB on Dahlia Board

Best regards,
Julian

Thanks for the fast reply @jbruno,

The - was a typo in my previous message. I edited it to show the right one.

As I said before, the development board and dahlia use different codecs so if you’re using the wrong codec you’d experience problems with it but it seems that Rafael instructed you well about changing the device tree already.

Could you please share with us the full dmesg log? We’ll try to reproduce it on our side in the meantime.

Best regards,

Attached the log file.
dmesg.log (26.5 KB)
Thank you very much for your help.
Best regards,

Hi @gclaudino.tx ,
I have connected the oscilloscope to measure the signals from connector X14 while playing the audio file 440hz_10s.wav. Scope channel 1 displays the codec right channel and scope channel 2 displays the codec left channel. To my knowledge, in the capture of the oscilloscope you can clearly see that the signal of the right channel (ch1) is distorted by a misinterpretation of the numerical format.

I am attaching a file with the ALSA configuration.
alsa_conf.txt (5.2 KB)

I hope someone can help me.

Thanks,
Julián

Hi @jbruno,

We’re currently investigating this behavior internally as we could reproduce it here. Do you have other modules or carrier boards where you could reproduce it? We’ll come back to you once we have more news on the topic.

Best regards,

Hi @gclaudino.tx
I have tried on several Dahlia boards and with different Verdin modules, even with all versions of the linux multimedia reference image. The error is always the same, the MSB of the right channel is misinterpreted.

From the tests we’ve been doing, everything seems to point to an error in the i2s configuration, although we can’t confirm it yet. The WM8904 supports 4 different audio formats, which mode do you use? We have captured the i2s signals with a logic analyzer and it seems that you are using DSP Mode Audio Interface (mode A, AIF_LRCLK_INV=0, Master).

I await your news.

Best regards,

Dear @jbruno,

Thanks for the update. I’ve sent this to our team and we’ll come back once we have any news on it.

Please also keep us aware if you have any news on this topic.

Best regards,

Dear @gclaudino.tx

We have been analyzing the configurations of the audio codec and the i2s of the imx8mm that you make. From this analysis it can be deduced that both devices have been configured to work in I2S Justified Audio Interface mode (see figure 47 of the codec manual) but when measuring the I2S signals with the oscilloscope it seems that the imx8mm is transmitting in DSP Mode Audio Interface mode A format ( see figure 48 of the codec manual).

According to your configuration you are using a BCLK 34 times faster than the LRCLK, and since 32 bits are transmitted, two cycles of BCLK remain unused. In I2S Justified Audio Interface mode, these unused BCLK cycles between the LSB of one sample and the MSB of the next. In DSP Mode Audio Interface, these unused BCLK cycles between the LSB of the right channel data and the next sample.) The audio codec expects data in the first format but receives it in the second format and is for this reason it always misreads the MSB of the right channel.

We have done tests with a wav file that contains a square wave form, which only has two possible values ​​(0x7D and 0x83) that are repeated in time in both channels. Below I show some captures with the oscilloscope where you can see that the audio samples are transmitted in the DSP Mode Audio Interface format (mode A, AIF_LRCLK_INV=0, Master).

square 0x83 i2s - LRch.bmp (1.1 MB)
square 0x83 i2s - Rch.bmp (1.1 MB)
square 0x83 i2s - Lch.bmp (1.1 MB)

Below I show a scheme of my interpretation of the measurements made.

I don’t understand why the imx8mm is transmitting the audio samples in DSP format when it is configured to work in i2s format, has NXP reported this bug? In which format does the audio codec of your Verdin Development Board expect to receive the audio samples? Have you checked if this right channel distortion error is present on your card at the Verdin Development Board?

I await your news.

Best regards,

Dear @jbruno,

Thanks for the update. This will indeed be very useful for us to debug this behavior.

About that point:

I tested the same audio file on the Development Board and could get any distortion on my earphone as I experienced on the Dahlia. I didn’t have an oscilloscope with me, however. In any case, this doesn’t seem to happen on the Development Board. The Development Board uses a different codec than the Dahlia.

Best regards,

Dear @gclaudino.tx ,

I have it clear. The suspicion I have is that it is not the fault of the audio codec that misinterprets the data, but rather that it is the fault of the imx8mm that sends the data in the wrong format. If so, it could also fail on the Verdin Development Board.

Best regards,

Dear @gclaudino.tx,

I can confirm that this issue is due to a bug in the imx8mm SAI configuration. Analyzing the data frames with the sociloscpio there is no doubt that the SAI is transmitting the audio samples in DSP mode A format but the frame sync (LRCLK) is inverted, as shown below.

To test our theory and resolve this issue, we have modified the audio codec driver (wm8904.c) and the SAI driver (fsl-sai.c). We have forced the audio codec to work in DSP mode A format (SND_SOC_DAIFMT_DSP_A) and we have forced the SAI to work with inverted frame sync (FSL_SAI_CR4_FSP). The result of this patch can be seen below. In this figure it can be seen that neither of the two channels suffer any distortion.

For some unknown reason, the imx8mm SAI does not configure itself in I2S mode even though its driver tries to do so. For us the error must be in the fsl-sai.c file or in the fact that the driver tries twice to configure the sai.

I value your feedback, so let me know what you think!

Best regards,

Dear @jbruno,

Thanks for this great feedback. We really appreciate your effort to help us debug this problem. Could you please share your patch with us? I’ll forward it to the team investigating the issue on our side so that we could make a proper correction for future releases of our BSP’s.

If you wish you could send the patch here or by mail at support@toradex.com.

Best regards,

Hello @jbruno,
Sorry for the long delay in answering this. Thank you for your analysis of this issue. I did some research on this problem as well, and I’m pretty confident that the problem is not related to the wrong format being set on the digital interface. The formats are being properly set from the software point of view.
However, what I found is that there’s a small error when the sampling frequency is set to 44.1KHz:

As we can see, in this case, the actual clock is 45.2Khz. If we play a file that’s sampled at 48KHz, the error is much smaller and there’s no distortion on the right channel:

The distortion happens because the slightly wrong clock is enough to cause a 1-bit shift on the right channel of the I2S signal.
The error on the clock is caused by the fact that the root clock is not completely compatible with the 44.1KHz frequency, there’s no integer divider that can do it.

[  132.676490] wm8904 3-001a: Target BCLK is 1411200Hz
[  132.676504] wm8904 3-001a: Using 24576000Hz MCLK
[  132.676510] wm8904 3-001a: CLK_SYS is 12288000Hz
[  132.676514] wm8904 3-001a: Selected CLK_SYS_RATIO of 256
[  132.676518] wm8904 3-001a: Selected SAMPLE_RATE of 44100Hz
[  132.676522] wm8904 3-001a: Selected BCLK_DIV of 80 for 1536000Hz BCLK
[  132.676525] wm8904 3-001a: LRCLK_RATE is 34

There is a fractional divider in this codec, but it doesn’t seem to be used by the driver. This still needs to be investigated further.

The reason that I’m posting this right now is that there are actual workarounds for this problem, and maybe they would be enough to solve your issues:

  1. Only play audio sampled at frequencies that are multiple of 48KHz.

  2. Setup software resampling so that the codec always receives 48Khz instead of being fed directly with 44.1KHz.

Please let me know if these workarounds can work for you. I’ll keep analyzing if there’s a more definitive solution to the sampling frequency issue, but I can’t promise any timeline at the moment.

Best regards,
Rafael Beims

Hi @rafael.tx,
The configuration of the codec’s internal clocks is somewhat complex, but according to the manufacturer, there is a control mechanism to partially avoid this situation that you describe.

In the measurements that I made with the oscilloscope during my tests, the edges of BCLK and LRCLK seem to match, so I do not see a frequency deviation between both clocks.

It is true that if the clock divider is not adequate, a shift in frequency of the audio signal spectrum would occur. It would be like reproducing a signal at a different sample rate than the one at which it was synthesized. But this would not explain the distortion of the electrical signal as shown above.

I have tested with signals sampled at 44.1 kHz and 48 kHz and both signals have the same distortion. However our patch seems to solve the problem.

I am attaching two audio files that correspond to a 440Hz pure tone sampled at 44.1kHz and 48kHz. Please try to reproduce them and you will see that the same distortion is observed as in the image that I show above.

I await the results of your tests.

Best regards,

Everything that you said is correct. However, I think the part that you are missing is the fact that I2S needs a “dummy” bit between the left and the right channel:

If you count the bits in the 44.1KHz case, you will see that the “dummy” bit starts before the LRCLK signal changes phase. All the other bits of the channel are transferred after that. If the codec only starts reading bits after the edge of the LRCLK signal, this dummy bit will be lost and all the other bits will be shifted to the MSB direction.
In the 48KHz case, the bits are properly aligned (you can see it in the images I posted) and the distortion is not reproducible, at least in my case. As I already mentioned before, the signal that’s being generated by the SAI seems to be OK, including the “dummy” bits.
Could you try to enable the wm8904 dynamic debug output to check if the files are indeed being sent with the correct sample rate?

$ echo "file wm8904.c +p" > /sys/kernel/debug/dynamic_debug/control

After playing an audio file you should see something like this:

root@verdin-imx8mm-12345678:~# aplay -c 2 -Dsysdefault:CARD=imx8mmwm8904 440_hz_10min.wav 
Playing WAVE '440_hz_10min.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Mono
^CAborted by signal Interrupt...
aplay: pcm_write:2059: write error: Interrupted system call
root@verdin-imx8mm-12345678:~# dmesg|tail
[  282.566613] wm8904 3-001a: CLK_SYS is 12288000Hz
[  282.566619] wm8904 3-001a: Selected CLK_SYS_RATIO of 256
[  282.566625] wm8904 3-001a: Selected SAMPLE_RATE of 44100Hz
[  282.566631] wm8904 3-001a: Selected BCLK_DIV of 80 for 1536000Hz BCLK
[  282.566637] wm8904 3-001a: LRCLK_RATE is 34
[  282.566645] wm8904 3-001a: Set deemphasis 0
[  282.587357] wm8904 3-001a: Restoring DC servo state
[  282.605303] wm8904 3-001a: DC servo ready
[  282.609281] wm8904 3-001a: Restoring DC servo state
[  282.621330] wm8904 3-001a: DC servo ready
root@verdin-imx8mm-12345678:~# 
root@verdin-imx8mm-12345678:~# aplay -c 2 -Dsysdefault:CARD=imx8mmwm8904 440_hz_10min_48k.wav 
Playing WAVE '440_hz_10min_48k.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono
^CAborted by signal Interrupt...
aplay: pcm_write:2059: write error: Interrupted system call
root@verdin-imx8mm-12345678:~# dmesg|tail
[  316.275772] wm8904 3-001a: CLK_SYS is 12288000Hz
[  316.275776] wm8904 3-001a: Selected CLK_SYS_RATIO of 256
[  316.275780] wm8904 3-001a: Selected SAMPLE_RATE of 48000Hz
[  316.275784] wm8904 3-001a: Selected BCLK_DIV of 80 for 1536000Hz BCLK
[  316.275787] wm8904 3-001a: LRCLK_RATE is 32
[  316.275796] wm8904 3-001a: Set deemphasis 0
[  316.306125] wm8904 3-001a: Restoring DC servo state
[  316.321359] wm8904 3-001a: DC servo ready
[  316.329628] wm8904 3-001a: Restoring DC servo state
[  316.344139] wm8904 3-001a: DC servo ready

Hello @jbruno ,
Do you have any news on this topic?

Could you try to enable the wm8904 dynamic debug output to check if the files are indeed being sent with the correct sample rate?

Best regards,
Josep

Hi @josep.tx,
I have tried but apparently this path does not exist


I await your comments.
Regards,
Julián

Hello,
If you don’t have the file you are probably missing the CONFIG_DYNAMIC_DEBUG setting on your kernel. This config option is enabled by default in our latest BSP releases (I know that BSP 5.7.0 has it, not sure about earlier versions).
For more information about dynamic debugging on the linux kernel, check this link:
https://www.kernel.org/doc/html/v4.11/admin-guide/dynamic-debug-howto.html