SK-AM62A-LP: MCASP RxBuffer modification before transmit

Part Number: SK-AM62A-LP
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hello. I would like to get some help for my audio processing project with AM62A. 
The goal of my project is to apply real-time audio FXs on I2S audio data.
I would like to achieve this with (1) no rtos, (2) stereo I2S audio input (3) MCASP DMA mode.

I managed to port the mcasp_playback_codec_aic31_am62ax-sk_a53ss0-0_freertos_gcc-aarch64 project into nortos example project and achieved my goal with MCASP interrupt mode without DMA.

But as the timing is little tight, I wanted to try MCASP DMA mode.

The problem is that, on every MCASP RX callback, even though I modified the buffer of each transaction by applying my audio FX, it always play back the original audio. It seems like my audio FX modification didn't affect the audio data at all. At first I thought it was due to the bug on my audio FX function, so I tried to simply replace all audio samples to zero to test the root problem. Even then, the audio is not silent as expected, but instead the original audio is played back.

This is how I modified the callback functions of MCASP RX and TX:

void mcasp_txcb(MCASP_Handle handle,
                          MCASP_Transaction *transaction)
{
    MCASP_submitRx(handle, transaction);
}

uint32_t RX_Buf_R[2][32], RX_Buf_L[2][32] __attribute__((aligned(256)));
uint32_t TX_Buf_R[2][32], TX_Buf_L[2][32] __attribute__((aligned(256)));
uint8_t  IDX_Rx = 0, IDX_Proc = 0, IDX_Tx = 1;

void mcasp_rxcb(MCASP_Handle handle,
                          MCASP_Transaction *transaction)
{
    int32_t    *ptr32;
    size_t bufferSize;
    
    ptr32 = (void *)((transaction->buf));
    bufferSize = transaction->count;

    for (size_t i = 0; i < bufferSize/2; i++) {
        RX_Buf_L[IDX_Rx][i] = *ptr32++;
        RX_Buf_R[IDX_Rx][i] = *ptr32++;
    }
    
    ptr32 = (void *)((transaction->buf));
    
    for(int i = 0; i < bufferSize/2; i++) {
        *ptr32++ = TX_Buf_L[IDX_Tx][i];  // Left
        *ptr32++ = TX_Buf_R[IDX_Tx][i];  // Right
    }

    IDX_Rx ^= 0x01;
    IDX_Tx ^= 0x01;
    
    // Submit the modified buffer to the TX queue
    MCASP_submitTx(handle, transaction);
}

This is all MCASP related configuration generated by sysconfig.

/*
 * MCASP
 */

/* MCASP transmit callback */
void mcasp_txcb(MCASP_Handle handle, MCASP_Transaction *transaction);
/* MCASP receive Callback */
void mcasp_rxcb(MCASP_Handle handle, MCASP_Transaction *transaction);
/* MCASP transmit loopjob buffer */
uint8_t gTxLoopjobBuf0[256] __attribute__((aligned(256))) = {0};
/* MCASP receive loopjob buffer */
uint8_t gRxLoopjobBuf0[256] __attribute__((aligned(256))) = {0};

/* Arrays containing indices of MCASP Tx/Rx serializers used */
uint8_t gMcasp0TxSersUsed[1] = {0};
uint8_t gMcasp0RxSersUsed[1] = {2};

Udma_EventObject gBcdmaTxCqEventObj;
Udma_EventObject gBcdmaRxCqEventObj;

/* Number of ring entries */
#define UDMA_RING_ENTRIES_TX             (MCASP_TX_DMA_RING_ELEM_CNT)
#define UDMA_RING_ENTRIES_RX             (MCASP_RX_DMA_RING_ELEM_CNT)
/* Size (in bytes) of each ring entry (Size of pointer - 64-bit) */
#define MCASP_UDMA_RING_ENTRY_SIZE       (sizeof(uint64_t))

#define MCASP_RING_MEM_SIZE_TX           (MCASP_UDMA_RING_ENTRY_SIZE*UDMA_RING_ENTRIES_TX)
#define MCASP_RING_MEM_SIZE_RX           (MCASP_UDMA_RING_ENTRY_SIZE*UDMA_RING_ENTRIES_RX)

