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.

OMAP4430: Stereo Audio Channel Swap Issue: Need help.

I am seeing a very peculiar channel swap issue on the OMAP4430. I have provided all the details of the issue. I am really stuck right now and looking for any help/pointers to move forward. 

Or Is this an existing issue reported on OMAP4430? If so what was the root cause and how was it resolved?

Issue Summary:

 In the stereo 48K recorded audio, the left and right channels are swapped randomly – sometimes at the beginning, sometimes in the middle.  This is observed during playback also, when played an audio file that has data only on left channel.

 Setup:

 Android Gingerbread, L27.G.5 source base. OMAP4430 (I2S Master) talking to an Audience Codec (Slave) through McBSP3. sDMA is used to transfer audio data from/to peripheral to/from OMAP’s memory. Stereo 48K recording. Sample size per channel is 16 bit. A user space linux utility is running that calls a blocking system read call to record audio with a large buffer of size 122880. Once buffer is filled the utility writes the buffer data to a file and calls again Read. Using packet mode of transfer in DMA. McBSP3 thresholds are set at 128 words.DMA chaining is used. Logical channels 2 and 3 are used.

 Ruled Out:

 Clocks and Frame Sync from OMAP4430 are clean. The polarity of these clocks and frame sync are verified to be as expected. Oscilloscope probes connected to the test points to monitor McBSP3 Clk, FS, Dx and DR lines shows that audience codec sends the data on the correct channels. There is no programming error in calculating offsets within the data buffers that accumulates audio data during record or drains data during playback.

 Experiments done:

On MCBSP settings, tried dual phase, 16 bit per phase – same issue. Single phase, 32 bit also has same issue.

 Attachments:

SerialConsole.log – Log that has McBSP, DMA settings during record and a subsequent playback.

ve_rec120424094530.pcm – Recorded file

chswap_logs\rec_reg_dump\mcbsp3_reg0.rd – McBSP3 register dump during record

chswap_logs\rec_reg_dump\sdma_reg0.rd – sDMA channels register dump

chswap_logs\rec_reg_dump\omap4430_aud_mcbsp_rec.rd1 – Clock register dump to be given as input for the TI clocktree tool.

 chswap_logs\pb_reg_dump\mcbsp3_reg0.rd – McBSP3 register dump during playback

chswap_logs\pb_reg_dump\sdma_reg0.rd – sDMA channels register dump

chswap_logs\pb_reg_dump\omap4430_aud_mcbsp_rec.rd1 – Clock register dump to be given as input for the TI clocktree tool.

