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 Slave configuration

Other Parts Discussed in Thread: AM3359

Hi Sitara Champs!

I am quite new to McASP and sound driver development, and was hoping for some guidance to enable custom functionality.

Background

I am attempting to utilize the McASP for sending data out from an AM335x to a CPLD using gstreamer or other userspace audio application. The specific hardware configuration is different from the EVM examples in that there is no high-speed clock present, only a bit clock and frame sync being sourced externally by the CPLD to the Sitara. I was able to find quite a few posts and references to sourcing clocks to the McASP externally, but I was not able to find one with this particular configuration..

Goal

Drive a single channel of data from the McASP of the AM335x device to a CPLD with the CPLD providing bit clock and frame sync to the McASP of the AM335x utilizing gstreamer or similar userspace application.

Issue

Present analysis of the existing audio and McASP Linux drivers/examples (sound/soc/davinci/davinci-evm.c and davinci-mcasp.c) appears to indicate that an external or internal high frequency clock is required for the McASP and audio drivers to function properly. Modifications to the driver appear to be required to operate solely from an external bit clock and frame sync.

Questions

  • Is the sysclk within the davinci-evm.c sound file referencing the high-speed (AHCLK) clock of the McASP peripheral?

  • Is it possible to drive only a bit clock and frame sync to the McASP and utilize the existing audio Linux drivers and userspace applications (gstreamer) or are significant changes needed to enable this setup?

  • Can the sound driver operate without a high-speed clock source (sysclk) present on the McASP/Sitara?

Steps Taken

  • The Processor SDK Linux Audio page was utilized to perform the Audio DAC Example and to reference the Audio Porting Guide to gain some familiarity with the driver structure.

  • The existing driver configuration for BeagleBone Black (TDA998x) was used as a basis to configure the McASP being driven by the internal clock (26MHz) on the high-frequency transmit clock (AHCLKX), being divided down for the bit clock (ACLKX), and generating the frame sync internally as well. devicetree changes were made for pinmuxing.

    • Gstreamer was then utilized to feed data to the sound driver with data being shown on the serializer pin (axr1) of the custom hardware using an oscilloscope.

  • Changes were made to the example snd_soc_dai_link’s .dai_fmt within evm_dai_tda998x_hdmi to indicate codec bit clock master and code frame sync master for configuring the McASP as receiving both the bit clock and frame sync from the CPLD (SND_SOC_DAIFMT_CBM_CFM).

    • These changes resulted in no data being present on the serializer

  • After removing the above changes, changes were made to the evm_tda998x_hw_params function instead to manually set the bclk_freq and sysclk (high-speed clock) variables to match those of the CPLD inputs while still operating the McASP off internal clocks.

    • Any changes made to the bclk_freq or sysclk values resulted in no data being present on the serializer.

  • Having both changes present at the same time (codec bit clock/frame sync master and adjusting sysclk/bclk_freq) also resulted in no data being present on the serializer.

  • Current estimates are that since the CPLD is providing the bit clock instead of the high-speed (sysclk) this approach will not operate correctly with the current Linux driver and modifications are necessary.

Any assistance or guidance is greatly appreciated!

Best Regards,

