This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

McASP TDM capture on Beaglebone: Random channel swaps due to skipped time-slots



Hello,

I'm capturing an 8-channel TDM stream on McASP0 (just record, no playback). My ALSA driver seem to work porperly when CPU load is low, however, I'm experiencing some very strange behaviour when CPU load (and/or SDcard access) increases: suddenly channels are swapping randomly (signal from channel 1 is now on channel 2 etc.).

The reason seems to be, that some time-slots (4 byte) get lost along the way such that the recorded signal looks like

FRAME1: ch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8

FRAME2: ch1 ch2 ch3 ch4 ch5 ch6 ch7 ch1 (<= ch8 slot missing!)

FRAME3: ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch1

FRAME4: ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch1

and so on...

Since this problem seems to correlate with cpu/disc usage, I'm pretty sure that the problem isn't in the codec but in the processor side (also due to the fact that there are no bit shifts - only entirely missing time-slots) . The problem is, that I have no clue how to debug this error - it just seems that somwhere on the way from McASP serializer0 via DMA buffer to the ALSA API those 4 Bytes are lost.

Can anyone suggest a way to debug this behaviour?

Also it seems that the McASP driver isn't using ping pong buffering since davinci_pcm_enqueue_dma (sound/soc/davinci/davinci-pcm.c) is called on every DMA interrupt. Should ping/pong buffering be used, and if so, how can I enable it?  

best,

Chris

  • Chris,

    This could be because the stop and restart sequence after the XRUN in the ALSA layer is incorrect

    Could you please try the following fix and let me know it solves you issue.

    diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
    index 2879c88..3721c62 100644
    --- a/sound/soc/soc-pcm.c
    +++ b/sound/soc/soc-pcm.c
    @@ -515,22 +515,45 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
         struct snd_soc_dai *codec_dai = rtd->codec_dai;
         int ret;
     
    -    if (codec_dai->driver->ops->trigger) {
    -        ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
    -        if (ret < 0)
    -            return ret;
    -    }
    +    if (cmd == SNDRV_PCM_TRIGGER_START
    +        || cmd == SNDRV_PCM_TRIGGER_RESUME
    +        || cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) {
    +
    +        if (codec_dai->driver->ops->trigger) {
    +            ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
    +            if (ret < 0)
    +                return ret;
    +        }
     
    -    if (platform->driver->ops && platform->driver->ops->trigger) {
    -        ret = platform->driver->ops->trigger(substream, cmd);
    -        if (ret < 0)
    -            return ret;
    -    }
    +        if (platform->driver->ops && platform->driver->ops->trigger) {
    +            ret = platform->driver->ops->trigger(substream, cmd);
    +            if (ret < 0)
    +                return ret;
    +        }
     
    -    if (cpu_dai->driver->ops->trigger) {
    -        ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
    -        if (ret < 0)
    -            return ret;
    +        if (cpu_dai->driver->ops->trigger) {
    +            ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
    +            if (ret < 0)
    +                return ret;
    +        }
    +    } else {
    +        if (codec_dai->driver->ops->trigger) {
    +            ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
    +            if (ret < 0)
    +                return ret;
    +        }
    +
    +        if (cpu_dai->driver->ops->trigger) {
    +            ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
    +            if (ret < 0)
    +                return ret;
    +        }
    +
    +        if (platform->driver->ops->trigger) {
    +            ret = platform->driver->ops->trigger(substream, cmd);
    +            if (ret < 0)
    +                return ret;
    +        }
         }
         return 0;
     }