/* * Copyright (c) 2017, 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 "fil.h" /* FILE I/O implementation */ #include "sys.h" /* System API and structures */ #include "sysbfflt.h" /* System support for BF filters */ #include "mcasp_cfg.h" #include "cmb.h" /* The infamous xdc/std.h must come before any header file which uses XDC symbols */ #include /* mandatory - have to include first, for BIOS types */ #include #include #include "../../../common/components/mss/mss.h" /* local version used */ #include #if (SYS_USE_DRC) #include #include #endif /*---------------------------------------- * BIOS header files *----------------------------------------*/ #include /* mandatory - if you call APIs like BIOS_start() */ #include /* header file for statically defined objects/handles */ #include /* for System_printf, and similar */ #include /* for benchmarking/profiling */ #include /* for tracing */ #include #include /* and more tracing */ #include /* this looks obvious */ #include "ti/drv/uart/UART_stdio.h" #define Timestamp_get Timestamp_get32 /* use 32-bit time stamps */ #define MIN(a,b) (((a)>(b))?(b):(a)) /* Min/Max macros */ #define MAX(a,b) (((a)<(b))?(b):(a)) #define loop while(1) /* endless loop for the task */ /* Frame index for Rx and Tx buffers */ uint8_t rxFrameIndex = 1; uint8_t txFrameIndex = 1; uint32_t gtxFrameIndexCount = 0; uint32_t grxFrameIndexCount = 0; /* 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]; Ptr wkBuf[NUM_BUFS]; Ptr outBuf[NUM_BUFS]; /* channel 0 (serilizer 1 left) - mic1 */ /* channel 1 (serilizer 1 right) - mic2 */ /* channel 2 (serilizer 2 left) - mic5 */ /* channel 3 (serilizer 2 right) - mic6 */ /* channel 4 (serilizer 3 left) - mic3 */ /* channel 5 (serilizer 3 right) - mic4 */ /* channel 6 (serilizer 4 left) - mic8 */ /* channel 7 (serilizer 4 right) - mic7 */ int chanToMicMapping[8] = {0, 1, 4, 5, 3, 2, 7, 6}; /* Error flag */ uint32_t gblErrFlag = 0; Error_Block eb; /* External function declarations */ void GblErr(int arg); signed char* getGlobalAddr(signed char* addr); #define TX_FIFO_EVENT_DMA_RATIO 1 #define RX_FIFO_EVENT_DMA_RATIO 1 /* McASP HW setup for receive */ Mcasp_HwSetupData mcaspRcvSetup = { /* .rmask = */ 0xFFFFFFFF, /* 16 bits are to be used */ /* .rfmt = */ 0x000180F0, /* * 1 bit delay from framesync * MSB first * No extra bit padding * Padding bit (ignore) * slot Size is 32 * Reads from DMA port * NO rotation */ /* .afsrctl = */ 0X00000111, /* I2S mode - 2 slot TDM * Frame sync is one word * Externally generated frame sync * Falling 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 = */ 0x00000080, /* Bit CLK Pol: falling edge, ACLKR is external */ /* .ahclkrctl = */ 0x00000000, /* AHCLKR is external */ /* .rclkchk = */ 0x00000000 } }; /* McASP HW setup for transmit */ #if (CMB_AUDIO_DAC) Mcasp_HwSetupData mcaspXmtSetup = { /* .xmask = */ 0xFFFFFFFF, /* 16 bits are to be used */ /* .xfmt = */ 0x000180F0, /* * 1 bit delay from framesync * MSB first * No extra bit padding * Padding bit (ignore) * slot Size is 32 * Reads from DMA port * NO rotation */ /* .afsxctl = */ 0x00000113, /* I2S mode - 2 slot TDM * Frame sync is one word * Falling edge is start of frame * Externally 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 = */ 0X000000E3, /* Bit CLK Pol: falling edge, ASYNC is 1, ACLKX is internal, HF CLK to BCLK divider is 4 */ /* .ahclkxctl = */ 0x00000000, /* AHCLKX is external */ /* .xclkchk = */ 0x00000000 }, }; #endif /* McAsp channel parameters for receive */ Mcasp_ChanParams mcaspRxChanParam = { 0x0004, /* number of serializers */ {Mcasp_SerializerNum_0, Mcasp_SerializerNum_1, Mcasp_SerializerNum_2, Mcasp_SerializerNum_3 }, /* 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, RX_FIFO_EVENT_DMA_RATIO, TRUE, Mcasp_WordBitsSelect_LSB }; #if (CMB_AUDIO_DAC) /* 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, TX_FIFO_EVENT_DMA_RATIO, TRUE, Mcasp_WordBitsSelect_LSB }; #endif #if (SYS_USE_DRC) /* Output frame for MSS, input for DRC */ #pragma DATA_ALIGN(txOutFrame1,8) linSample txOutFrame1[SYS_FRAME_LENGTH]; /* Output frame for DRC, input for VAU */ #pragma DATA_ALIGN(txOutFrame2,8) linSample txOutFrame2[SYS_FRAME_LENGTH]; #endif typedef struct txBfDebug_stc { tulong frmcnt; /* normal frames */ tulong silcnt; /* silence frames */ tuint invsrc; /* no mic active, invalid output */ tuint invopt; /* >1 mic active, invalid output */ } txBfDebug_t; typedef struct txTaskDebug_stc { tuint overrun; /* counts how many times we ran out of MIPS */ txBfDebug_t bf[SYS_VMICS_MAX]; /* beamformer statistics */ } txTaskDebug_t; txTaskDebug_t txTaskDebug; /* Tx task debug stats */ /* Profiling/benchmarking information for the Tx task */ typedef struct txTaskProfileData_stc { tulong min; /* Minimum number of cycles */ tulong max; /* Maximum number of cycles */ tulong n; /* Number of measurements */ float total; /* Total number of cycles */ } txTaskProfileData_t; typedef struct txTaskProfile_stc { txTaskProfileData_t bf; /* Beamformer profile */ txTaskProfileData_t asnr; /* ASNR profile */ txTaskProfileData_t mss; /* MSS profile */ txTaskProfileData_t drc; /* DRC profile */ txTaskProfileData_t vau; /* VAU profile */ } txTaskProfile_t; volatile txTaskProfile_t txTaskProfile = { {~(0uL), 0, 0, 0.0f}, {~(0uL), 0, 0, 0.0f}, {~(0uL), 0, 0, 0.0f}, {~(0uL), 0, 0, 0.0f}, {~(0uL), 0, 0, 0.0f} }; /* To be used for debug trace */ mssSrc_t mssDbgCurSrc = { -1, -1 /* Current source group/index */ }; mssSrc_t mssDbgNewSrc = { -1, -1 /* New source group/index */ }; /* Handle to eDMA */ extern EDMA3_DRV_Handle hEdma1; /** * \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 Cmb_EOK on Success or error code */ Cmb_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); /* 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(cmb_write("\r\nMEM_calloc failed for Rx\n")); IFPRINT(UART_printf("\r\nMEM_calloc failed for Rx\n")); } } /* Allocate work buffers for signal processing */ for(count = 0; count < NUM_BUFS; count++) { wkBuf[count] = Memory_calloc(iheap, (BUFSIZE * RX_NUM_SERIALIZER/(SYS_FS_RATIO*2)), BUFALIGN, &eb); if(NULL == wkBuf[count]) { IFPRINT(cmb_write("\r\nMEM_calloc failed for Wk\n")); IFPRINT(UART_printf("\r\nMEM_calloc failed for Wk\n")); } } #if (CMB_AUDIO_DAC) /* 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(cmb_write("\r\nMEM_calloc failed for Tx\n")); IFPRINT(UART_printf("\r\nMEM_calloc failed for Tx\n")); } } /* Allocate output buffers for the MSS */ for(count = 0; count < NUM_BUFS; count++) { outBuf[count] = Memory_calloc(iheap, (BUFSIZE * TX_NUM_SERIALIZER/(SYS_FS_RATIO*2*2)), BUFALIGN, &eb); if(NULL == outBuf[count]) { IFPRINT(cmb_write("\r\nMEM_calloc failed for Out\n")); IFPRINT(UART_printf("\r\nMEM_calloc failed for Out\n")); } } #endif for(count = 0; count < NUM_BUFS; count++) { /* Issue the first & second empty buffers to the input stream */ memset((uint8_t *)rxBuf[count], 0xAA, (BUFSIZE * RX_NUM_SERIALIZER)); memset((uint8_t *)wkBuf[count], 0xBB, (BUFSIZE * RX_NUM_SERIALIZER/(SYS_FS_RATIO*2))); /* RX frame processing */ rxFrame[count].cmd = MCASP_READ; rxFrame[count].addr = (void*)(getGlobalAddr(rxBuf[count])); rxFrame[count].size = BUFSIZE * RX_NUM_SERIALIZER; 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(cmb_write("mcaspSubmitChan for Rx Failed\n")); IFPRINT(UART_printf("mcaspSubmitChan for Rx Failed\n")); return (Cmb_EFAIL); } } #if (CMB_AUDIO_DAC) for(count = 0; count < NUM_BUFS; count++) { memset((uint8_t *)txBuf[count], 0xCC, (BUFSIZE * TX_NUM_SERIALIZER)); memset((uint8_t *)outBuf[count], 0xDD, (BUFSIZE * TX_NUM_SERIALIZER/(3*2*2))); /* TX frame processing */ txFrame[count].cmd = MCASP_WRITE; txFrame[count].addr = (void*)(getGlobalAddr(txBuf[count])); txFrame[count].size = BUFSIZE * TX_NUM_SERIALIZER; 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(cmb_write("mcaspSubmitChan for Tx Failed\n")); IFPRINT(UART_printf("mcaspSubmitChan for Tx Failed\n")); return (Cmb_EFAIL); } } #endif return (Cmb_EOK); } /** * \brief Configures McASP module and creates the channel * for audio Tx and Rx * * \return Cmb_EOK on Success or error code */ Cmb_STATUS mcaspAudioConfig(void) { Int status; #if (CMB_AUDIO_DAC) hMcaspDevTx = NULL; hMcaspTxChan = NULL; #endif hMcaspDevRx = NULL; hMcaspRxChan = NULL; /* Initialize McASP Tx and Rx parameters */ #if (CMB_AUDIO_DAC) mcaspTxParams = Mcasp_PARAMS; #endif mcaspRxParams = Mcasp_PARAMS; #if (CMB_AUDIO_DAC) mcaspTxParams.mcaspHwSetup.tx.clk.clkSetupClk = 0x63; mcaspTxParams.mcaspHwSetup.rx.clk.clkSetupClk = 0x23; #endif mcaspRxParams.mcaspHwSetup.rx.clk.clkSetupClk = 0x23; mcaspRxParams.mcaspHwSetup.tx.clk.clkSetupClk = 0x63; #if (CMB_AUDIO_DAC) mcaspTxParams.mcaspHwSetup.glb.pdir |= 0x2000000; //Set Amute pin as output for Tx channel #endif /* Initialize eDMA handle */ mcaspRxChanParam.edmaHandle = hEdma1; #if (CMB_AUDIO_DAC) mcaspTxChanParam.edmaHandle = hEdma1; /* Bind McASP2 for Tx */ status = mcaspBindDev(&hMcaspDevTx, CSL_MCASP_2, &mcaspTxParams); if((status != MCASP_COMPLETED) || (hMcaspDevTx == NULL)) { IFPRINT(cmb_write("mcaspBindDev for Tx Failed\n")); IFPRINT(UART_printf("mcaspBindDev for Tx Failed\n")); return (Cmb_EFAIL); } #endif /* Bind McASP1 for Rx */ status = mcaspBindDev(&hMcaspDevRx, CSL_MCASP_1, &mcaspRxParams); if((status != MCASP_COMPLETED) || (hMcaspDevRx == NULL)) { IFPRINT(cmb_write("mcaspBindDev for Rx Failed\n")); IFPRINT(UART_printf("mcaspBindDev for Rx Failed\n")); return (Cmb_EFAIL); } #if (CMB_AUDIO_DAC) /* Create McASP channel for Tx */ status = mcaspCreateChan(&hMcaspTxChan, hMcaspDevTx, MCASP_OUTPUT, &mcaspTxChanParam, mcaspAppCallback, &txChanMode); if((status != MCASP_COMPLETED) || (hMcaspTxChan == NULL)) { IFPRINT(cmb_write("mcaspCreateChan for Tx Failed\n")); IFPRINT(UART_printf("mcaspCreateChan for Tx Failed\n")); return (Cmb_EFAIL); } configAudioDAC(); #endif /* Create McASP channel for Rx */ status = mcaspCreateChan(&hMcaspRxChan, hMcaspDevRx, MCASP_INPUT, &mcaspRxChanParam, mcaspAppCallback, &rxChanMode); if((status != MCASP_COMPLETED) || (hMcaspRxChan == NULL)) { IFPRINT(cmb_write("mcaspCreateChan for Rx Failed\n")); IFPRINT(UART_printf("mcaspCreateChan for Rx Failed\n")); return (Cmb_EFAIL); } /* Initialize the buffers and submit for McASP Tx/Rx */ if(initBuffers() != Cmb_EOK) { IFPRINT(cmb_write("McASP Buffer Initialization Failed\n")); IFPRINT(UART_printf("McASP Buffer Initialization Failed\n")); return (Cmb_EFAIL); } return (Cmb_EOK); } /** * \brief Function to exit the test * * \return None */ void testRet(uint32_t status) { cmb_write("\n\nAudio DC Analog Interface Test Completed!\n"); UART_printf("\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 Cmb_EOK on Success or error code */ #define DUMP_SEC 5 #define FRAME_PER_SEC 100 int gAudDumpBufIdx = 0; unsigned char gAudDumpBuf[(BUFSIZE*RX_NUM_SERIALIZER)*FRAME_PER_SEC*DUMP_SEC]; unsigned char gAudOutDumpBuf[(BUFSIZE*TX_NUM_SERIALIZER)*FRAME_PER_SEC*DUMP_SEC]; Void Audio_echo_Task(void) { int32_t i, j, k; unsigned char *tempTxPtr, *tempRxPtr, *tempWkPtr; unsigned char *tempOutPtr, *tempMicPtr; tint nmics, nvmics, err, angle; volatile tulong t1, t2; /* for profiling */ tulong delta; void *inst_p; linSample *in_r; /* pointer to current microphone input buffer */ linSample *frame_p; /* pointer to signal frame */ linSample *outframe_p; /* Output frame pointer for VAU */ linSample *mics_in[SYS_MICS_MAX+1]; /* pointers to microphone inputs */ mssDebugStat_t mssDbg; Semaphore_Params_init(¶ms); /* Create semaphores to wait for buffer reclaiming */ semR = Semaphore_create(0, ¶ms, &eb); semT = Semaphore_create(0, ¶ms, &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); #if (CMB_AUDIO_DAC) Semaphore_pend(semT, BIOS_WAIT_FOREVER); #endif /* Reclaim full buffer from the input stream */ #if (CMB_AUDIO_DAC) gtxFrameIndexCount = txFrameIndex; #endif grxFrameIndexCount = rxFrameIndex; #if (CMB_AUDIO_DAC) #if 0 // Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1 // copy RX mic 1 to TX left channel and RX mic 5 to right channel // set the RX pointer to mic 1 tempRxPtr = (uint32_t *)rxBuf[grxFrameIndexCount]; // set the TX pointer to left cahhnel tempTxPtr = (uint32_t *)txBuf[gtxFrameIndexCount]; // copy RX mic 1 to TX left channel for (i=0; i