#define MCASP_UDMA_TR3_TRPD_SIZE         (UDMA_GET_TRPD_TR3_SIZE(1))
#define MCASP_UDMA_HPD_SIZE              UDMA_ALIGN_SIZE((sizeof(CSL_UdmapCppi5HMPD)))

Udma_ChObject       gMcasp0UdmaTxChObj;
Udma_EventObject    gMcasp0_UdmaCqEventObjTx;

Udma_ChObject       gMcasp0UdmaRxChObj;
Udma_EventObject    gMcasp0_UdmaCqEventObjRx;

static uint8_t gMcasp0UdmaTxTrpdMem[MCASP_UDMA_TR3_TRPD_SIZE*MCASP_TX_DMA_RING_ELEM_CNT] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));
static uint8_t gMcasp0UdmaRxTrpdMem[MCASP_UDMA_HPD_SIZE*MCASP_RX_DMA_RING_ELEM_CNT] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));

static uint8_t gMcasp0TxFqRingMem[UDMA_ALIGN_SIZE(MCASP_RING_MEM_SIZE_TX)] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));
static uint8_t gMcasp0RxFqRingMem[UDMA_ALIGN_SIZE(MCASP_RING_MEM_SIZE_RX)] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));

static MCASP_Transaction *gMcasp0TxCbParam[MCASP_TX_DMA_RING_ELEM_CNT];
static MCASP_Transaction *gMcasp0RxCbParam[MCASP_RX_DMA_RING_ELEM_CNT];

MCASP_DmaChConfig gMcasp0_DmaChCfg[] =
{
    {
        .txChHandle         = &gMcasp0UdmaTxChObj,
        .rxChHandle         = &gMcasp0UdmaRxChObj,
        .cqTxEvtHandle      = &gMcasp0_UdmaCqEventObjTx,
        .cqRxEvtHandle      = &gMcasp0_UdmaCqEventObjRx,
        .txTrpdMem          = gMcasp0UdmaTxTrpdMem,
        .rxTrpdMem          = gMcasp0UdmaRxTrpdMem,
        .txRingMem          = gMcasp0TxFqRingMem,
        .rxRingMem          = gMcasp0RxFqRingMem,
        .txCbParams         = gMcasp0TxCbParam,
        .rxCbParams         = gMcasp0RxCbParam,
        .rxEvtNum           = UDMA_PDMA_CH_MAIN0_MCASP1_RX,
        .txEvtNum           = UDMA_PDMA_CH_MAIN0_MCASP1_TX,
    }
};

/* MCASP Driver handles */
MCASP_Handle gMcaspHandle[CONFIG_MCASP_NUM_INSTANCES];
/* MCASP Driver Open Parameters */
MCASP_OpenParams gMcaspOpenParams[CONFIG_MCASP_NUM_INSTANCES] =
{
    {
        .transferMode = MCASP_TRANSFER_MODE_DMA,
        .txBufferFormat = MCASP_AUDBUFF_FORMAT_1SER_MULTISLOT_INTERLEAVED,
        .rxBufferFormat = MCASP_AUDBUFF_FORMAT_1SER_MULTISLOT_INTERLEAVED,
        .txSerUsedCount = 1,
        .rxSerUsedCount = 1,
        .txSerUsedArray = (uint8_t *) gMcasp0TxSersUsed,
        .rxSerUsedArray = (uint8_t *) gMcasp0RxSersUsed,
        .txSlotCount = 2,
        .rxSlotCount = 2,
        .txCallbackFxn = mcasp_txcb,
        .rxCallbackFxn = mcasp_rxcb,
        .txLoopjobEnable = true,
        .txLoopjobBuf = (uint8_t *) gTxLoopjobBuf0,
        .txLoopjobBufLength = 64,
        .rxLoopjobEnable = true,
        .rxLoopjobBuf = (uint8_t *) gRxLoopjobBuf0,
        .rxLoopjobBufLength = 64,
        .dmaChCfg = &gMcasp0_DmaChCfg[0],
        .mcaspDmaDrvObj = &gUdmaDrvObj[CONFIG_UDMA0],
        .mcaspPktDmaDrvObj = &gUdmaDrvObj[CONFIG_UDMA1],
        .skipDriverOpen = 0,
    },
};




