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 Input Issue

Hi,

I am trying to configure McASP0 on a C6746 device in 16 channel TDM mode. I am currently just trying to configure audio input. I am using the BIOS PSP McASP driver for this (iospsp_03_00_01_00).

This release is targeted at the C6748, but I believe that this should port to the C6746 without any software changes needed?

I am receiving digital audio directly to the McASP, no codec involved. 

I used the BIOS PSP sample application as a starting point, having removed the AIC31 and I2s related parts of this application. When I run the application, I have stepped through all of the GIO and McASP initialisation, all of which succeeds and all McASP registers look correct. 

Currently, what happens when I run the application is that it hangs at this call within the audio loop:

/* Reclaim full buffer from the input stream */
status = GIO_reclaim(inStream, (Ptr *)&rcv, NULL, NULL);

I believe that this is happening because the RDATA flag in the RSTAT register is not toggling. I have placed breakpoints in all receive related functions in the McASP driver code; specifically, I should see this function being called: Mcasp_localEdmaCallback(), but I never hit this function and am stuck in the idle loop.

I can see that on the PDIN register, expected activity on all of the clock pins and serializer 0 data pin (where I am trying to read 16 channels of audio in). 

I have also tried to check the RBUF0 register to see if data is getting this far, but I never see anything here. I have a Logic PD experimenter EVM, so I have run the application in burst mode, but I could not see anything in RBUF in CCS while running this (despite seeing audio in the buffers and hearing on output), so I can't be sure that audio is not getting from the shift register into RBUF on my C6746 setup.

I am have spent some time at this and, currently, cannot think how to debug the issue any further. Is there a way of checking if data is being clocked into the serializer shift register and/or receive buffer (RBUF)?

Any ideas audio data would not get clocked into RBUF?

Thanks