chswap_logs.zip
  • Hi,

    I think the problem is in the configuration of McBSP and/or sDMA. Can you share the steps how are you configure them?

    Also take a look to: http://processors.wiki.ti.com/index.php?title=McBSP_Channel_Swapping

  • The link you gave did not help. As I am not using McBSP in slave mode.

    Here is more information.

    I am not using ALSA style instead using a OSS style driver taken from droid2 codebase. I have dumped the McBSP3 and sDMA registers for recording (Rx) and Playback (Tx). Recording uses Logical DMA channels 4 and 5, chained together. Playback uses DMA channels 2 and 3 chained together.

     

    I am using packed mode of transfer in sDMA. Using HW synchronized transfer. Source sync for Recording and Destination Sync for Playback.

     

    Audience codec is configured to use I2S on its digital port connected to McBSP3.

     

    I understand your comment about the McBSP threshold value, but playing around with it did not help fix the channel swap. I did saw underrun on Rx initially. But when I modified to start the McBSP RRST earlier before DMA, the underrun was gone but the channel swap problem was still there.

     

    The following is my setting for FSG:

     

    static struct omap_mcbsp_srg_fsg_cfg srg_fsg_params = {

          .period = 31, /* Frame period */

          .pulse_width = 15, /* Frame width */

          .fsgm = 1,

          .sample_rate = 48000,

          .bits_per_sample = 32, 

          .srg_src =  OMAP_MCBSP_SRGCLKSRC_CLKS, //OMAP_MCBSP_SRGCLKSRC_FCLK,

          .sync_mode = OMAP_MCBSP_SRG_FREERUNNING, /* SRG free running mode */

          .polarity = OMAP_MCBSP_CLKS_POLARITY_RISING,

          .dlb = 0, /* digital loopback mode */

    };

     

     

    I have used each of the following McBSP phase settings, (Audience codec is set to generate sine tone 1Khz only on left channel with right channel silence - put on I2S. ) and observed the following:

     

    Record Settings 1: - This has random channel swap, sometimes in the beginning and stays, sometimes no channel swap and sometimes swaps in the middle.

     

    static struct omap_mcbsp_cfg_param rx_cfg_params = {

          .fsync_src = OMAP_MCBSP_RXFSYNC_INTERNAL,

          .fs_polarity = OMAP_MCBSP_FS_ACTIVE_LOW, 

          .clk_polarity = OMAP_MCBSP_CLKR_POLARITY_RISING,

          .clk_mode = OMAP_MCBSP_CLKRXSRC_INTERNAL,

          .frame_length1 = OMAP_MCBSP_FRAMELEN_N(1), 

          .word_length1 = OMAP_MCBSP_WORD_16,      

          .frame_length2 = OMAP_MCBSP_FRAMELEN_N(1), 

          .word_length2 = OMAP_MCBSP_WORD_16,            

          .justification = OMAP_MCBSP_RJUST_ZEROMSB,     

          .reverse_compand = OMAP_MCBSP_MSBFIRST,

          .phase = OMAP_MCBSP_FRAME_DUALPHASE, 

          .data_delay = OMAP_MCBSP_DATADELAY1,

    };

     

    static struct omap_mcbsp_dma_transfer_params rx_params = {

          .skip_alt = OMAP_MCBSP_SKIP_NONE,

          .auto_reset = OMAP_MCBSP_AUTO_RRST,

          .callback = mcbsp_dma_rx_cb,

          .word_length1 = OMAP_MCBSP_WORD_16,

          .word_length2 = OMAP_MCBSP_WORD_16,

    };

     

     

    Record Settings 2: This has channel swap right from the beginning and stays the same. This is the setting used in the attached recording (stereo 48K, intel raw PCM format), and register dumps.

     

    static struct omap_mcbsp_cfg_param rx_cfg_params = {

          .fsync_src = OMAP_MCBSP_RXFSYNC_INTERNAL,

          .fs_polarity = OMAP_MCBSP_FS_ACTIVE_LOW, 

          .clk_polarity = OMAP_MCBSP_CLKR_POLARITY_RISING,

          .clk_mode = OMAP_MCBSP_CLKRXSRC_INTERNAL,

          .frame_length1 = OMAP_MCBSP_FRAMELEN_N(1), 

          .word_length1 = OMAP_MCBSP_WORD_32,      

          //.frame_length2 = OMAP_MCBSP_FRAMELEN_N(1), 

          //.word_length2 = OMAP_MCBSP_WORD_16,          

          .justification = OMAP_MCBSP_RJUST_ZEROMSB,     

          .reverse_compand = OMAP_MCBSP_MSBFIRST,

          .phase = OMAP_MCBSP_FRAME_SINGLEPHASE, 

          .data_delay = OMAP_MCBSP_DATADELAY1,

    };

     

    static struct omap_mcbsp_dma_transfer_params rx_params = {

          .skip_alt = OMAP_MCBSP_SKIP_NONE,

          .auto_reset = OMAP_MCBSP_AUTO_RRST,

          .callback = mcbsp_dma_rx_cb,

          .word_length1 = OMAP_MCBSP_WORD_32,

          //.word_length2 = OMAP_MCBSP_WORD_16,

    };

     

     

    Playback Settings: When I used the following settings, I do NOT observe channel swap. If I used dual phase and 16 bit each phase I did observe random channel swap.

     

     

    static struct omap_mcbsp_cfg_param tx_cfg_params = {

          .fsync_src = OMAP_MCBSP_TXFSYNC_INTERNAL,  // was external

          .fs_polarity = OMAP_MCBSP_FS_ACTIVE_HIGH,  

          .clk_polarity = OMAP_MCBSP_CLKX_POLARITY_FALLING,

          .clk_mode = OMAP_MCBSP_CLKTXSRC_INTERNAL, // was external

          .frame_length1 = OMAP_MCBSP_FRAMELEN_N(1), // was 1

          .word_length1 = OMAP_MCBSP_WORD_32,       // should this be 32??? - SK

          //.frame_length2 = OMAP_MCBSP_FRAMELEN_N(1), // was 1

          //.word_length2 = OMAP_MCBSP_WORD_16,       // should this be 32??? - SK

          .justification = OMAP_MCBSP_RJUST_ZEROMSB,

          .reverse_compand = OMAP_MCBSP_MSBFIRST,

          .phase = OMAP_MCBSP_FRAME_SINGLEPHASE,

          .data_delay = OMAP_MCBSP_DATADELAY1,

    };

     

    static struct omap_mcbsp_dma_transfer_params tx_params = {

          .skip_alt = OMAP_MCBSP_SKIP_NONE,

          .auto_reset = OMAP_MCBSP_AUTO_XRST,

          .callback = mcbsp_dma_tx_cb,

          .word_length1 = OMAP_MCBSP_WORD_32,

          //.word_length2 = OMAP_MCBSP_WORD_16,

    };

     

    Hopefully that gives more data to check what is going on.

     

    -sathiya

    1321.chswp1.zip

  • Hi Sathiya,

    I am trying to reproduce the issue. I can't connect something to the McBSP3, but I have made a HW hack in order have a loop in McBSP2. I will update as soon as I have something.

  • Hi Sathiya,

    I don't know much about your driver, so it would be good to know if you are following the McBSP Basic Programming model in TRM.

    IE: Figure 23-157. Flow Diagram of McBSP Initialization Procedure for Master Mode

    My feeling is that when you start the DMA it is detecting a flag in McBSP that is taking as it has received data. So make sure you reset McBSP when you have it disabled, then configure DMA and then enable the McBSP port.

    Can you confirm this is what you are doing?

  • Israel

    I follow the sequence of turning on the McBSP as per the TRM. I have setup the DMA chain and then at the last step I enable the MCBSP (take it out of RESET).

    One update on the progress is that,

    I no longer see the channel swap if I fix the frame sycn polarity to Active HIGH during stereo audio capture and playback. If I set that to Active LOW I saw the swap. I am using single phase 32 bit data on McBSP and 32 bit data type in DMA transfer element size. This frame sync polarity is exactly opposite of what I2S spec specifies.

    But however, if I have to do mono capture, I have to set the frame sycn polarity to Active LOW during stereo audio capture and playback. This is inline with the I2S spec recommendation.

    Can you explain why the frame sync polarity has to be changed for stereo audio alone to avoid channel swap?

    -sathiya

  • HI Sathiya,

    I haven't notice that you are using clock polarity to Rising in RX and Falling in TX, you should swap that in order to send the data in clock rising edge and receive in the clocl falling edge. It makes sense?

    Let me know what is the behavior after that.

  • Hi Sathiya,

    Frame Sync is a pulse used to synchronise the master and slave, it has to be configured to HIGH because that means that when this pin goes to low the data transmission will start. So the first channel data is sent when this pin is low and second when high for stereo, and for mono data is sent when low only.

    As conclusion, this hast to be configured as active-high frame-sync always for I2S protocol.

  • From what I understood I summarized below. Please confirm.

    "Frame Sync Polarity Active HIGH - means - when the pulse on the frame sync pin goes low, the data transmission will start. Hence first channel is sent here. and Second channel data is sent when the pin goes high.

    Frame Sync Polarity Active LOW - means - when the pulse on the frame sync pin goes high, the data transmission will start."

    I am not a hardware engineer, but it seems counter-intutive to think that Frame sycn Polarity active high setting would mean the pin being low. Why is that? Is this documented in TRM of OMAP McBSP spec?

    On a related note, I understand this setting has to be consistent from Mono and Stereo capture/playback. But as I observed and indicated couple of responses back, I had to set to Active LOW for Mono operation. If I do Active HIGH I get nothing. Why could that happen?

    -sathiya

  • Hi Sathiya,

    Let me put it in this way, the frame sync you select is the level that master will use to tell the slave that it is going to send a frame, so if you set a frame sync pulse high it is saying the slave to hold for a new frame meanwhile the pin is high. Once you change the level you are already in sync, so you can start the transmission, does it makes sense?

    About the problem in mono I am not sure if your config is correct, can you share it?. Also if you want to see some examples for both cases you can take a look at the TRM in McBSP chapter and look for Frame Phase (Dual-Phase Frame I2S Support) section, there it explains both cases with some values and waveforms.