/*
 * MCASP
 */
/* MCASP atrributes */
static MCASP_Attrs gMcaspAttrs[CONFIG_MCASP_NUM_INSTANCES] =
{



    {
        .instNum               = MCASP1,
        .baseAddr              = (uintptr_t) CSL_MCASP1_CFG_BASE,
        .dataBaseAddr          = (uintptr_t) CSL_MCASP1_DMA_BASE,
        .isSynchronous          = 1U,
        /* MCASP Data port Address  */
        .numOfSerializers = (uint32_t)16,
        /* Serializers available in MCASP */
        .intCfgTx =
        {
            .intrNum = (uint32_t)270,
            .evntNum = (uint32_t)0,
            .intrPriority = 4,
        },
        /* Tx Int params for McASP */
        .intCfgRx =
        {
            .intrNum = (uint32_t)269,
            .evntNum = (uint32_t)0,
            .intrPriority = 3,
        },
        .txSlotSize = (uint32_t)32,
        .rxSlotSize = (uint32_t)32,
        .hwCfg =
        {
            .gbl =
            {
                (uint32_t)0x0,  /* MCASP_PFUNC */
                (uint32_t)0x8000001,  /* MCASP_PDIR */
                (uint32_t)0x0,  /* MCASP_GBLCTL */
                (uint32_t)0x0,  /* MCASP_TXDITCTL */
                (uint32_t)0x0,  /* MCASP_LBCTL */
                (uint32_t)0x0,  /* MCASP_TXDITCTL */
                {   /* serializer setup (MCASP_XRSRCTLn) */
                    (uint32_t)0x1, /* [0] - Tx */
                    (uint32_t)0x0, /* [1] - Inactive */
                    (uint32_t)0x2, /* [2] - Rx */
                    (uint32_t)0x0, /* [3] - Inactive */
                    (uint32_t)0x0, /* [4] - Inactive */
                    (uint32_t)0x0, /* [5] - Inactive */
                    (uint32_t)0x0, /* [6] - Inactive */
                    (uint32_t)0x0, /* [7] - Inactive */
                    (uint32_t)0x0, /* [8] - Inactive */
                    (uint32_t)0x0, /* [9] - Inactive */
                    (uint32_t)0x0, /* [10] - Inactive */
                    (uint32_t)0x0, /* [11] - Inactive */
                    (uint32_t)0x0, /* [12] - Inactive */
                    (uint32_t)0x0, /* [13] - Inactive */
                    (uint32_t)0x0, /* [14] - Inactive */
                    (uint32_t)0x0, /* [15] - Inactive */
                },
            },
            .rx =
            {
                (uint32_t)0xFFFFFFFFU, /* MCASP_RXMASK */
                (uint32_t)0x180F0U, /* MCASP_RXFMT */
                (uint32_t)0x111U, /* MCASP_RXFMCTL */
                (uint32_t)0x3U, /* MCASP_RXTDM */
                (uint32_t)0x0U, /* MCASP_EVTCTLR */
                (uint32_t)0xffffU, /* MCASP_RXSTAT */
                (uint32_t)0x1U, /* MCASP_REVTCTL */
                {
                    (uint32_t)0x80U, /* MCASP_ACLKRCTL */
                    (uint32_t)0x8001U, /* MCASP_AHCLKRCTL */
                    (uint32_t)0x0, /* MCASP_RXCLKCHK */
                    (uint32_t)0x0,  /* HCLK is internal */
                },
                {
                    (uint32_t)0x12001U, /* RFIFOCTL */
                    (uint32_t)0x0, /* RFIFOSTS */
                },
            },
            .tx =
            {
                (uint32_t)0xFFFFFFFFU, /* MCASP_TXMASK */
                (uint32_t)0x180F0U, /* MCASP_TXFMT */
                (uint32_t)0x111U, /* MCASP_TXFMCTL */
                (uint32_t)0x3U, /* MCASP_TXTDM */
                (uint32_t)0x0U, /* MCASP_EVTCTLX */
                (uint32_t)0xffffU, /* MCASP_TXSTAT */
                (uint32_t)0x1U, /* MCASP_XEVTCTL */
                {
                    (uint32_t)0x80U, /* MCASP_ACLKXCTL */
                    (uint32_t)0x8001U, /* MCASP_AHCLKXCTL */
                    (uint32_t)0x0, /* MCASP_TXCLKCHK */
                    (uint32_t)0x0,  /* HCLK is internal */
                },
                {
                    (uint32_t)0x12001U, /* WFIFOCTL */
                    (uint32_t)0x0, /* WFIFOSTS */
                },
            },
        },
    },
};

