[alsa-devel] Problem with MX27 ASoC audio
I have a target that uses iMX27(L) + tlv320aic3x. The kernel tree is HEAD of linux-arm from about a week ago.
Simple playback and recording (using aplay and arecord) work fine. However, I've run into a strange problem when both playback and capture streams are opened at the same time.
Consider the attached test program. The capture device is setup with a period time of 10ms, and the program reads samples in a loop. The expected result is that I get a sample every 10ms. This works fine if the playback device is *not* opened (more specifically, if the hw_params are not set). However if the playback device is opened (#if 1 code) then I get samples every 20ms, which seems very wrong.
I have tried using both DMA and FIQ ssi-pcm interfaces and both give the same strange result. With the FIQ driver, if I instrument the timer callback, the timer triggers every 10ms but there is only enough data every 20ms.
The codec is being driven with a 13MHz MCLK (output from MX27) and the BCLK and WCLK come from the codec. They seem to have the correct rates.
Any ideas? Can anybody else with MX27 hardware verify if my test program also fails on their target?
thanks, randolph
/* Test program */
#include <alsa/asoundlib.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <sys/time.h>
int main(int argc, char **argv) { int err = -1; char buf[4096]; unsigned long period_size; snd_pcm_t *in_handle = NULL, *out_handle; snd_pcm_hw_params_t *hwparams;
if (snd_pcm_open(&in_handle, "hw:0,0", SND_PCM_STREAM_CAPTURE, 0) < 0) { printf("Cannot open capture device\n"); return -1; } snd_pcm_hw_params_malloc(&hwparams); snd_pcm_hw_params_any(in_handle, hwparams); snd_pcm_hw_params_set_access(in_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(in_handle, hwparams, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(in_handle, hwparams, 1); snd_pcm_hw_params_set_rate(in_handle, hwparams, 8000, 0); snd_pcm_hw_params_set_period_time(in_handle, hwparams, 10000, 0); snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0); snd_pcm_hw_params(in_handle, hwparams); snd_pcm_hw_params_free(hwparams);
if (snd_pcm_open(&out_handle, "hw:0,0", SND_PCM_STREAM_PLAYBACK, 0) < 0) { printf("Cannot open playback device\n"); return -1; } #if 1 snd_pcm_hw_params_malloc(&hwparams); snd_pcm_hw_params_any(out_handle, hwparams); snd_pcm_hw_params_set_access(out_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(out_handle, hwparams, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(out_handle, hwparams, 1); snd_pcm_hw_params_set_rate(out_handle, hwparams, 8000, 0); snd_pcm_hw_params_set_period_time(out_handle, hwparams, 10000, 0); snd_pcm_hw_params(out_handle, hwparams); snd_pcm_hw_params_free(hwparams); #endif
printf("period size = %u\n", period_size);
printf("Config done, start loop\n"); while (1) { struct timeval tv; int ret = snd_pcm_readi(in_handle, buf, period_size); if (ret < 0) snd_pcm_prepare(in_handle); gettimeofday(&tv, NULL); printf("[%u.%06u] snd_pcm_readi() return %d\n", tv.tv_sec, tv.tv_usec, ret); }
return 0; }
On Thu, Aug 12, 2010 at 06:15:47PM +0800, Randolph Chung wrote:
I have a target that uses iMX27(L) + tlv320aic3x. The kernel tree is HEAD of linux-arm from about a week ago.
Simple playback and recording (using aplay and arecord) work fine. However, I've run into a strange problem when both playback and capture streams are opened at the same time.
Consider the attached test program. The capture device is setup with a period time of 10ms, and the program reads samples in a loop. The expected result is that I get a sample every 10ms. This works fine if the playback device is *not* opened (more specifically, if the hw_params are not set). However if the playback device is opened (#if 1 code) then I get samples every 20ms, which seems very wrong.
I have tried using both DMA and FIQ ssi-pcm interfaces and both give the same strange result. With the FIQ driver, if I instrument the timer callback, the timer triggers every 10ms but there is only enough data every 20ms.
The codec is being driven with a 13MHz MCLK (output from MX27) and the BCLK and WCLK come from the codec. They seem to have the correct rates.
Any ideas? Can anybody else with MX27 hardware verify if my test program also fails on their target?
You should check the return values of the snd_pcm_hw_params_* functions. At least snd_pcm_hw_params_set_channels fails because we currently only support two channels. I'm not sure whether we can support one channel mode without changes to the driver.
Sascha
On Thu, Aug 12, 2010 at 8:56 PM, Sascha Hauer s.hauer@pengutronix.de wrote:
On Thu, Aug 12, 2010 at 06:15:47PM +0800, Randolph Chung wrote:
I have a target that uses iMX27(L) + tlv320aic3x. The kernel tree is HEAD of linux-arm from about a week ago.
Simple playback and recording (using aplay and arecord) work fine. However, I've run into a strange problem when both playback and capture streams are opened at the same time.
Consider the attached test program. The capture device is setup with a period time of 10ms, and the program reads samples in a loop. The expected result is that I get a sample every 10ms. This works fine if the playback device is *not* opened (more specifically, if the hw_params are not set). However if the playback device is opened (#if 1 code) then I get samples every 20ms, which seems very wrong.
I have tried using both DMA and FIQ ssi-pcm interfaces and both give the same strange result. With the FIQ driver, if I instrument the timer callback, the timer triggers every 10ms but there is only enough data every 20ms.
The codec is being driven with a 13MHz MCLK (output from MX27) and the BCLK and WCLK come from the codec. They seem to have the correct rates.
Any ideas? Can anybody else with MX27 hardware verify if my test program also fails on their target?
You should check the return values of the snd_pcm_hw_params_* functions. At least snd_pcm_hw_params_set_channels fails because we currently only support two channels. I'm not sure whether we can support one channel mode without changes to the driver.
I will double check tomorrow, but I have another version of the code that checks all the return values and I am quite sure the set_channels didn't fail....
In any case why would it work if there is only a capture device open?
Also I would imagine even if there are 2 channels the code should still work....
I would appreciate some test results on another mx27 board to verify if it is a problem specific to my setup or generic to other mx27 targets.
thanks, randolph
On Thu, Aug 12, 2010 at 10:59:19PM +0800, Randolph Chung wrote:
I will double check tomorrow, but I have another version of the code that checks all the return values and I am quite sure the set_channels didn't fail....
Actually, if the interval between the time periods doubles in the failure case that suggests that the hardware may have decided to start running in mono mode...
On Thu, Aug 12, 2010 at 11:01 PM, Mark Brown broonie@opensource.wolfsonmicro.com wrote:
On Thu, Aug 12, 2010 at 10:59:19PM +0800, Randolph Chung wrote:
I will double check tomorrow, but I have another version of the code that checks all the return values and I am quite sure the set_channels didn't fail....
Actually, if the interval between the time periods doubles in the failure case that suggests that the hardware may have decided to start running in mono mode...
I investigated this a bit further. Sasha is right that only stereo channels work. However in the end that is not really relevant to my problem.
The below may be a related issue:
I initiate a recording using arecord from the command line:
arecord -D hw:0,0 -f S16_LE -r 8000 -c 2 -d 5 /dev/null (this command actually takes 10 seconds to complete)
I check the clock rates on the physical connections from the codec: MCLK = 13MHz BCLK = 8kHz WCLK = 256kHz
This seems to be correct. However, on the MX27 side I only get "half" the data (i.e. the data arrives at a rate of 128kHz). This is checked by instrumenting the DMA driver in the progression routine or the FIQ driver in the timer routine. (Also from checking the time arecord runs) If I hack my codec to double the datarate to 16kHz then I get back data that plays back correctly at 8kHz (my earlier test was using this hack, which I had forgotten about). So this seems to be a problem on the MX27 side.
I am not sure if there is any special additional setup that might be needed in my machine driver to match up the codec configuration. It would seem to me that if the MX27 is the I2S slave, then it should just clock in data using the external clock signals, so I don't quite understand how the received data rate can not match what is coming from the codec. Playback works fine without any hacks.
Any ideas? I do not see any in-tree drivers that use MX27+I2S codecs, only MX27+AC97, which goes through a different path. Just wondering if the I2S path works for others in the capture case?
randolph
Hi Randolph,
Le 16/08/2010 11:27, Randolph Chung a écrit :
Any ideas? I do not see any in-tree drivers that use MX27+I2S codecs, only MX27+AC97, which goes through a different path. Just wondering if the I2S path works for others in the capture case?
it's working (at least was working a few weeks ago) here on an i.MX27 using a TLV320AIC23B which is the I2S master, check : sound/soc/imx/eukrea-tlv320.c
Eric
Any ideas? I do not see any in-tree drivers that use MX27+I2S codecs, only MX27+AC97, which goes through a different path. Just wondering if the I2S path works for others in the capture case?
it's working (at least was working a few weeks ago) here on an i.MX27 using a TLV320AIC23B which is the I2S master, check : sound/soc/imx/eukrea-tlv320.c
Thanks for the pointer. I was able to get this to work better after I applied your changes related to I2S slave register settings to imx-ssi.c.
Nonetheless, the system still doesn't behave properly when record and playback are happening at the same time. Here's a simple test:
In one session, do: # time arecord -D hw:0,0 -f S16_LE -c 2 -d 60 /dev/null Recording WAVE '/dev/null' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo real 1m 0.32s user 0m 0.18s sys 0m 8.65s
This works fine. But if you repeat the test, while in another session do some audio output (e.g. speaker-test or aplay), the record will get a lot of overruns and will finish prematurely: # time arecord -D hw:0,0 -f S16_LE -c 2 -d 60 /dev/null Recording WAVE '/dev/null' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo overrun!!! (at least 0.659 ms long) overrun!!! (at least 0.204 ms long) overrun!!! (at least 0.324 ms long) overrun!!! (at least 1.225 ms long) overrun!!! (at least 0.597 ms long) overrun!!! (at least 0.081 ms long) overrun!!! (at least 0.881 ms long) overrun!!! (at least 0.168 ms long) overrun!!! (at least 0.691 ms long) overrun!!! (at least 0.528 ms long) overrun!!! (at least 0.672 ms long) overrun!!! (at least 3.534 ms long) overrun!!! (at least 1.264 ms long) overrun!!! (at least 0.019 ms long) overrun!!! (at least 0.514 ms long) real 0m 13.39s user 0m 0.16s sys 0m 9.04s
It appears the DMA is not able to keep up (or we are missing interrupts?) when there are two channels running simultaneously. The xrun stacktrace looks like this: [ 501.680000] [<c0287e70>] (xrun+0x0/0xec) from [<c02889a8>] (snd_pcm_update_state+0x104/0x10c) [ 501.680000] r6:0000dac0 r5:cf745100 r4:cf133000 [ 501.680000] [<c02888a4>] (snd_pcm_update_state+0x0/0x10c) from [<c0288c1c>] (snd_pcm_update_hw_ptr0+0x26c/0x7a0) [ 501.680000] r5:7d000000 r4:0000e678 [ 501.680000] [<c02889b0>] (snd_pcm_update_hw_ptr0+0x0/0x7a0) from [<c02891f0>] (snd_pcm_period_elapsed+0xa0/0xf0) [ 501.680000] [<c0289150>] (snd_pcm_period_elapsed+0x0/0xf0) from [<c029f468>] (imx_ssi_dma_progression+0x38/0x3c) [ 501.680000] r6:00004829 r5:00000009 r4:c041fa74 [ 501.680000] [<c029f430>] (imx_ssi_dma_progression+0x0/0x3c) from [<c0034014>] (dma_irq_handler+0x254/0x348) [ 501.680000] [<c0033dc0>] (dma_irq_handler+0x0/0x348) from [<c006f538>] (handle_IRQ_event+0x48/0x11c)
I have also noticed that the DMA watchdog timer sometimes triggers. I've increased the timeout to 2s for testing.
Will do more digging around, but maybe somebody else has an idea.
randolph
Nonetheless, the system still doesn't behave properly when record and playback are happening at the same time. Here's a simple test:
Actually the problem is due to "mismatched" recording and playback rates. My test was recording at 8kHz and playing back at 48kHz. The codec driver only supports playback rate = capture rate. When the playback starts the codec starts clocking at 48kHz which causes the xruns.
Will see if the codec driver (tlv320aic3x) can be fixed up.
randolph
On Wed, Aug 18, 2010 at 03:53:16PM +0800, Randolph Chung wrote:
Nonetheless, the system still doesn't behave properly when record and playback are happening at the same time. Here's a simple test:
Actually the problem is due to "mismatched" recording and playback rates. My test was recording at 8kHz and playing back at 48kHz. The codec driver only supports playback rate = capture rate. When the playback starts the codec starts clocking at 48kHz which causes the xruns.
Will see if the codec driver (tlv320aic3x) can be fixed up.
If the CODEC has only a single LRCLK pin then it should be setting the symmetric_rates flag in its DAI. The core will then take care of the symmetry requirements for it.
On Wed, Aug 18, 2010 at 4:41 PM, Mark Brown broonie@opensource.wolfsonmicro.com wrote:
On Wed, Aug 18, 2010 at 03:53:16PM +0800, Randolph Chung wrote:
Nonetheless, the system still doesn't behave properly when record and playback are happening at the same time. Here's a simple test:
Actually the problem is due to "mismatched" recording and playback rates. My test was recording at 8kHz and playing back at 48kHz. The codec driver only supports playback rate = capture rate. When the playback starts the codec starts clocking at 48kHz which causes the xruns.
Will see if the codec driver (tlv320aic3x) can be fixed up.
If the CODEC has only a single LRCLK pin then it should be setting the symmetric_rates flag in its DAI. The core will then take care of the symmetry requirements for it.
The codec (at least the variant of tlv320aic3x that I am using) can have two pins in the hardware, but it's up to the board whether it's hooked up that way. The codec driver as currently implemented assumes the rates are symmetric, but it need not be.
I see that there is a symmetric_rates flag for the dai_link too. Thanks for the pointer.
randolph
On Wed, Aug 18, 2010 at 04:58:12PM +0800, Randolph Chung wrote:
The codec (at least the variant of tlv320aic3x that I am using) can have two pins in the hardware, but it's up to the board whether it's hooked up that way. The codec driver as currently implemented assumes the rates are symmetric, but it need not be.
In that case the driver should be setting the symmetric_rates flag anyway since it does have this constraint - if it implements support for asymmetric rates then the flag can be removed then.
I see that there is a symmetric_rates flag for the dai_link too.
This is still a good idea if your board has a single LRCLK anyway in case someone does do asymmetric rates.
Mark Brown <broonie <at> opensource.wolfsonmicro.com> writes:
On Wed, Aug 18, 2010 at 04:58:12PM +0800, Randolph Chung wrote:
The codec (at least the variant of tlv320aic3x that I am using) can have two pins in the hardware, but it's up to the board whether it's hooked up that way. The codec driver as currently implemented assumes the rates are symmetric, but it need not be.
In that case the driver should be setting the symmetric_rates flag anyway since it does have this constraint - if it implements support for asymmetric rates then the flag can be removed then.
I see that there is a symmetric_rates flag for the dai_link too.
This is still a good idea if your board has a single LRCLK anyway in case someone does do asymmetric rates.
Hi experts, We are also working on getting the audio work with the same codec tlv320aic3x (TLV320AIC3106) with AT91SAMAD34 board. Playback is working fine with the board. But we have issues with capture. On "arecord" , nothing is being recorded in the file. Can you please tell us the TLV320AIC3X register settings that has to be to make the capture work.
Thanks in adavnce, Dhiv.
participants (5)
-
Dhiv
-
Eric Bénard
-
Mark Brown
-
Randolph Chung
-
Sascha Hauer