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.