/* MCASP objects - initialized by the driver */
static MCASP_Object gMcaspObjects[CONFIG_MCASP_NUM_INSTANCES];
/* MCASP driver configuration */
MCASP_Config gMcaspConfig[CONFIG_MCASP_NUM_INSTANCES] =
{
    {
        &gMcaspAttrs[CONFIG_MCASP0],
        &gMcaspObjects[CONFIG_MCASP0],
    },
};

uint32_t gMcaspConfigNum = CONFIG_MCASP_NUM_INSTANCES;

/*
 * UDMA
 */
/* UDMA driver instance object */
Udma_DrvObject          gUdmaDrvObj[CONFIG_UDMA_NUM_INSTANCES];
/* UDMA driver instance init params */
static Udma_InitPrms    gUdmaInitPrms[CONFIG_UDMA_NUM_INSTANCES] =
{
    {
        .instId             = UDMA_INST_ID_BCDMA_0,
        .skipGlobalEventReg = FALSE,
        .virtToPhyFxn       = Udma_defaultVirtToPhyFxn,
        .phyToVirtFxn       = Udma_defaultPhyToVirtFxn,
    },
    {
        .instId             = UDMA_INST_ID_PKTDMA_0,
        .skipGlobalEventReg = FALSE,
        .virtToPhyFxn       = Udma_defaultVirtToPhyFxn,
        .phyToVirtFxn       = Udma_defaultPhyToVirtFxn,
    },
};

The only thing I modified from the original mcasp_playback_codec_aic31_am62ax-sk_a53ss0-0_freertos_gcc-aarch64 project is the size of APP_MCASP_AUDIO_BUFF_SIZE to 256, and replacing the uart standby loo with the while-loop of continuous audio FX.

/* Audio buffer settings */
#define APP_MCASP_AUDIO_BUFF_COUNT  (4U)
#define APP_MCASP_AUDIO_BUFF_SIZE   (256U)

/* Create buffers for transmit and Receive */
uint8_t gMcaspAudioBufferTx[APP_MCASP_AUDIO_BUFF_COUNT][APP_MCASP_AUDIO_BUFF_SIZE] __attribute__((aligned(256)));
uint8_t gMcaspAudioBufferRx[APP_MCASP_AUDIO_BUFF_COUNT][APP_MCASP_AUDIO_BUFF_SIZE] __attribute__((aligned(256)));

/* Create transaction objects for transmit and Receive */
MCASP_Transaction   gMcaspAudioTxnTx[APP_MCASP_AUDIO_BUFF_COUNT] = {0};
MCASP_Transaction   gMcaspAudioTxnRx[APP_MCASP_AUDIO_BUFF_COUNT] = {0};

