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.

am335x MCASP DMA problem

Hello every one:

I am using am335x sdk 06.00.00.00 kernel 3.2.0.

I use mcasp as i2s sending audio data to adau1961 codec.

I use my test program play  .wav  file one by one cycle using aplay  continously by  the system (aplay xxx.wav) in qt .

It was found that the aplay  sometime sleep in my test program when it change to play another wav file,

I go into the kernel find that after the davinci_pcm_trigger () execute ,there is no pcm_dma_irq ocurred ,then the poll of aplay sleep.

I should be result from dma error or  mcasp start error.

After trigger execute,then the data should be send to codec .when sending finished , there should be irq ocurred to update the pointer and wake up the aplay poll call.I add the printk in the irq function,when the problem occured ,there is no such printk output.

The sdk of am335x change a lot from my version,can anyone tell me which bug in the kernel will result this behavior?

Because it is impossible to change the kernel version  for some reason ,I want to implement the solution in the version which i am using.

Thanks.

wangl

  • Hi,

    I will ask the software team to look at this.
  • hi Biser :
    I am also strange about the following comments in the 2.0.0.0 newest kernel
    static void mcasp_start_tx(struct davinci_mcasp *mcasp)
    {.......
    /* wait for XDATA to be cleared */
    cnt = 0;
    while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) &
    ~XRDATA) && (cnt < 100000))
    cnt++;
    It look like that it is not waiting XDATA to be cleared,It seems that XDATA is not the break condition.
    It seems that it waiting error ocurred.If no XDMAERR or other error it will loop.

    Best regards
    wangl
  • Hello wangl,

    This is the given comment on this change.

    ASoC: davinci-mcasp: Correct TX start sequence
    
    Follow the sequence described in the TRMs when starting TX. This sequence
    will make sure that we are not facing with initial channel swap caused by
    no data available in McASP for transmit.


    You can search through the commits or use a commit viewer like a gitk to derive additional information and see why these changes were made, which may help you to find a clue on this issue.

    Best regards,
    Kemal

  • Dear Kemal:

    Thanks for your reply ,

    I have implement this solution to my 3.2.0 kernel version days ago, I have saw this  on the  log

    2014-10-29 ASoC: davinci-mcasp: Correct TX start sequence Peter Ujfalusi 2 -16/+15

    But things become strange that 

    It can not  play   B.wav when switching from A.wav to B.wav in the past using my test program.

    I  add the following in the mcasp_stop_tx() and the changing you mention above.

    val =  TXHCLKRST | TXCLKRST | TXFSRST;

    mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);

    mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);

    Then swithing from A .wav to B.wav is fine,

    But  one in ten times ,it  can not play the first wav file when I use my test program now.

    I am still puzzled ,I think maybe there are problem with the DMA.I am look through the TRM.

    Best regards

    wangl

  • Dear Kemal:
    There should be bug exist in the newest version mcasp driver.
    while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) &
    ~XRDATA) && (cnt < 100000))
    I found that every time it return the cnt is 0 and the TXSTAT_REG is 10C or 12C
    It do not wait the XRDATA to be cleared. It just wait for error , this code should be changed.
    It also find that when I meet the start problem the TXSTAT_REG always is 0x12C

    I add code like this :
    XSTAT=mcasp_get_reg(mcasp,DAVINCI_MCASP_TXSTAT_REG);
    if(XSTAT &XRDATA){
    udelay(100); //must add
    mcasp_set_bits(mcasp,DAVINCI_MCASP_TXSTAT_REG);
    }
    I have try it thousands time to start aplay a.wav then switch to aplay b.wav in qt, and then power on power off to check whether it wok fine.,

    The gap between power on and power off alway 10 seconds when it has no problem.
    it fail only one time when it first power on after 12 hours power off.It do not play any sound and aplay sleeped.
    It seems that have some effect.But problem still exist ,can you give me some advice?

    Best regards
    wangl
  • This is strange. Is there any log from the kernel or qt side indicating buffer overflow or something?
  • Dear kemal:

    Can you do the test on your evm board .

    I do beleive that you can reproduce this problem on your hardware.

    I also strange why there is always error ocurred?

    Best regards

    wangl

  • I can try to reproduce this. Which qt application and which audio sample you use?
  • Hello Kemal :

    Can you give me your email, I can send the qt test program to you.

    Best regards

    wangl

  • Sure, this is my email address: [removed to prevent unsolicited messages]

  • I run the test app. Now I shut down and left the device for 12 hours.
  • I couldn't reproduce this. The samples are playing at the first attempt, but the test app get stuck on 15-th sample which need further investigation.
  • Hello Kemal:

    Do you receive my program and try it ?

    You can copy about 15 .wav  file in windows system folder  to am335x file system,then test with it  ,

    I guess you will find that it can not play the first wave file sometime and aplay sleep and can not wake up by kernel space.

    It will be one in ten times.

    best regards

    wangl

  • Hi,Kemal:
    Do you mean the test app do not play the 15th sample wav file when switch from 14th sample to 15th sample wav in the playing loop?
    I meet many times it can not play one of the samples and may be the 2nd or 3rd,it is random.
    Then I think it relate to the mcasp_stop_tx in kernel, then I do some changed then it do not occurr when switching from A to B .
    But it happen 1 in 10 times when it first play the wav file.
    My test app only use QTimer and system call aplay to play the wav. It is not result from my test app.
    best regards
    wangl
  • To make sure, could you try to reproduce this just from the terminal

    for i in `ls Sound/`; do aplay Sound/$i ; done

    Also what kind of samples you use? The aplay may get stuck on re-sampling.

  • Dear Kemal:

    I use the mono wav 44100Hz, I have do some change in my kernel ,the possibility is very low now.

    There is no differece between you script and my test app.
    Your script is fine,but it do relate to kernel

    ,I also recompile the alsa lib-1.0.26 ,I add some print in it ,I find that the aplay sleep in the

    snd_pcm_write_areas()-> snd_pcm_wait()-> snd_pcm_wait_nocheck() ,it will poll the kernel.

    when problem come, it sleep,it never return.

    So there is no sound.
    Best regards
    wangl
  • You are right, the qt application is okay. I have reproduced this also with the script, then asked for a help and got this valuable pointers.

    Along with the 'ASoC: davinci-mcasp: Correct TX start sequence' patch I think
    it makes sense to take a look at:
    'ASoC: davinci-mcasp: When stopping TX/RX stop the AFIFO as the last step'

    It would be great to see the I2S fs/bclk lines when the audio is stuck, does
    it have the needed clocks?
    In most cases the no DMA generated and audio seams to be stuck is because the
    I2S master does not generate clocks so McASP is not shifting out any data. It
    might read some amount of data to the FIFO and you can check that via:
    cat /proc/asound/card0/pcm0p/sub0/status

    the hw_ptr is the point where ALSA thinks that the DMA is pointing to.

  • Dear Kemal:

    >>it makes sense to take a look at:
    >>'ASoC: davinci-mcasp: When stopping TX/RX stop the AFIFO as the last step'

    Yes,I clear he AFIFO twice,

    static void mcasp_stop_tx(struct davinci_audio_dev *dev)
    {
    mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST|TXCLKRST|TXSERCLR);
    mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
    mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,FIFO_ENABLE);
    }

    static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
    {
    if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
           if (dev->txnumevt) { /* disable FIFO */
               if (dev->version == MCASP_VERSION_3)
               mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,FIFO_ENABLE);
              else
              mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,FIFO_ENABLE);
           }
         mcasp_stop_tx(dev);
    } else {
    .......
    }
    }

    then the switching stuck problem gone ,but the new problem come 

    one in ten times the first wav file can not play.I do the change like this

    static void mcasp_start_tx(struct davinci_audio_dev *dev)
    {
    u8 offset = 0, i;
    u32 cnt;
    u32 XSTAT;

    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);

    mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,FIFO_ENABLE);
    mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL,FIFO_ENABLE);
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
    /* - wait for TX ready */

    cnt = 0;

    /*+wait for XDATA to be cleared*/
    while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG) &
    ~XRDATA) && (cnt <100000))
    cnt++;

    XSTAT=mcasp_get_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG);
    if(XSTAT & XRDATA) {

    udelay(100);

    mcasp_set_bits(dev->base + DAVINCI_MCASP_TXSTAT_REG,XRDATA);
    }

    /*Release TX State machine*/
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
    /*Release Frame Sync generator*/
    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);

    mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_EVTCTLX_REG, XUNDRN);
    }

    then ,the chance of first wav can not be play changed to about  1 in  50.

    I am still strange who write the code 

    /*+wait for XDATA to be cleared*/
    while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG) &
    ~XRDATA) && (cnt <100000))
    cnt++;

    It do not wait XDATA to be cleared ,anyhow I do not change it ,I clear it when it is 1.

    >>It would be great to see the I2S fs/bclk lines when the audio is stuck, does
    >>it have the needed clocks?

    I use adau1961 as the clock master, the am335x  AHCLK only provide 24MHZ clock to adau MCLK .

    Adau1961 will send the bclk and fs.

    When the problem come ,when there is switch stuck problem ,the bclk fs is fine,the ahclk also fine.

    I will test again and check the clock again because it is first wav can not be play problem now.

    wangl

  • Can you dump the McASP registers when it got stuck?

    Do they have the FIFO enabled in McASP :
    tx-num-evt = <32>;
    rx-num-evt = <32>;
    should be set for the McASP they are using.

    > I am still strange who write the code
    >
    > /*+wait for XDATA to be cleared*/
    > while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG) &
    > ~XRDATA) && (cnt <100000))
    > cnt++;
    >
    > It do not wait XDATA to be cleared ,anyhow I do not change it ,I clear it when
    > it is 1.

    The fix is already in linux-next:
    http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=e2a0c9fa80227be5ee017b5476638829dd41cb39

  • Dear Kemal:

    I have test it for 2 days but the stuck  do not come out .It only occurr one time  after I  put the workaround  on it.

    However ,one time error will make product of my company loss.I will ask tester test it  again and again.

    What is the state of your test?You said the fix is in linux-next ,

    then do you mean the  this update will fix the bug which I meet? But the update is same to my workaround

    >>Can you dump the McASP registers when it got stuck?

    >>Do they have the FIFO enabled in McASP :
    >>tx-num-evt = <32>;
    >>rx-num-evt = <32>;
    >>should be set for the McASP they are using.

    Which register do you mean?Can you tell me the offset ?

    Best regards

    wangl