Mark-

  • Hi Mark,

    I will forward this to the SW team.
  • Hello Mark,

    I am discussing your questions with audio SW experts. 

    Take a look on the answers on your questions:

    Q1: Is the sysclk within the davinci-evm.c sound file referencing the high-speed (AHCLK) clock of the McASP peripheral?

    1. sysclk in the davinci-evm.c driver file does refer to the AHCLK.  It’s passed to the driver so the BCLK divider can be properly calculated

      #Q2: Is it possible to drive only a bit clock and frame sync to the McASP and utilize the existing audio Linux drivers and userspace applications (gstreamer) or are significant changes needed to enable this setup?

      I’m afraid I don’t understand the question.  Could we get more details? If possible, what usecase they’re trying to enable.

      #Q3: Can the sound driver operate without a high-speed clock source (sysclk) present on the McASP/Sitara?

      Yes, it’s possible to operate without the high-speed clock, only if McASP is slave (i.e. analog audio codec provides the BCLK)

    1. In the diagram below, the external ACLKX is the bit clock that would be used if AHCLKX is not wanted.

    Best regards,

    Yanko

  • Hi Yanko,

    Thank you for your responses. I am Mark's customer and need help with the issue presented my Mark. I would like to give my inputs/more-details regarding question#2(Q2) as you requested:

    Use case we are trying to enable:

    We want to Stream audio data to a "Codec" (in reality a CPLD but we can treat it as a codec because it is dedicated to process audio data). The Codec is connected to McASP and only provides Bit clock and Frame Sync clk to the McASP. There is no sysclk that this external Codec provide to the McASP. However, our Sitara processor (am3359) still have its internal sysclk of 24MHz, but we are unsure, if in our use case (CodecBitMaster, CodecFrameMaster), this internal sysclk should be used and how!!!

    Q2 was about what kind of changes we need to add in davinci interface to enable such use case. Based on following wiki example:

    http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_DAC_Example

     

    Following are new changes we made to davinci-evm.c:

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    static int cpld_hw_params(struct snd_pcm_substream *substream,

    struct snd_pcm_hw_params *params)

    {

    struct snd_soc_pcm_runtime *rtd = substream->private_data;

    struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

    struct snd_soc_codec *codec = rtd->codec;

    struct snd_soc_card *soc_card = codec->card;

    struct platform_device *pdev = to_platform_device(soc_card->dev);

     unsigned int bclk_freq = evm_get_bclk(params);

    unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)

    snd_soc_card_get_drvdata(soc_card))->sysclk;

    int ret;

    ret = snd_soc_dai_set_clkdiv(cpu_dai, 1, sysclk/bclk_freq); /*ToDo: Not sure if this is needed since CPLD does not provide a sysclk. but only provides Bit clk and frame sync clk to McASP */

    if (ret < 0) {

    dev_err(&pdev->dev, "can't set CPU DAI clock divider %d\n", ret);

    return ret;

    }

     

    ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_IN);  /*ToDo: Not sure if this is needed since CPLD does not provide a sysclk. but only provides Bit clk and frame sync clk to McASP */

     

    if (ret < 0)

    {

    printk("sdn_soc_dai_set_sysclk failed!\n");

    return ret;

    }

     return ret;

    }

    static struct snd_soc_ops cpld_ops = {

    .startup = evm_startup, //evm_startup is generic and can be use here

    .shutdown = evm_shutdown, //evm_shutdown is generic and can be use here

    .hw_params = cpld_hw_params, //specific to the cpld

    };

    static struct snd_soc_dai_link evm_dai_cpld = {
     .name  = "CPLDG",
     .stream_name = "Playback", //This comes from the CPLD driver created in /sound/soc/codec/cpld.c
     .codec_dai_name = "cpld-audio", //This comes from the cpld driver created in /sound/soc/codec/cpld.c
     .ops            = &cpld_ops, 

     .dai_fmt  = (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_DSP_B |
                 SND_SOC_DAIFMT_IB_NF),
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    As you can see in the provided changes we added to sound/soc/davinci/davinci-evm.c, we are unsure on how to handle sysclk.

    Note that we have set dai_fmt with SND_SOC_DAIFMT_CBM_CFM to enable Codec as Bit clk Master and Frame sync clk Master.

    Any guidance on how to handle sysclk and is other changes needed in davinci, mcasp, etc..., interfaces to achieve this use case?

  • I'm admittedly not very familiar with the TI ALSA driver but wanted to provide a few hardware centric details.

    1. There is no requirement to provide AHCLKX.  Ultimately that's just an option to derive ACLKX, but as Yanko showed in the marked up diagram, it is possible to directly provide ACLKX from the pin, which is what you will need to do.  This is programmed by configuring ACLKXCTL[CLKXM]=0.  The CLKXM bit is what controls the mux shown in Yanko's diagram.
    2. There's a similar concept that applies to the frame sync.  Please see Figure 22-19 "Frame Sync Generator Block Diagram" in the AM335x TRM.  If you wish the frame sync to be provided from the external device as an input to the AM335x then you must program AFSXCTL[FSXM]=0.
    3. If ACLKX and AFSX are inputs to the McASP, make sure that you configure PDIR[ACLKX]=0 and PDIR[AFSX]=0.
    4. Make sure that the pin mux registers for ACLKX and AFSX have both configured bit 5 (rxactive) to 1 (enabled).  Otherwise, the signal will be unable to propagate from the pad to the mcasp.

    As a starting point I recommend looking at each of the registers I mentioned above using devmem2.  That should help you to see which registers are configured incorrectly and then perhaps you can search in the code for areas pertaining that register to better understand what you need to do.

  • Hello PEleph,

    The completed answer on your questions is:

    The sysclk rate is irrelevant when McASP is in slave mode.  Customer could just set it to 0. Register - ACLKXCTL[5] CLKXM - Transmit bit clock source bit.

    0x0 = External transmit clock source from ACLKX pin.

    The way the machine driver indicates that McASP is to be slave (hence the codec is master) is through the SND_SOC_DAIFMT_CBM_CFM format flag, which the customer appears to be already doing properly.

    Their call to set clock direction is correct:

    ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_IN);

    The bit clock divider call is not relevant when McASP is in slave mode, please refer to the diagram I sent in my previous email:

    ret = snd_soc_dai_set_clkdiv(cpu_dai, 1, sysclk/bclk_freq);

    See register ACLKXCTL[0:4] CLKXDIV - Transmit bit clock divide ratio bits determine the divide-down ratio from AHCLKX to ACLKX. 0x0 = Divide-by-1.

    In conclusion - It seems to me that the customer settings are correct.

    Best regards,

    Yanko

  • In reply to Brad's inputs, I have checked those registers values and they are all 0s while I am running the gstreamer app to send data to the McASP port.
    I am using mcasp1 and data pin axr0.

    For AFSXCTL (offset=ACh) Transmit Frame Sync Control Register
    root@am335x-evm:~# devmem2 0x4803C0AC
    /dev/mem opened.
    Memory mapped at address 0xb6f95000.
    Read at address 0x4803C0AC (0xb6f950ac): 0x00000110

    For ACLKXCTL (offset=B0h) Transmit Clock Control Register
    root@am335x-evm:~# devmem2 0x4803C0B0
    /dev/mem opened.
    Memory mapped at address 0xb6f3f000.
    Read at address 0x4803C0B0 (0xb6f3f0b0): 0x00000000


    Obviously, from ACKXCTL it seems that bit 5 (CLKXM) is not set active to 1, so, that is a concern!
  • PEleph said:
    For ACLKXCTL (offset=B0h) Transmit Clock Control Register
    root@am335x-evm:~# devmem2 0x4803C0B0
    /dev/mem opened.
    Memory mapped at address 0xb6f3f000.
    Read at address 0x4803C0B0 (0xb6f3f0b0): 0x00000000


    Obviously, from ACKXCTL it seems that bit 5 (CLKXM) is not set active to 1, so, that is a concern!

    There's no concern here.  Bit 5 is supposed to be 0.  That corresponds to external transmit clock source.

  • I wanted to update this thread to note that the root cause of things not working was eventually determined to be that the frame sync was not meeting the setup/hold times of the data manual and so it was not being "seen" by the McASP. After a small adjustment it looks to be working well now.
  • Hi Yanko,

    Base on your comments, If am335x McASP is in master mode, it need to transmit clock to sound codec via AHCLKX pin.  ACLKX pin is useless at this status.

    Is that true?

    Thanks!
    Regards,
    Luther Lu

  • so what was that "small adjustment"?  yes i know this is a 2 year old post

  • It was adjusting the timings to meet the data sheet requirements.  It involved a configuration change to the external device to alter its output waveform.  I forget if we changed the clock edge, extended the frame sync, etc.