void mcasp_playback_main(void *args)
{
    int32_t         status = SystemP_SUCCESS;
    uint32_t        i;
    MCASP_Handle    mcaspHandle;
    char            valueChar;

    mcasp_aic31_codec_config();

    DebugP_log("[MCASP] Audio playback example started.\r\n");

    //mcaspHandle = manual_MCASP_getHandle(CONFIG_MCASP0);
    mcaspHandle = MCASP_getHandle(CONFIG_MCASP0);

    /* Prepare and submit audio transaction transmit objects */
    for (i = 0U; i < APP_MCASP_AUDIO_BUFF_COUNT; i++)
    {
        gMcaspAudioTxnTx[i].buf = (void*) &gMcaspAudioBufferTx[i][0];
        gMcaspAudioTxnTx[i].count = APP_MCASP_AUDIO_BUFF_SIZE/4;
        gMcaspAudioTxnTx[i].timeout = 0xFFFFFF;
        MCASP_submitTx(mcaspHandle, &gMcaspAudioTxnTx[i]);
    }

    /* Prepare and submit audio transaction receive objects */
    for (i = 0U; i < APP_MCASP_AUDIO_BUFF_COUNT; i++)
    {
        gMcaspAudioTxnRx[i].buf = (void*) &gMcaspAudioBufferRx[i][0];
        gMcaspAudioTxnRx[i].count = APP_MCASP_AUDIO_BUFF_SIZE/4;
        gMcaspAudioTxnRx[i].timeout = 0xFFFFFF;
        MCASP_submitRx(mcaspHandle, &gMcaspAudioTxnRx[i]);
    }

    /* Trigger McASP receive operation */
    status = MCASP_startTransferRx(mcaspHandle);
    DebugP_assert(status == SystemP_SUCCESS);

    /* Trigger McASP transmit operation */
    status = MCASP_startTransferTx(mcaspHandle);
    DebugP_assert(status == SystemP_SUCCESS);

    DebugP_log("Enter your response on UART terminal");

    while(1){
        Process_Audio_Data();
    }
}


void Process_Audio_Data( void )
{
    if( IDX_Rx != IDX_Proc ) {
        My_audio_fx_process(&Rx_Data[IDX_Rx][0], 0.5f, &Tx_Data[IDX_Tx][0], buffer_size/2);
        IDX_Proc ^= 0x01;
    }
}

My questions are:

(1) For the stereo I2S MCASP_AUDBUFF_FORMAT_1SER_MULTISLOT_INTERLEAVED audio data, is it correct that the 32 stereo audio samples are received as [L0, R0, L1, R1, L2, R2, ...., L31, R31]? (APP_MCASP_AUDIO_BUFF_SIZE/4 as the buffer's count value which is 256/4=64 in my scenario.) I just want to make sure I'm accessing the buffer's data in correct order.

(2) What would be the possible causes of the data being not modified, and instead, the original audio is played back? 

I used the scope to check the timing of my audio FX function and it is faster than 44kHz audio sampling rate. Also even simply replacing the values with zero didn't work. So I believe it is not related to the timing of my audio FX function. My approach to modify the transaction's buffer might need to be fixed. Any advice would be greatly appreciated.

Thank you in advance.

  • Hi  Yejin,

    I have assigned your query to our expert. Please expect a response in a day/two.

    Best Regards,

    Suren

  • Hi Yejin,

    Wanted to confirm few more details.

    1. Does your audio FX generate desired output while using the MCASP interrupt mode?

    2. You were using MCASP with interrupt mode of transfer and had a working audio FX, but when you changed the mode of transfer to DMA using sysConfig tool, you are not able to witness the desired output. Is my understanding correct?

    Regards,
    Ritapravo

  • Hello Ritapravo,

    Thank you for the reply.

    1. Yes. With the MCASP interrupt mode, my audio FX generates the modified audio output as I intended.

    2. Yes that's correct. With DMA transfer mode, the output is not what I desired. 

    While waiting for your reply, I further investigated this problem and found out if I use 'CacheP_wbInv(transaction->buf, transaction->count / 2, CacheP_TYPE_ALL)' inside 'mcasp_rxcb' right before 'MCASP_submitTx()', the output audio is now modified with my audio FX function. 

    But now the problem is that:

    (1) The modified sound seems incomplete, i.e. comparing the audio FX between the interrupt transfer mode and the DMA transfer mode, the audio quality of the modified audio output with DMA mode is much worse (quite distorted with white noises).

    (2) If I replace all received audio data with zero instead of applying my own audio FX, instead of the silence, a very loud high-pitch noise is played back.

    So basically, with with 'CacheP_wbInv' it seems like the received audio data are now modified and then transmitted to the external audio codec. But the modification on these audio data isn't what I've intended and it is somehow distorted.