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.

AUDK2G: Example use case of using two inputs to generate one output

Part Number: AUDK2G

Hello,

I'm combing through the AUDK2G audioAnalogLoopbackTest code to see if I can accomplish a specific use case, but so far cannot figure out how to accomplish this.

Basically, I would like to take two input channels, specifically ADC0 left, and ADC0 right, perform an operation on the two channels, and supply one output to DAC0 left.  For example, if I want to take the average of the two input channels ((channelInLeft[i] + channelInRight[i]) / 2 = channelOutLeft[i]), and supply that result to the output of DAC0, where/how would I begin doing this?  Is all the data from all the channels contained in txBuf/rxBuf?  How can I access specific channel frames?  Or do I have to "route" the channels somewhere else during initialization?

A simple example of something like this would provide answers to a few different questions I have regarding data manipulation in the echo_task call.

If there's documentation that I'm missing, let me know.  I'm constantly looking, but there's so much it's easy to miss the important parts.

--

Justyn

  • Justyn,

    I don`t think we have an example that can perform something similar to what you are looking for but we are working on some TI Design that will release by end of 1Q17 or early 2Q17 that will take multiple analog inputs and output single stereo channel out.

    what you are trying to achieve can be done using the existing MCASP driver design. Please look at the design document MCASP_LLD_SDS.pdf under the path pdk_k2g_1_x_x\packages\ti\drv\mcasp\docs . 

    Set the RX_NUM_SERIALIZER to 2 and TX_NUM_SERIALIZER to 1 and  to get input from multiple serializer you can setup the MCASP_channel params as shown below:

    /* McAsp channel parameters for receive                      */
    Mcasp_ChanParams  mcaspRxChanParam =
    {
    	0x0002,                    /* number of serializers      */
    	{Mcasp_SerializerNum_0,
    	 Mcasp_SerializerNum_1,
    	 }, /* serializer index           */
    	&mcaspRcvSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */
    	Mcasp_WordLength_32,
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	///Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1,
    	Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2,
    	TRUE,
    	TRUE
    };
    
    
    /* McAsp channel parameters for transmit             */
    Mcasp_ChanParams  mcaspTxChanParam =
    {
    	0x0001,                   /* number of serializers       */
    	{Mcasp_SerializerNum_2,}, /* serializer index for DAC0    */
    	&mcaspXmtSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,
    	Mcasp_WordLength_32,      /* word width                  */
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
    	///Mcasp_BufferFormat_1SER_MULTISLOT_NON_INTERLEAVED,
    	TRUE,
    	TRUE
    };
    

    The data will then be available from Multiple serializers in the TxBuff in interleaved format S1_L, S2_L, S1_R, S2_R.

    NoTe: MAke sure you have allocated RXBUF is of size (BUFSIZE * RX_NUM_SERIALIZER).

    Hope this helps.

    Regards,

    Rahul

  • Thank you for the additional information.  Just from the little snippet of code you provided, I can see better what's going on.

    I've made these changes and played with both interleaved and non-interleaved data, but I was not able to get the audio to work.  At best, I hear ringing with faint, distorted sounds.  I'm sure it's because of the way I'm copying the data over, but I can sort-of verify that the correct channels are working.

    I was wondering if you could provide an example of getting channel data from NON-interleaved data.  In the past with other audio applications, you can choose between interleaved data, and non interleaved data.  With non-interleaved data, you simple access an element of the input/output buffers to get the channel (or in this case, serializer and channel) data.

    So, for example, if I configure the McASP channel parameters as such:

    /* McAsp channel parameters for receive                      */
    Mcasp_ChanParams  mcaspRxChanParam =
    {
    	0x0002,                    /* number of serializers      */
    	{Mcasp_SerializerNum_0,
    	 Mcasp_SerializerNum_1}, /* serializer index           */
    	&mcaspRcvSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */
    	Mcasp_WordLength_32,
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2,
    	TRUE,
    	TRUE
    };
    
    /* McAsp channel parameters for transmit - DAC0              */
    Mcasp_ChanParams  mcaspTx0ChanParam =
    {
    	0x0001,                   /* number of serializers       */
    	{Mcasp_SerializerNum_0}, /* serializer index for DAC0    */
    	&mcaspXmtSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,
    	Mcasp_WordLength_32,      /* word width                  */
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	Mcasp_BufferFormat_1SER_MULTISLOT_NON_INTERLEAVED,
    	TRUE,
    	TRUE
    };

    Can I access individual channels/serializers from the rxBuf?  And if yes, how can I do this?

    In previous audio project, for example, using the Portaudio framework, you can access different channels of a buffer by simply accessing one of its elements, instead of having to de-interleave every sample.  Eg:

    float *in_left_front = ((float **) inputBuffer)[0];
    float *in_right_front = ((float **) inputBuffer)[1];
    float *in_left_rear = ((float **) inputBuffer)[2];
    float *in_right_rear = ((float **) inputBuffer)[3];
    

    Is there something similar I can do here?

    At the end of the day, I want to drop a function in that does the following:

    average_audio(ser_1_left, ser_1_right, ser_2_left, ser_2_right, output_left, output_right, size) {
        unsigned int i;
        for (i = 0; i < size, i++) {
            output_left[i] = (ser_1_left[i] + ser_2_left[i])/2;
            output_right[i] = (ser_1_right[i] + ser_2_right[i])/2;
        }
    }

    I have configured the channels correctly, from what I can tell.  I think a non-interleaved data format is what I want, and I have the txBuf and rxBuf.

    Since rxBuf contains all the audio data I need, how can I get those 4 channels of audio? (ser_1_left, ser_1_right, ser_2_left, ser_2_right)?  And how can I get the two channels of output output_left, output_right?

    This is pretty much the last link I need right now.  I would spend more time on this, but we're actively developing complex algorithms to drop onto the board all the time, and the more time I spend trying to figure out all the TI nuance stuff, the less time I have to complete porting these algorithms over.

    Thank you, once again,

    Justyn

  • Hi, Rahul.

    I'm trying to go through the documentation for all the different interleave/non-interleaved modes, ie

    /**
     * \brief Enum to specify the supported buffer formats.
     *
     * Interleaved and non-interleaved is standard format, this enumeration
     * captures the standard and custom data formats.
     */
    typedef enum Mcasp_BufferFormat_e
    {
        /* This mode is used for buffer containing the data in continous      *
         * memory locations where each sample is  "wordWidth" long. This      *
         * format is supported for following configurations                   *
         *
         * Single serializer in DSP mode.DIT mode also can use this format    *
         *                                                                    *
         * Note : interleaved and non interleaved does not apply for this     *
         * buffer format                                                      */
        Mcasp_BufferFormat_1SER_1SLOT,
    
        /* This is used for transfer of data on a single serializer with      *
         * multiple slots.please note that the slot data is not interleaved   *
         * in this format.                                                    *
         *                                                                    *
         * TDM with single serializer and slots > 1 uses this format.DIT can  *
         * also use this format                                               */
        Mcasp_BufferFormat_1SER_MULTISLOT_NON_INTERLEAVED,
        /* This is used for transfer of data on a single serializer with      *
         * multiple slots.please note that the slot data is interleaved       *
         * in this format.                                                    *
         *                                                                    *
         * TDM with single serializer and slots > 1 uses this format. DIT     *
         * mode can also be supported here                                    */
        Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
    
        /* This is used for transfer of data on a single slot with  multiple  *
         * serializers enabled.please note that the serializer data is        *
         * interleaved in this format.                                        *
         *                                                                    *
         * DSP and DIT mode with multiple serializer uses this format         */
        Mcasp_BufferFormat_MULTISER_1SLOT_SER_INTERLEAVED,
    
        /* This is used for transfer of data on a single slot with  multiple  *
         * serializers enabled.please note that the serializer data is        *
         * interleaved in this format.                                        *
         *                                                                    *
         * DSP and DIT mode with multiple serializer uses this format         */
        Mcasp_BufferFormat_MULTISER_1SLOT_SER_NON_INTERLEAVED,
    
        /* This is used for transfer of data with  multiple serializers and   *
         * also multiple slots enabled.please note that the serializer data is*
         * interleaved in this format. The slot data is also interleaved      *
         * Refer to the user guide to view the sample data format.            *
         *
         * TDM and DIT mode with multiple serializer and multiple slots uses  *
         * this format                                                        */
        Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1,
    
        /* This is used for transfer of data with  multiple serializers and   *
         * also multiple slots enabled.please note that the serializer data is*
         * NOT interleaved in this format. The slot data is interleaved       *
         * Refer to the user guide to view the sample data format.            *
         *
         * TDM and DIT mode with multiple serializer and multiple slots uses  *
         * this format                                                        */
        Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2
    
        /* we are unable to support this buffer format because the MCASP gives*
         * tx underrun error.
         * When 2 serializers are configured in 2 slot mode each. The MCASP   *
         * even though it receives two 16 bit samples it considers it as only *
         * one 32 bit sample because of which it will always give an underrun *
         * error. Hence this buffer format cannot be supported                *
         * This is used for transfer of data with  multiple serializers and   *
         * also multiple slots enabled.please note that the slot data is      *
         * NOT interleaved in this format. The serializer data is interleaved *
         * Refer to the user guide to view the sample data format.            *
         *
         * TDM and DIT mode with multiple serializer and multiple slots uses  *
         * this format                                                        *
        BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_3,
         */
    }Mcasp_BufferFormat;

    I've been through most of the literature, and can't find a diagram or example of what these different modes mean.

    In the AUDK2G loopback example as well as the MCASP_Audio loopback example, at the heart of the echo_task call, there's just a memcpy.

    You literally couldn't provide less details of how the samples are handled than by using a memcpy.  I would suggest instead of a memcpy, you could have a for loop the shows how to loopback the samples one-by-one.


    But anyway, for now, I'm still lost.  I can't find relevant information, and the code doesn't demonstrate how to deinterleave data.

    Again, ideally, I think I want the data in non-interleaved format.  An example of this would be the MOST helpful for my purposes.

  • There's obviously something I'm missing in the way that samples are interleaved from the serializer when more than one are used.

    When I'm only using one serializer for input and output, I can de-interleave the samples, and route them out as I would expect.  For example, here's the configuration for single-serializer mode:

    /* McAsp channel parameters for receive                      */
    Mcasp_ChanParams  mcaspRxChanParam =
    {
    	0x0001,                    /* number of serializers      */
    	{Mcasp_SerializerNum_0},
    	&mcaspRcvSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */
    	Mcasp_WordLength_32,
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
    	TRUE,
    	TRUE
    };
    
    /* McAsp channel parameters for transmit - DAC0              */
    Mcasp_ChanParams  mcaspTx0ChanParam =
    {
    	0x0001,                   /* number of serializers       */
    	{Mcasp_SerializerNum_0}, /* serializer index for DAC0    */
    	&mcaspXmtSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,
    	Mcasp_WordLength_32,      /* word width                  */
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
    	TRUE,
    	TRUE
    };
    
    

    I have a few buffers allocated on the heap for debug purposes.

    int32_t inBufTempL1[BUFSIZE * RX_NUM_SERIALIZER];
    int32_t inBufTempL2[BUFSIZE * RX_NUM_SERIALIZER];
    int32_t inBufTempR1[BUFSIZE * RX_NUM_SERIALIZER];
    int32_t inBufTempR2[BUFSIZE * RX_NUM_SERIALIZER];

    In the echo task call, my code looks like this:

    		int32_t *inBuf;
    		int32_t *outBuf;
    
    		outBuf = (int32_t *)txBuf[gtxFrameIndexCount];
    		inBuf = (int32_t *)rxBuf[grxFrameIndexCount];
    
    		unsigned int i, j;
    
    		/* Deserialize input */
    		for (i = 0, j = 0; i < BUFSIZE * RX_NUM_SERIALIZER / sizeof(int32_t); i += 2, j++) {
    			inBufTempL1[j] = inBuf[i];		// S1L, S1R, S1L, S1R, etc...
    			inBufTempR1[j] = inBuf[i + 1];
    		}
    
    		/* Serialize output */
    		for (i = 0, j = 0; i < BUFSIZE * TX_NUM_SERIALIZER / sizeof(int32_t); i += 2, j++) {
    			outBuf[i] = inBufTempL1[j];
    			outBuf[i + 1] = inBufTempL1[j];
    		}

    So, what I'm doing is assuming samples are coming in R, L, R, L, etc.  I put all the left samples into one buffer (inBufTempL1), and all the right samples into another (inBufTempR1).  Then when I serialize the output to play back, I can double the right samples, or double the left samples to hear the output of either left or right in the headphones.  In the code above, I could the left channel.  I can also playback true stereo audio by changing the last couple lines to

    outBuf[i] = inBufTempL1[j];
    outBuf[i + 1] = inBufTempR1[j];

    However, nothing is making sense when I use more than one serializer.  My configuration for multiple input channels is:



    /* McAsp channel parameters for receive */ Mcasp_ChanParams mcaspRxChanParam = { 0x0002, /* number of serializers */ {Mcasp_SerializerNum_0, Mcasp_SerializerNum_1}, &mcaspRcvSetup, TRUE, Mcasp_OpMode_TDM, /* Mode (TDM/DIT) */ Mcasp_WordLength_32, NULL, 0, NULL, GblErr, 2, /* number of TDM channels */ Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2, TRUE, TRUE }; /* McAsp channel parameters for transmit - DAC0 */ Mcasp_ChanParams mcaspTx0ChanParam = { 0x0001, /* number of serializers */ {Mcasp_SerializerNum_0}, /* serializer index for DAC0 */ &mcaspXmtSetup, TRUE, Mcasp_OpMode_TDM, Mcasp_WordLength_32, /* word width */ NULL, 0, NULL, GblErr, 2, /* number of TDM channels */ Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED, TRUE, TRUE };

    As per your previous comment, you mention the samples should be coming S1_L, S2_L, S1_R, S2_R.

    So in my echo_task code, I do something similar:

    		int32_t *inBuf;
    		int32_t *outBuf;
    
    		outBuf = (int32_t *)txBuf[gtxFrameIndexCount];
    		inBuf = (int32_t *)rxBuf[grxFrameIndexCount];
    
    		unsigned int i, j;
    
    		/* Deserialize input */
    		for (i = 0, j = 0; i < BUFSIZE * RX_NUM_SERIALIZER / sizeof(int32_t); i += 4, j++) {
    			inBufTempL1[j] = inBuf[i];		// S1L, S2L, S1R, S2R, etc...
    			inBufTempR1[j] = inBuf[i + 1];
    			inBufTempL2[j] = inBuf[i + 2];
    			inBufTempR2[j] = inBuf[i + 3];
    		}
    
    		/* Serialize output */
    		for (i = 0, j = 0; i < BUFSIZE * TX_NUM_SERIALIZER / sizeof(int32_t); i += 2, j++) {
    			outBuf[i]		= inBufTempL1[j];
    			outBuf[i + 1]	= inBufTempL1[j];
    		}

    This does not work.  I get garbage noise on the output with a little bit of actual signal.  When I use the SEMI_INTERLEAVED_2 macro as you suggested, I can hear multiple inputs on the output, which is DEFINITELY not expected.  When I use SEMI_INTERLEAVED_1, I hear only one of the 4 outputs (two serializers, two channels (L and R)), however the audio still sounds like garbage.

    I will attach my mcasp_cfg.c and mcasp_cfg.h files, as this is the only place I've made changes so far.  There's a macro in the header called "TWO_INPUT", when you toggle it off/on, it will configure the channels as suggested and use different parts of the code in the echo_task call.  Please advise as this is getting pretty tedius.mcasp_cfg.h

    mcasp_cfg.c
    /*
     * Copyright (c) 2015, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    /**
     * \file      mcasp_config.c
     *
     * \brief     Configures McASP module
     *
     */
    
    #include <osp_process.h>
    
    #include "mcasp_cfg.h"
    
    /* Frame index for Rx and Tx buffers */
    uint8_t rxFrameIndex = 1;
    uint8_t txFrameIndex = 1;
    uint32_t gtxFrameIndexCount = 0;
    uint32_t grxFrameIndexCount = 0;
    
    int32_t inBufTempL1[BUFSIZE * RX_NUM_SERIALIZER];
    int32_t inBufTempL2[BUFSIZE * RX_NUM_SERIALIZER];
    int32_t inBufTempR1[BUFSIZE * RX_NUM_SERIALIZER];
    int32_t inBufTempR2[BUFSIZE * RX_NUM_SERIALIZER];
    
    /* Flags for counting Rx and Tx interrupts */
    volatile uint32_t rxFlag = 0;
    volatile uint32_t txFlag = 0;
    
    /* Semaphore handle for Tx and Rx */
    Semaphore_Handle semR;
    Semaphore_Handle semT;
    Semaphore_Params params;
    
    /* McASP device handles */
    Ptr hMcaspDevTx;
    Ptr hMcaspDevRx;
    
    /* McASP channel handles */
    Ptr hMcaspTxChan;
    Ptr hMcaspRxChan;
    
    /* McASP channel parameters */
    Mcasp_Params mcaspTxParams;
    Mcasp_Params mcaspRxParams;
    
    /* McASP Callback function argument */
    uint32_t txChanMode;
    uint32_t rxChanMode;
    uint32_t mcaspRxChanArg = 1;
    uint32_t mcaspTxChanArg = 2;
    
    /* McASP Tx and Rx frame buffers */
    MCASP_Packet rxFrame[NUM_BUFS];
    MCASP_Packet txFrame[NUM_BUFS];
    
    /* McASP Tx and Rx frame buffer pointers */
    Ptr txBuf[NUM_BUFS];
    Ptr rxBuf[NUM_BUFS];
    
    /* Error flag */
    uint32_t gblErrFlag = 0;
    Error_Block eb;
    
    /* Handle to heap object */
    extern HeapMem_Handle heapHandle;
    
    /* Mcasp IOM function object */
    extern IOM_Fxns Mcasp_IOMFXNS;
    
    /* External function declarations */
    void McaspDevice_init(void);
    void GblErr(int arg);
    signed char*  getGlobalAddr(signed char* addr);
    
    /* McASP HW setup for receive */
    Mcasp_HwSetupData mcaspRcvSetup = {
            /* .rmask    = */ 0xFFFFFFFF, /* 16 bits are to be used     */
            /* .rfmt     = */ 0x000180F2, /*
                                           * 0 bit delay from framesync
                                           * MSB first
                                           * No extra bit padding
                                           * Padding bit (ignore)
                                           * slot Size is 32
                                           * Reads from DMA port
                                           * NO rotation
                                           */
            /* .afsrctl  = */ 0X00000112, /* I2S mode - 2 slot TDM
                                           * Frame sync is one word
                                           * Internally generated frame sync
                                           * Rising edge is start of frame
                                           */
            /* .rtdm     = */ 0x00000003, /* slot 1 and 2 are active (I2S)        */
            /* .rintctl  = */ 0x00000000, /* sync error and overrun error         */
            /* .rstat    = */ 0x000001FF, /* reset any existing status bits       */
            /* .revtctl  = */ 0x00000000, /* DMA request is enabled               */
            {
                 /* .aclkrctl  = */ 0x000000A7,
                 /* .aclkrctl  = */ // 0x000000A7,
                 /* .ahclkrctl = */ 0x0000C001,
                 /* .rclkchk   = */ 0x00000000
            }
    };
    
    /* McASP HW setup for transmit */
    Mcasp_HwSetupData mcaspXmtSetup = {
            /* .xmask    = */ 0xFFFFFFFF, /* 16 bits are to be used     */
            /* .xfmt     = */ 0x000180F6, /*
                                           * 0 bit delay from framesync
                                           * MSB first
                                           * No extra bit padding
                                           * Padding bit (ignore)
                                           * slot Size is 32
                                           * Reads from DMA port
                                           * NO rotation
                                           */
            /* .afsxctl  = */ 0x00000112, /* I2S mode - 2 slot TDM
                                           * Frame sync is one word
                                           * Rising edge is start of frame
                                           * Internally generated frame sync
                                           */
            /* .xtdm     = */ 0x00000003, /* slot 1 and 2 are active (I2S)               */
            /* .xintctl  = */ 0x00000000, /* sync error,overrun error,clK error   */
            /* .xstat    = */ 0x000001FF, /* reset any existing status bits       */
            /* .xevtctl  = */ 0x00000000, /* DMA request is enabled or disabled   */
            {
                 /* .aclkxctl  = */ 0X000000A7,
                 /* .ahclkxctl = */ 0x0000C001,
                 /* .xclkchk   = */ 0x00000000
            },
    
    };
    
    /* McAsp channel parameters for receive                      */
    Mcasp_ChanParams  mcaspRxChanParam =
    {
    #ifdef TWO_INPUT
    	0x0002,                    /* number of serializers      */
    	{Mcasp_SerializerNum_0,
    	 Mcasp_SerializerNum_1},
    #else
    	0x0001,                    /* number of serializers      */
    	{Mcasp_SerializerNum_0},
    #endif
    	&mcaspRcvSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,          /* Mode (TDM/DIT)             */
    	Mcasp_WordLength_32,
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    #ifdef TWO_INPUT
    	Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2,
    #else
    	Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
    #endif
    	TRUE,
    	TRUE
    };
    
    /* McAsp channel parameters for transmit - DAC0              */
    Mcasp_ChanParams  mcaspTx0ChanParam =
    {
    	0x0001,                   /* number of serializers       */
    	{Mcasp_SerializerNum_0}, /* serializer index for DAC0    */
    	&mcaspXmtSetup,
    	TRUE,
    	Mcasp_OpMode_TDM,
    	Mcasp_WordLength_32,      /* word width                  */
    	NULL,
    	0,
    	NULL,
    	GblErr,
    	2,                        /* number of TDM channels      */
    	Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED,
    	TRUE,
    	TRUE
    };
    
    /* Handle to eDMA */
    extern EDMA3_DRV_Handle hEdma0;
    extern EDMA3_DRV_Handle hEdma1;
    
    extern uint32_t sineData[];
    extern uint32_t sineData_4ch[];
    
    /**
     *  \brief    Function called by McASP driver in case of error
     *
     *  \return    None
     */
    void GblErr(int arg)
    {
    	gblErrFlag = 1;
    }
    
    /**
     *  \brief   McASP callback function called up on the data transfer completion
     *
     *  \param  arg   [IN]  - Application specific callback argument
     *  \param  ioBuf [IN]  - McASP IO buffer
     *
     *  \return    None
     */
    void mcaspAppCallback(void *arg, MCASP_Packet *ioBuf)
    {
    	/* Callback is triggered by Rx completion */
    	if(ioBuf->cmd == MCASP_READ)
    	{
    		rxFlag++;
    
    		if(rxFrameIndex == 0)
    		{
    			rxFrameIndex = 1;
    		}
    		else
    		{
    			rxFrameIndex = 0;
    		}
    
    		/* Post semaphore */
    		Semaphore_post(semR);
    	}
    
    	/* Callback is triggered by Tx completion */
    	if(ioBuf->cmd == MCASP_WRITE)
    	{
    		if(txFrameIndex == 0)
    		{
    			txFrameIndex = 1;
    		}
    		else
    		{
    			txFrameIndex = 0;
    		}
    
    		txFlag++;
    
    		/* Post semaphore */
    		Semaphore_post(semT);
    	}
    }
    
    /**
     *  \brief   Initializes McASP data buffers and submits to McASP driver
     *
     *  \return    Audk2g_EOK on Success or error code
     */
    Audk2g_STATUS initBuffers(void)
    {
    	Error_Block  eb;
        uint32_t     count = 0;
        IHeap_Handle iheap;
        Int          status;
    
        iheap = HeapMem_Handle_to_xdc_runtime_IHeap(heapHandle);
        Error_init(&eb);
    
        //txBufTemp = Memory_calloc(iheap, (BUFSIZE * RX_NUM_SERIALIZER), BUFALIGN, &eb);
    
        /* Allocate buffers for the McASP data exchanges */
        for(count = 0; count < NUM_BUFS; count++)
        {
            rxBuf[count] = Memory_calloc(iheap, (BUFSIZE * RX_NUM_SERIALIZER),
            						     BUFALIGN, &eb);
            if(NULL == rxBuf[count])
            {
                IFPRINT(audk2g_write("\r\nMEM_calloc failed for Rx\n"));
            }
        }
    
        /* Allocate buffers for the McASP data exchanges */
        for(count = 0; count < NUM_BUFS; count++)
        {
            txBuf[count] = Memory_calloc(iheap, (BUFSIZE * TX_NUM_SERIALIZER),
            							 BUFALIGN, &eb);
            if(NULL == txBuf[count])
            {
                IFPRINT(audk2g_write("\r\nMEM_calloc failed for Tx\n"));
            }
        }
    
        for(count = 0; count < NUM_BUFS; count++)
        {
            /* Issue the first & second empty buffers to the input stream */
        	memset((uint8_t *)rxBuf[count], 0xFF, (BUFSIZE * RX_NUM_SERIALIZER));
    
    		/* RX frame processing */
    		rxFrame[count].cmd    = MCASP_READ;
    		rxFrame[count].addr   = (void*)(getGlobalAddr(rxBuf[count]));
    		rxFrame[count].size   = BUFSIZE;
    		rxFrame[count].arg    = (uint32_t) mcaspRxChanArg;
    		rxFrame[count].status = 0;
    		rxFrame[count].misc   = 1;   /* reserved - used in callback to indicate asynch packet */
    
    		/* Submit McASP packet for Rx */
    		status = mcaspSubmitChan(hMcaspRxChan, &rxFrame[count]);
    		if((status != MCASP_COMPLETED) && (status != MCASP_PENDING))
    		{
    			IFPRINT(audk2g_write("mcaspSubmitChan for Rx Failed\n"));
    			return (Audk2g_EFAIL);
    		}
        }
    
        for(count = 0; count < NUM_BUFS; count++)
        {
        	memset((uint8_t *)txBuf[count], 0xCC, (BUFSIZE * TX_NUM_SERIALIZER));
    
    		/* TX frame processing */
    		txFrame[count].cmd    = MCASP_WRITE;
    		txFrame[count].addr   = (void*)(getGlobalAddr(txBuf[count]));
    		txFrame[count].size   = BUFSIZE;
    		txFrame[count].arg    = (uint32_t) mcaspTxChanArg;
    		txFrame[count].status = 0;
    		txFrame[count].misc   = 1;   /* reserved - used in callback to indicate asynch packet */
    
    		/* Submit McASP packet for Tx */
    		status = mcaspSubmitChan(hMcaspTxChan, &txFrame[count]);
    		if((status != MCASP_COMPLETED) && (status != MCASP_PENDING))
    		{
    			IFPRINT(audk2g_write("mcaspSubmitChan for Tx Failed\n"));
    			return (Audk2g_EFAIL);
    		}
        }
    
        return (Audk2g_EOK);
    }
    
    /**
     *  \brief   Configures McASP module and creates the channel
     *           for audio Tx and Rx
     *
     *  \return    Audk2g_EOK on Success or error code
     */
    Audk2g_STATUS mcaspAudioConfig(void)
    {
    	Int status;
    
    	hMcaspDevTx  = NULL;
    	hMcaspDevRx  = NULL;
    	hMcaspTxChan = NULL;
    	hMcaspRxChan = NULL;
    
    	/* Initialize McASP Tx and Rx parameters */
    	mcaspTxParams = Mcasp_PARAMS;
    	mcaspRxParams = Mcasp_PARAMS;
    
    	mcaspTxParams.mcaspHwSetup.tx.clk.clkSetupClk = 0x63;
    	mcaspTxParams.mcaspHwSetup.rx.clk.clkSetupClk = 0x23;
    	mcaspRxParams.mcaspHwSetup.rx.clk.clkSetupClk = 0x23;
    	mcaspRxParams.mcaspHwSetup.tx.clk.clkSetupClk = 0x63;
    
    	mcaspTxParams.mcaspHwSetup.glb.pdir |= 0x2000000; //Set Amute pin as output for Tx channel
    
    	/* Set the HW interrupt number */
    	mcaspTxParams.hwiNumber = 8;
    	mcaspRxParams.hwiNumber = 8;
    
    	/* Initialize eDMA handle */
    	mcaspRxChanParam.edmaHandle  = hEdma1;
    	mcaspTx0ChanParam.edmaHandle = hEdma0;
    
    	/* Bind McASP0 for Tx */
    	status = mcaspBindDev(&hMcaspDevTx, CSL_MCASP_0, &mcaspTxParams);
    	if((status != MCASP_COMPLETED) || (hMcaspDevTx == NULL))
    	{
    		IFPRINT(audk2g_write("mcaspBindDev for Tx Failed\n"));
    		return (Audk2g_EFAIL);
    	}
    
    	/* Bind McASP1 for Rx */
    	status = mcaspBindDev(&hMcaspDevRx, CSL_MCASP_1, &mcaspRxParams);
    	if((status != MCASP_COMPLETED) || (hMcaspDevRx == NULL))
    	{
    		IFPRINT(audk2g_write("mcaspBindDev for Rx Failed\n"));
    		return (Audk2g_EFAIL);
    	}
    
    	/* Create McASP channel for Tx */
    	status = mcaspCreateChan(&hMcaspTxChan, hMcaspDevTx,
    	                         MCASP_OUTPUT,
    	                         &mcaspTx0ChanParam,
    	                         mcaspAppCallback, &txChanMode);
    	if((status != MCASP_COMPLETED) || (hMcaspTxChan == NULL))
    	{
    		IFPRINT(audk2g_write("mcaspCreateChan for Tx Failed\n"));
    		return (Audk2g_EFAIL);
    	}
    
    	configAudioDAC();
    
    	/* Create McASP channel for Rx */
    	status = mcaspCreateChan(&hMcaspRxChan, hMcaspDevRx,
    	                         MCASP_INPUT,
    	                         &mcaspRxChanParam,
    	                         mcaspAppCallback, &rxChanMode);
    	if((status != MCASP_COMPLETED) || (hMcaspRxChan == NULL))
    	{
    		IFPRINT(audk2g_write("mcaspCreateChan for Rx Failed\n"));
    		return (Audk2g_EFAIL);
    	}
    
    	/* Initialize the buffers and submit for McASP Tx/Rx */
    	if(initBuffers() != Audk2g_EOK)
    	{
    		IFPRINT(audk2g_write("McASP Buffer Initialization Failed\n"));
    		return (Audk2g_EFAIL);
    	}
    
    	return (Audk2g_EOK);
    }
    
    /**
     *  \brief   Function to exit the test
     *
     *  \return    None
     */
    void testRet(uint32_t status)
    {
    	audk2g_write("\n\nAudio DC Analog Interface Test Completed!\n");
    
    	testExit(status);
    }
    
    /**
     *  \brief   Task to echo the input data to output
     *
     *  Waits for the McASP data transfer completion and copies the
     *  Rx data to Tx buffers
     *
     *  \return    Audk2g_EOK on Success or error code
     */
    Void Audio_echo_Task(void)
    {
        int32_t count;
    
        Semaphore_Params_init(&params);
    
    	/* Create semaphores to wait for buffer reclaiming */
        semR = Semaphore_create(0, &params, &eb);
        semT = Semaphore_create(0, &params, &eb);
    
        /* Forever loop to continuously receive and transmit audio data */
        while (1)
        {
        	if(gblErrFlag)
        	{
        		break;
    		}
    
        	/* Reclaim full buffer from the input stream */
        	Semaphore_pend(semR, BIOS_WAIT_FOREVER);
        	Semaphore_pend(semT, BIOS_WAIT_FOREVER);
    
            /* Reclaim full buffer from the input stream */
        	gtxFrameIndexCount = txFrameIndex;
        	grxFrameIndexCount = rxFrameIndex;
    
    		for(count = 0; count < 0; count++)
    		{
    			asm("* Comment to maintain loops through compiler optimization");
    		}
    
            /* Reclaim empty buffer from the output stream to be reused           */
    
            /* Copy the receive information to the transmit buffer */
    
    		int32_t *inBuf;
    		int32_t *outBuf;
    
    		outBuf = (int32_t *)txBuf[gtxFrameIndexCount];
    		inBuf = (int32_t *)rxBuf[grxFrameIndexCount];
    
    		unsigned int i, j;
    
    #ifdef TWO_INPUT
    		/* Deserialize input */
    		for (i = 0, j = 0; i < BUFSIZE * RX_NUM_SERIALIZER / sizeof(int32_t); i += 4, j++) {
    			inBufTempL1[j] = inBuf[i];		// S1L, S2L, S1R, S2R, etc...
    			inBufTempR1[j] = inBuf[i + 1];
    			inBufTempL2[j] = inBuf[i + 2];
    			inBufTempR2[j] = inBuf[i + 3];
    		}
    
    		/* Serialize output */
    		for (i = 0, j = 0; i < BUFSIZE * TX_NUM_SERIALIZER / sizeof(int32_t); i += 2, j++) {
    			outBuf[i]		= inBufTempL1[j];
    			outBuf[i + 1]	= inBufTempL1[j];
    		}
    #else
    		/* Deserialize input */
    		for (i = 0, j = 0; i < BUFSIZE * RX_NUM_SERIALIZER / sizeof(int32_t); i += 2, j++) {
    			inBufTempL1[j] = inBuf[i];		// S1L, S1R, S1L, S1R, etc...
    			inBufTempR1[j] = inBuf[i + 1];
    		}
    
    		/* Serialize output */
    		for (i = 0, j = 0; i < BUFSIZE * TX_NUM_SERIALIZER / sizeof(int32_t); i += 2, j++) {
    			outBuf[i] = inBufTempL1[j];
    			outBuf[i + 1] = inBufTempL1[j];
    		}
    #endif
    
    		//memcpy(txBuf[gtxFrameIndexCount], rxBuf[grxFrameIndexCount], (BUFSIZE * RX_NUM_SERIALIZER));
    
    		//memcpy(txBuf[gtxFrameIndexCount], (const void *)sineData, (BUFSIZE * RX_NUM_SERIALIZER));
    		//memcpy(txBuf[gtxFrameIndexCount], (const void *)sineData_4ch, (BUFSIZE * RX_NUM_SERIALIZER));
    
            /* Issue full buffer to the output stream                             */
            /* TX frame processing */
    		txFrame[gtxFrameIndexCount].cmd    = MCASP_READ;
    		txFrame[gtxFrameIndexCount].addr   = (void*)(getGlobalAddr(txBuf[gtxFrameIndexCount]));
    		txFrame[gtxFrameIndexCount].size   = (BUFSIZE);
    		txFrame[gtxFrameIndexCount].arg    = (uint32_t) mcaspTxChanArg;
    		txFrame[gtxFrameIndexCount].status = 0;
    		txFrame[gtxFrameIndexCount].misc   = 1;   /* reserved - used in callback to indicate asynch packet */
    
    		mcaspSubmitChan(hMcaspTxChan, &txFrame[gtxFrameIndexCount]);
    
            /* Issue an empty buffer to the input stream                          */
    		rxFrame[grxFrameIndexCount].cmd    = MCASP_WRITE;
    		rxFrame[grxFrameIndexCount].addr   = (void*)(getGlobalAddr(rxBuf[grxFrameIndexCount]));
    		rxFrame[grxFrameIndexCount].size   = (BUFSIZE);
    		rxFrame[grxFrameIndexCount].arg    = (uint32_t) mcaspRxChanArg;
    		rxFrame[grxFrameIndexCount].status = 0;
    		rxFrame[grxFrameIndexCount].misc   = 1;   /* reserved - used in callback to indicate asynch packet */
    
            mcaspSubmitChan(hMcaspRxChan, &rxFrame[grxFrameIndexCount]);
    	}
    
        testRet(0);
    }
    
    /* Nothing past this point */
    

  • Justyn,

    I apologize for leaving this unanswered but I was working on a high priority task so couldn`t spend as much time on this issue.  I reached out to the developer to provide some guidance or documentation and here is the documentation that I was able get from them.

    MCASP_DataFormats.pdf

    I haven`t reviewed the entire document but the interpretation of SEMI interleaved is consistent to what I mentioned. I will try to experiment with these settings and also review your code and see if I can provide some additional guidance.

    Are you creating test vectors and using one stereo input to check the buffer format ? 

    Regards,

    Rahul

  • Justyn,

    Here is graphical representation of the MCASP LLD input and output buffers for the different formats specified. My earlier interpretation seems to be incorrect. These formats have been independently verified by a colleague of mine who is working on a multi-microphone input board and MCASP LLD drivers.

    For I2S mode with Data format Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1

    For I2S mode with Data format Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2

     

    Hope this gives some clarity for deserializing and processing the data


    Regards,

    Rahul

  • Okay, it's finally working with Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2.

    There was a couple problems happening at once, and because of some misinformation, nothing worked correctly at the same time.

    So a couple more things to get this to work, the TX/RX buffers need to be correctly allocated in mcasp_cfg.c line 81 and 82.

    /* McASP Tx and Rx frame buffer pointers */
    Ptr txBuf[NUM_BUFS * TX_NUM_SERIALIZER];
    Ptr rxBuf[NUM_BUFS * RX_NUM_SERIALIZER];
    

    Which I think you mentioned when I initially asked the question.  But also the rx/txFrame's size attribute has to be modified on line 331 and 352 to

    rxFrame[count].size   = BUFSIZE * RX_NUM_SERIALIZER;
    

    and

    txFrame[count].size = BUFSIZE * TX_NUM_SERIALIZER; 

    This also has to change in the actual echo loopback call as well on lines 529 and 539.

    Basically, you warned me to allocate enough buffer space for rxBuf and txBuf, but I didn't think on my own to make changes to rxFrame and txFrame as well.  I did indeed play around with test vectors at the ADC, but was seeing very wrong results in terms of buffer content.  I think it was just not allocating correctly compounded with the slight misinformation, I wasn't able to get it working for a while.  In addition, my project's requirements were relaxed for the time being to use one TX and one RX serializer, so I wasn't putting too much effort into it.

    In short thank you for all the help once again.

  • Thanks for confirming that your setup is working, Justyn.

    Can you please clarify which format you used and confirm that the format in which the data was obtained matched to the graphic provided. We plan to add similar graphic to the driver documentation so your confirmation will re-enforce our observations for others who come across this post.

    Regards,
    Rahul

  • Sorry it's been a while, I kind of took off with development after I got the answer above.

    However, I did get some time to respond to this.

    The mode that I used that works is I2S mode with Data format Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2

    And I can confirm that it matches the table above.

    However, there's a few typos in the table for the Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1 mode.  The correct format for SEMI_INTERLEAVED_1 is SR1_L1, SR2_L1, SR1_R1, SR2_R1, SR1_L2, SR2_L2, SR1_R2, SR2_R2, etc.

    Maybe a little more clearly, the samples come in like L,L, R,R, L,L, R,R, where the first L is SR1, second SR2, etc.  The engineers might be correct, but that table for SEMI_INTERLEAVED_1 is all garbled up.

    --

    Justyn

  • Justyn,

    We have this visually represented in the documentation attached. thanks for your feedback and helping us identifying this gap in the collateral.
    processors.wiki.ti.com/.../Processor_SDK_RTOS_MCASP

    Regards,
    Rahul