Brian

  • Hi,

    Thanks for your post.

    First, could you please clarify whether McASP is configured as TDM or burst transfer modes since in burst transfer mode, the frame sync generation is not periodic or time driven as like in TDM mode instead it is data driven and the control registers must be configured accordingly for burst transfer mode and there are burst mode specific bit fields which needs to be cleared as below:

    Clear RMOD/XMOD bits to 0 to indicate burst mode. Clear FRWID/FXWID bits to 0 for single bit frame sync duration

    For more details on burst and TDM transfer mode and how control registers are configured accordingly for the same, kindly refer sections 23.0.21.2.1 & 23.0.21.2.2

    Also, i wonder that you should configure McASP in Digital Audio Interface Transmit (DIT) Transfer Mode since you mentioned above, having removed the AIC31 and I2s related parts of the application code and if so, the McASP in DIT mode supports transmission of audio data in the S/PDIF, AES-3, or IEC-60958 format. These formats are designed to carry audio data between different systems through an optical or coaxial cable. The DIT mode only applies to serializers configured as transmitters, not receivers.

    Basically, the McASP operation in DIT mode is basically identical to the 2 time slot TDM mode, but the data transmitted is output as a biphase mark encoded bit stream, with preamble, channel status, user data, validity, and parity automatically stuffed into the bit stream by the McASP.

    The transmit TDM time slot register (XTDM) should be programmed to all 1s during DIT mode. TDM functionality is not supported in DIT mode, except that the TDM slot counter counts the DIT subframes. If the McASP is configured to transmit in the DIT mode on more than one serial data pin, the bit streams on all pins will be synchronized

    For more details on transmit DIT encoding, transmit DIT clock and framesync generation, control register configuration required for DIT mode, kindly refer sections 23.0.21.2.3.1 and 23.0.21.2.3.2 from the TRM below:

    http://www.ti.com.cn/cn/lit/ug/spruh79b/spruh79b.pdf

    Thanks & registers,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.

    -------------------------------------------------------------------------------------------------------

  • Hi Sivaraj,

    Thanks you for taking the time to respond to my post, but unfortunately none of your response deals with my queries. 

    I said that I am working in 16 channel TDM mode, not burst mode or DIT mode. I have gone through the TMS320C6000 DSP Multichannel Audio Serial Port (McASP) Reference Guide in detail in order to configure the registers correctly for 16 channel TDM. I am working off an external frame sync clock and a bit clock. These have been verified on separate audio peripherals (DACs, etc), so the clocks have been verified.

    My issue is that I can't see audio entering the serializer. Is it possible to view the serializer shift register? What could be the cause of audio not getting clocked into RBUF?

    Here are my register settings for McASP receive:

    Mcasp_HwSetupData mcaspRcvSetup = {
            /* .rmask    = */ 0xFFFFFFFF, /* All the data bits are to be used     */
            /* .rfmt     = */ 0x000080F0, /*
                                           * 0 bit delay from framsync
                                           * MSB first
                                           * No extra bit padding
                                           * Padding bit (ignore)
                                           * slot Size is 32
                                           * Reads from DMA port
                                           * NO rotation
                                           */
            /* .afsrctl  = */ 0x00000810, /* burst mode,
                                           * Frame sync is one bit
                                           * Rising edge is start of frame
                                           * externally generated frame sync
                                           */
            /* .rtdm     = */ 0x0000FFFF, /* slot 1 is active (DSP)               */
            /* .rintctl  = */ 0x000000AE, /* sync error and overrun error         */
            /* .rstat    = */ 0x000001FF, /* reset any existing status bits       */
            /* .revtctl  = */ 0x00000000, /* DMA request is enabled or disabled   */
            {
                 /* .aclkrctl  = */ 0x00000000,
                 /* .ahclkrctl = */ 0x00000000,
                 /* .rclkchk   = */ 0x00000000
            }
    } ;
    
    Mcasp_ChanParams  mcasp_chanparam[1]=
    {
        {
            0x0001,                    /* number of serialisers      */
            {Mcasp_SerializerNum_0, }, /* serialiser index           */
            &mcaspRcvSetup,
            TRUE,
            Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */
            Mcasp_WordLength_32,
            NULL,
            0,
            NULL,
            NULL,
            16u,                        /* number of TDM channels      */
            Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
            TRUE,
            TRUE
        }
    }

    Thanks

    Brian

  • Hi,

    To try to be as specific as possible about my issue, maybe somebody can answer this question. What are the minimum requirements for data to get shifted into the receive buffer (RBUF) of a serializer? From what I understand, serializers operate off the bit clock (ACLKX/ACLKR) and no other clock. This part of the McASP user manual suggests this:

    When configured as a receiver, the serializer shifts in data from the AXR[n] pin.

    The serializer is clocked from the transmit/receive section clock (ACLKX/ACLKR) if configured to transmit/receive respectively.

     

    So if I have a data signal and a bit clock signal (external ACLKR), I should see samples getting shifted into RBUF? 

    How can I check this (if audio samples are actually being shifted into RBUF) seeing as pausing in CCS and viewing RBUF registers does not seem to work; nothing in RBUF even when I've run on a separate setup with audio passing through.

    What could be the cause of audio not being shifted via shift register(s) into serializer receive buffer(s) (RBUFn)?

    Thanks

    Brian

     

  • Hi,

    Thanks for your update.

    Did you configure the McASP Rx. in active  timeslots? Usually, no transfer between the RBUF and XRSR registers in the serializer happens only during inactive rx. timeslots. I mean,  if the McASP doesn't participate in active rx. time slots configured (receive bit would be inactive), the transfer wouldn't occur between RBUF and XRSR. So, the minimum requirement would be for the transfer to happen between XRSR to RBUF is that the McASP should participate in active receive time slots configured in the code. Kindly validate this.

    Next, did you check the RDATA flag set in RSTAT which reflects the status of RBUF register? Kindly clear the RDATA flag bit if it is written as 1 or when all the serializers configured as receivers are read.

    If it is configured for RBUF data by DMA read, Did you see any DMA event AREVT whenever RDATA is set indicates the notification to the DMA of the RBUF ready status? Did you enable any RDATA interrupt in RINTCTL register? If so, Did you see any interrupt ARINT triggered for RBUF data ready for DMA read?

    Did you see any ROVRN flag set by the receiver state machine which indicate the RBUF data has not yet been read by the DMA or the DSP? But still if this is the case too, the individual serializer would overwrite the data in RBUF register and continue shifting it to receive format unit to DSP.

    Thanks & registers,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.

    -------------------------------------------------------------------------------------------------------

  • Hi Sivaraj,

    Thank you for your detailed response, these suggestions deal directly with my issue. 

    My input signal is 16 channel TDM, with signal only on the last 2 slots (14 and 15). But I have configured all of the 16 slots as active. I tried disabling the first 14 slots and enabling the last 2 slots, but unfortunately this didn't seem to make a difference. 

    I think that I need to poll the RSTAT/RBUF register in software somewhere as changes are very difficult to see in the register view in CCS because they happen so fast. All of the DMA driver functions after initialisation are interrupt driven, so I am trying to think of the best place to poll registers. Alternatively, I could configure an interrupt to monitor these registers. There must be an interrupt defined in the driver to monitor the RDATA bit? There is a function defined in Mcasp_ioctl.c which looks like it should do this, see here:

    /**
     *  \brief  This function is used to get the value of various parameters of the
     *          McASP instance. The value returned depends on the query passed.
     *
     *  \param  hMcasp    [IN]    Handle to mcasp H/W information structure
     *  \param  myQuery   [IN]    Query requested by application
     *  \param  response  [IN]    Pointer to buffer to return the data requested by
     *                            the query passed
     *  \param  eb        [IN]    pointer to error block
     *
     *  \return
     *          IOM_COMPLETED  - Successful completion of the query
     *          IOM error code - in case of error.
     *
     * \entry   hMcasp      should be non NULL and valid pointer
     *          myQuery     should be a valid value
     *          response    shluld be non NULL and valid pointer
     *
     * \leave   Not implemented
     */
    static Int32 mcaspGetHwStatus(Mcasp_HwHandle        hMcasp,
                                  Mcasp_HwStatusQuery   myQuery,
                                  Void                 *const response)
    {
        Int32                status      = IOM_COMPLETED;
        Mcasp_SerQuery     *serQuery     = NULL;
        Mcasp_SerModeQuery *serModeQuery = NULL;
    
    
        assert((NULL != hMcasp) && (NULL != response));
    
        switch (myQuery)
        {
            /* Return current transmit slot being transmitted                 */
            case Mcasp_HwStatusQuery_CURRENT_XSLOT:
                *((Uint16 *)response) =
                    (Uint16)(((hMcasp->regs)->XSLOT
                    & CSL_MCASP_XSLOT_XSLOTCNT_MASK)
                    >> CSL_MCASP_XSLOT_XSLOTCNT_SHIFT);
                break;
    
            /* Return current receive slot being received                     */
            case Mcasp_HwStatusQuery_CURRENT_RSLOT:
                *((Uint16 *)response) =
                    (Uint16)(((hMcasp->regs)->RSLOT
                    & CSL_MCASP_RSLOT_RSLOTCNT_MASK)
                    >> CSL_MCASP_RSLOT_RSLOTCNT_SHIFT);
                break;
    
            /* Return transmit error status bit                               */
            case Mcasp_HwStatusQuery_XSTAT_XERR:
                *(Bool *)response =
                    (Bool)(((hMcasp->regs)->XSTAT & CSL_MCASP_XSTAT_XERR_MASK)
                    >> CSL_MCASP_XSTAT_XERR_SHIFT);
                break;
    
            /* Return transmit clock failure flag status                      */
            case Mcasp_HwStatusQuery_XSTAT_XCLKFAIL:
                *(Bool *)response =
                    (Bool)(((hMcasp->regs)->XSTAT
                     & CSL_MCASP_XSTAT_XCKFAIL_MASK)
                     >> CSL_MCASP_XSTAT_XCKFAIL_SHIFT);
                break;
    
            /* Return unexpected transmit frame sync flag status              */
            case Mcasp_HwStatusQuery_XSTAT_XSYNCERR:
                *(Bool *)response =
                    (Bool)(((hMcasp->regs)->XSTAT
                    & CSL_MCASP_XSTAT_XSYNCERR_MASK)
                    >> CSL_MCASP_XSTAT_XSYNCERR_SHIFT);
                break;
    
            /* Return transmit underrun flag status                           */
            case Mcasp_HwStatusQuery_XSTAT_XUNDRN:
                *((Bool *)response) =
                    (Bool)(((hMcasp->regs)->XSTAT & CSL_MCASP_XSTAT_XUNDRN_MASK)
                    >> CSL_MCASP_XSTAT_XUNDRN_SHIFT);
                break;
    
            /* Return transmit data ready flag status                         */
            case Mcasp_HwStatusQuery_XSTAT_XDATA:
                (*(Bool *)response) =
                    (Bool)(((hMcasp->regs)->XSTAT & CSL_MCASP_XSTAT_XDATA_MASK)
                    >> CSL_MCASP_XSTAT_XDATA_SHIFT);
                break;
    
            /* Return receive error status bit                                */
            case Mcasp_HwStatusQuery_RSTAT_RERR:
                *((Bool *)response) =
                    (Bool)(((hMcasp->regs)->RSTAT & CSL_MCASP_RSTAT_RERR_MASK)
                    >> CSL_MCASP_RSTAT_RERR_SHIFT);
                break;
    
            /* Return receive clk failure flag status                         */
            case Mcasp_HwStatusQuery_RSTAT_RCLKFAIL:
                *((Bool *)response) =
                    (Bool)(((hMcasp->regs)->RSTAT
                    & CSL_MCASP_RSTAT_RCKFAIL_MASK)
                    >> CSL_MCASP_RSTAT_RCKFAIL_SHIFT);
                break;
    
            /* Return unexpected receive frame sync flag status               */
            case Mcasp_HwStatusQuery_RSTAT_RSYNCERR:
                *((Bool *)response) =
                    (Bool)(((hMcasp->regs)->RSTAT
                    & CSL_MCASP_RSTAT_RSYNCERR_MASK)
                    >> CSL_MCASP_RSTAT_RSYNCERR_SHIFT);
                break;
    
            /* Return receive overrun flag status                             */
            case Mcasp_HwStatusQuery_RSTAT_ROVRN:
                *((Bool *)response) =
                    (Bool)(((hMcasp->regs)->RSTAT & CSL_MCASP_RSTAT_ROVRN_MASK)
                    >> CSL_MCASP_RSTAT_ROVRN_SHIFT);
                break;
            /* Return receive data ready flag status                          */
            case Mcasp_HwStatusQuery_RSTAT_RDATA:
                *((Bool *)response) =
                (Bool)(((hMcasp->regs)->RSTAT & CSL_MCASP_RSTAT_RDATA_MASK)
                >> CSL_MCASP_RSTAT_RDATA_SHIFT);
                break;
    
            /* Return status whether rrdy is set or not                       */
            case Mcasp_HwStatusQuery_SRCTL_RRDY:
                {
                    serQuery = (Mcasp_SerQuery *)response;
                    mcaspGetSerRcvReady(
                                 hMcasp,
                                 (Bool *)&(serQuery->serStatus),
                                 serQuery->serNum);
                }
                break;
    
            /* Return status whether xrdy is set or not                       */
            case Mcasp_HwStatusQuery_SRCTL_XRDY:
                {
                    serQuery = (Mcasp_SerQuery *)response;
                    mcaspGetSerXmtReady(
                                hMcasp,
                                (Bool *)&(serQuery->serStatus),
                                serQuery->serNum);
                }
                break;
           /* Return status whether serializer is configured as TX/RX/FREE    */
           case Mcasp_HwStatusQuery_SRCTL_SRMOD:
                {
                    serModeQuery = (Mcasp_SerModeQuery *)response;
                    mcaspGetSerMode(hMcasp,
                                    &(serModeQuery->serMode),
                                    serModeQuery->serNum);
                    break;
                }
    
            /* Return the value of XSTAT register                             */
            case Mcasp_HwStatusQuery_XSTAT:
                *((Uint16 *)response) = (Uint16) (hMcasp->regs)->XSTAT;
                break;
    
            /* Return the value of RSTAT register                             */
            case Mcasp_HwStatusQuery_RSTAT:
                *((Uint16 *)response) = (Uint16) (hMcasp->regs)->RSTAT;
                break;
    
            /* Return the XSMRST and XFRST field values GBLCTL register       */
            case Mcasp_HwStatusQuery_SM_FS_XMT:
                *((Uint8 *)response) = mcaspGetSmFsXmt(hMcasp);
                break;
    
            /* Return the RSMRST and RFRST field values GBLCTL register       */
            case Mcasp_HwStatusQuery_SM_FS_RCV:
                *((Uint8 *)response) = mcaspGetSmFsRcv(hMcasp);
                break;
    
            /* Return status of DITEN bit in DITCTL register                  */
            case Mcasp_HwStatusQuery_DIT_MODE:
                *((Bool *)response) =
                    (Bool)(((hMcasp->regs)->DITCTL
                    & CSL_MCASP_DITCTL_DITEN_MASK)
                    >> CSL_MCASP_DITCTL_DITEN_SHIFT);
                break;
    
            case Mcasp_HwStatusQuery_AMUTE:
                *((Uint16 *)response) = (Uint16)(hMcasp->regs)->AMUTE;
                break;
    
            default:
                status = IOM_EBADARGS;
                break;
        }
    
        return status;
    }

    When I run the sample audio application though on the Logic PD experimenter dev kit (which works and passes audio in burst + DMA mode), this function is never hit. Maybe this functionality is not used? Could you suggest a method of monitoring registers that would not disrupt normal operation?

    Many thanks

    Brian

  • *second paragraph, second line should be:

    All of the McASP driver functions after initialisation are interrupt driven
  • Hi Sivaraj,

    I found an issue with the McASP driver and my application which was preventing samples being clocked in. There is a function in Mcasp_ioctl.c which sets the master clock to master and it was being configured in synchronous mode, so McASP receive serializer was being clocked by the internal transmit clock, which was not configured. I changed this, so the transmit channel is now configured properly and receive serializer is being clocked by the external clock.

    I set the RDATA bit in RINTCTL, and the McASP receive interrupt is now triggered. I have another issue now though, where the EDMA callback is not triggered. I have set RNUMEVT to 8 words in RFIFO, so an AREVT interrupt should be generated when 8 words are in the RFIFO, I believe. The RFIFO just fills up to the maximum capacity of 64 words though and no AREVT interrupt is generated. At least, the EDMA callback function is never triggered.

    Can you think what could be the cause of this?

    Thanks

    Brian

  • * There is a function in Mcasp_ioctl.c which sets the transmit clock to master