/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright 2016-2020 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "sai.h" #include "pin_mux.h" #include "clock_config.h" #include "board.h" #include "fsl_codec_common.h" #include "fsl_wm8960.h" #include "fsl_codec_adapter.h" #include "fsl_dmamux.h" #include "drvTlv6410.h" #include "music.h" #include "levelcontrol_interface.h" #include "hpf_interface.h" #define HPF_ENABLE (0) #define LEVELCTL_ENABLE (1) T_LEVELCONTROLParam *pInputLevelCtl; T_HPFParam *pHpfParam; char (*pInputHPFHistBuff)[HPF_GLOBST_LEN]; typedef struct _SaiContext { xTaskHandle taskHandle; MessageHandle msgHandle; MessageHandle parentMsgHandle; }SaiContext; static SaiContext SaiCt; /* SAI instance and clock */ #define DEMO_CODEC_WM8960 #define DEMO_SAI SAI1 #define DEMO_SAI_CHANNEL (0) #define DEMO_SAI_IRQ SAI1_IRQn #define DEMO_SAITxIRQHandler SAI1_IRQHandler #define DEMO_SAI_TX_SYNC_MODE kSAI_ModeAsync #define DEMO_SAI_RX_SYNC_MODE kSAI_ModeSync #define DEMO_SAI_TX_BIT_CLOCK_POLARITY kSAI_PolarityActiveLow #define DEMO_SAI_MCLK_OUTPUT true #define DEMO_SAI_MASTER_SLAVE kSAI_Master #define DEMO_AUDIO_DATA_CHANNEL (4U) #define DEMO_AUDIO_BIT_WIDTH kSAI_WordWidth32bits #define DEMO_AUDIO_SAMPLE_RATE (kSAI_SampleRate48KHz) #define DEMO_AUDIO_MASTER_CLOCK DEMO_SAI_CLK_FREQ /* IRQ */ #define DEMO_SAI_TX_IRQ SAI1_IRQn #define DEMO_SAI_RX_IRQ SAI1_IRQn /* DMA */ #define DEMO_DMA DMA0 #define DEMO_DMAMUX DMAMUX #define DEMO_TX_EDMA_CHANNEL (0U) #define DEMO_RX_EDMA_CHANNEL (1U) #define DEMO_SAI_TX_SOURCE kDmaRequestMuxSai1Tx #define DEMO_SAI_RX_SOURCE kDmaRequestMuxSai1Rx /* Select Audio/Video PLL (786.48 MHz) as sai1 clock source */ #define DEMO_SAI1_CLOCK_SOURCE_SELECT (2U) /* Clock pre divider for sai1 clock source */ #define DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER (0U) /* Clock divider for sai1 clock source */ #define DEMO_SAI1_CLOCK_SOURCE_DIVIDER (63U) /* Get frequency of sai1 clock */ #define DEMO_SAI_CLK_FREQ \ (CLOCK_GetFreq(kCLOCK_AudioPllClk) / (DEMO_SAI1_CLOCK_SOURCE_DIVIDER + 1U) / \ (DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER + 1U)) /* I2C instance and clock */ #define DEMO_I2C LPI2C1 /* Select USB1 PLL (480 MHz) as master lpi2c clock source */ #define DEMO_LPI2C_CLOCK_SOURCE_SELECT (0U) /* Clock divider for master lpi2c clock source */ #define DEMO_LPI2C_CLOCK_SOURCE_DIVIDER (5U) /* Get frequency of lpi2c clock */ #define DEMO_I2C_CLK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (DEMO_LPI2C_CLOCK_SOURCE_DIVIDER + 1U)) #define BOARD_MASTER_CLOCK_CONFIG() #define SIGLE_SAMPLE (DEMO_AUDIO_SAMPLE_RATE*4/1000)//4MS #define BUFFER_SIZE (SIGLE_SAMPLE*DEMO_AUDIO_DATA_CHANNEL*4)//48*4=192 192*4byte*4ch = 3072 #define BUFFER_NUMBER (4U) #ifndef DEMO_CODEC_VOLUME #define DEMO_CODEC_VOLUME 100U #endif /******************************************************************************* * Prototypes ******************************************************************************/ #define MAX_32 (int)0x7FFFFFFFL #define MIN_32 (int)0x80000000L /******************************************************************************* * Variables ******************************************************************************/ wm8960_config_t wm8960Config = { .i2cConfig = {.codecI2CInstance = BOARD_CODEC_I2C_INSTANCE, .codecI2CSourceClock = BOARD_CODEC_I2C_CLOCK_FREQ}, .route = kWM8960_RoutePlaybackandRecord, .leftInputSource = kWM8960_InputDifferentialMicInput3, .rightInputSource = kWM8960_InputDifferentialMicInput2, .playSource = kWM8960_PlaySourceDAC, .slaveAddress = WM8960_I2C_ADDR, .bus = kWM8960_BusI2S, .format = {.mclk_HZ = 6144000U * 2, .sampleRate = kWM8960_AudioSampleRate16KHz, .bitWidth = kWM8960_AudioBitWidth16bit}, .master_slave = false, }; codec_config_t boardCodecConfig = {.codecDevType = kCODEC_WM8960, .codecDevConfig = &wm8960Config}; /* * AUDIO PLL setting: Frequency = Fref * (DIV_SELECT + NUM / DENOM) * = 24 * (32 + 77/100) * = 786.48 MHz */ const clock_audio_pll_config_t audioPllConfig = { .loopDivider = 32, /* PLL loop divider. Valid range for DIV_SELECT divider value: 27~54. */ .postDivider = 1, /* Divider after the PLL, should only be 1, 2, 4, 8, 16. */ .numerator = 77, /* 30 bit numerator of fractional loop divider. */ .denominator = 100, /* 30 bit denominator of fractional loop divider */ }; AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t Buffer[BUFFER_NUMBER * BUFFER_SIZE], 4); AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t BufferPro[BUFFER_NUMBER * BUFFER_SIZE], 4); AT_QUICKACCESS_SECTION_DATA(sai_edma_handle_t txHandle); AT_QUICKACCESS_SECTION_DATA(sai_edma_handle_t rxHandle); static uint32_t tx_index = 0U, rx_index = 0U, cp_index = 0; volatile int emptyBlock = BUFFER_NUMBER; edma_handle_t dmaTxHandle = {0}, dmaRxHandle = {0}; extern codec_config_t boardCodecConfig; codec_handle_t codecHandle; bool rx_callback_finish = true; bool tx_callback_finish = true; SemaphoreHandle_t xMutex; /******************************************************************************* * Code ******************************************************************************/ int L_shr (int L_var1, short var2); int L_shl (int L_var1, short var2); int L_shl (int L_var1, short var2) { int L_var_out = 0L; if (var2 <= 0) { if (var2 < -32) { var2 = -32; } L_var_out = L_shr (L_var1, (short)-var2); } else { for (; var2 > 0; var2--) { if (L_var1 > (int) 0X3fffffffL) { L_var_out = MAX_32; break; } else { if (L_var1 < (int) 0xc0000000L) { L_var_out = MIN_32; break; } } L_var1 *= 2; L_var_out = L_var1; } } return (L_var_out); } int L_shr (int L_var1, short var2) { int L_var_out; if (var2 < 0) { if (var2 < -32) { var2 = -32; } L_var_out = L_shl (L_var1, (short)-var2); } else { if (var2 >= 31) { L_var_out = (L_var1 < 0L) ? -1 : 0; } else { if (L_var1 < 0) { L_var_out = ~((~L_var1) >> var2); } else { L_var_out = L_var1 >> var2; } } } return (L_var_out); } void BOARD_EnableSaiMclkOutput(bool enable) { if (enable) { IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK; } else { IOMUXC_GPR->GPR1 &= (~IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK); } } static void rx_callback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData) { if (kStatus_SAI_RxError == status) { /* Handle the error. */ } else { // PRINTF("RX status1=%d\r\n", status); // if (xSemaphoreTake(xMutex, portMAX_DELAY) != pdTRUE) // { // PRINTF("Failed to take semaphore.\r\n"); // } // PRINTF("RX status2=%d\r\n", status); // memcpy(BufferPro + cp_index*BUFFER_SIZE, Buffer + cp_index*BUFFER_SIZE, BUFFER_SIZE); // xSemaphoreGive(xMutex); // if (++cp_index == BUFFER_NUMBER) // { // cp_index = 0U; // } emptyBlock--; rx_callback_finish = true; //PRINTF("RX status=%d\r\n", status); } } static void tx_callback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData) { //PRINTF("TX status=%d\r\n", status); if (kStatus_SAI_TxError == status) { /* Handle the error. */ } else { emptyBlock++; tx_callback_finish = true; //PRINTF("TX status=%d\r\n", status); } } int AlgorithmInit() { int ret = 0; pInputLevelCtl = (T_LEVELCONTROLParam *)pvPortMalloc(sizeof(T_LEVELCONTROLParam)*DEMO_AUDIO_DATA_CHANNEL); pHpfParam = (T_HPFParam *)pvPortMalloc(sizeof(T_HPFParam)*DEMO_AUDIO_DATA_CHANNEL); for(int i = 0; i < DEMO_AUDIO_DATA_CHANNEL; i++) { pHpfParam[i].pChannelStAddr = &pInputHPFHistBuff[i]; pHpfParam[i].wChnSize = HPF_GLOBST_LEN; pHpfParam[i].wParamsize = (short)sizeof(T_HPFParam); pHpfParam[i].wCutOffFreq = 150; pHpfParam[i].cSamplingRate = HPF_SAMPLINGRATE_48K; pHpfParam[i].cHPF_Opt = 1; ret = HPF_Init(&pHpfParam[i]); PRINTF("HPF_Init Opt=%d, freq=%d, return %d\r\n", pHpfParam[i].cHPF_Opt, pHpfParam[i].wCutOffFreq, ret); } for(int i = 0; i < DEMO_AUDIO_DATA_CHANNEL; i++) { pInputLevelCtl[i].cMuteFlag = 0; pInputLevelCtl[i].wParamsize = (short)sizeof(T_LEVELCONTROLParam); pInputLevelCtl[i].wGainDB = -6; pInputLevelCtl[i].cSamplingRate= LEVELCONTROL_SAMPLINGRATE_48K; PRINTF("input LevelCtl cMuteFlag=%d, wGainDB=%.1f\r\n", pInputLevelCtl[i].cMuteFlag, pInputLevelCtl[i].wGainDB); } return 0; } /*! * @brief Main function */ void SaiTask(void *arg) { sai_transfer_t xfer, send_xfer; edma_config_t dmaConfig = {0}; sai_transceiver_t saiConfig; // BOARD_ConfigMPU(); // BOARD_InitBootPins(); // BOARD_InitBootClocks(); // BOARD_InitDebugConsole(); CLOCK_InitAudioPll(&audioPllConfig); /*Clock setting for LPI2C*/ CLOCK_SetMux(kCLOCK_Lpi2cMux, DEMO_LPI2C_CLOCK_SOURCE_SELECT); CLOCK_SetDiv(kCLOCK_Lpi2cDiv, DEMO_LPI2C_CLOCK_SOURCE_DIVIDER); /*Clock setting for SAI1*/ CLOCK_SetMux(kCLOCK_Sai1Mux, DEMO_SAI1_CLOCK_SOURCE_SELECT); CLOCK_SetDiv(kCLOCK_Sai1PreDiv, DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER); CLOCK_SetDiv(kCLOCK_Sai1Div, DEMO_SAI1_CLOCK_SOURCE_DIVIDER); /*Enable MCLK clock*/ BOARD_EnableSaiMclkOutput(true); /* Init DMAMUX */ DMAMUX_Init(DEMO_DMAMUX); DMAMUX_SetSource(DEMO_DMAMUX, DEMO_TX_EDMA_CHANNEL, (uint8_t)DEMO_SAI_TX_SOURCE); DMAMUX_EnableChannel(DEMO_DMAMUX, DEMO_TX_EDMA_CHANNEL); DMAMUX_SetSource(DEMO_DMAMUX, DEMO_RX_EDMA_CHANNEL, (uint8_t)DEMO_SAI_RX_SOURCE); DMAMUX_EnableChannel(DEMO_DMAMUX, DEMO_RX_EDMA_CHANNEL); PRINTF("SAI example started!DEMO_SAI_CLK_FREQ=%d\n\r",DEMO_SAI_CLK_FREQ); /* Init DMA and create handle for DMA */ EDMA_GetDefaultConfig(&dmaConfig); EDMA_Init(DEMO_DMA, &dmaConfig); EDMA_CreateHandle(&dmaTxHandle, DEMO_DMA, DEMO_TX_EDMA_CHANNEL); EDMA_CreateHandle(&dmaRxHandle, DEMO_DMA, DEMO_RX_EDMA_CHANNEL); #if defined(FSL_FEATURE_EDMA_HAS_CHANNEL_MUX) && FSL_FEATURE_EDMA_HAS_CHANNEL_MUX EDMA_SetChannelMux(DEMO_DMA, DEMO_TX_EDMA_CHANNEL, DEMO_SAI_TX_EDMA_CHANNEL); EDMA_SetChannelMux(DEMO_DMA, DEMO_RX_EDMA_CHANNEL, DEMO_SAI_RX_EDMA_CHANNEL); #endif /* SAI init */ SAI_Init(DEMO_SAI); SAI_TransferTxCreateHandleEDMA(DEMO_SAI, &txHandle, tx_callback, NULL, &dmaTxHandle); SAI_TransferRxCreateHandleEDMA(DEMO_SAI, &rxHandle, rx_callback, NULL, &dmaRxHandle); /* I2S mode configurations */ //SAI_GetClassicI2SConfig(&saiConfig, DEMO_AUDIO_BIT_WIDTH, kSAI_Stereo, 1U << DEMO_SAI_CHANNEL); SAI_GetTDMConfig(&saiConfig, kSAI_FrameSyncLenOneBitClk, DEMO_AUDIO_BIT_WIDTH, DEMO_AUDIO_DATA_CHANNEL, 1); //saiConfig.frameSync.frameSyncEarly = true; saiConfig.syncMode = DEMO_SAI_TX_SYNC_MODE; //saiConfig.bitClock.bclkPolarity = DEMO_SAI_TX_BIT_CLOCK_POLARITY; saiConfig.masterSlave = DEMO_SAI_MASTER_SLAVE; SAI_TransferTxSetConfigEDMA(DEMO_SAI, &txHandle, &saiConfig); saiConfig.syncMode = DEMO_SAI_RX_SYNC_MODE; SAI_TransferRxSetConfigEDMA(DEMO_SAI, &rxHandle, &saiConfig); /* set bit clock divider */ SAI_TxSetBitClockRate(DEMO_SAI, DEMO_AUDIO_MASTER_CLOCK, DEMO_AUDIO_SAMPLE_RATE, DEMO_AUDIO_BIT_WIDTH, DEMO_AUDIO_DATA_CHANNEL); SAI_RxSetBitClockRate(DEMO_SAI, DEMO_AUDIO_MASTER_CLOCK, DEMO_AUDIO_SAMPLE_RATE, DEMO_AUDIO_BIT_WIDTH, DEMO_AUDIO_DATA_CHANNEL); /* master clock configurations */ BOARD_MASTER_CLOCK_CONFIG(); tlv6410_i2c_init(); tlv6410_config(); tlv6410_Status(); short nRet = 0; short globalOutSize = SIGLE_SAMPLE; // pMic = (int *)pvPortMalloc(BUFFER_SIZE); // pTemp = (int *)pvPortMalloc(BUFFER_SIZE); int pMic[BUFFER_SIZE/4]; int pTemp[BUFFER_SIZE/4]; int pswp[BUFFER_SIZE/4]; int c=0; uint8_t sendbuff[BUFFER_SIZE] = {0}; send_xfer.data = sendbuff; send_xfer.dataSize = BUFFER_SIZE; AlgorithmInit(); while (1) { if (rx_callback_finish) { //PRINTF("emptyBlock1=%d\r\n",emptyBlock); rx_callback_finish = false; xfer.data = Buffer + rx_index * BUFFER_SIZE; xfer.dataSize = BUFFER_SIZE; if (kStatus_Success == SAI_TransferReceiveEDMA(DEMO_SAI, &rxHandle, &xfer)) { rx_index++; } if (rx_index == BUFFER_NUMBER) { rx_index = 0U; } } if (tx_callback_finish) { tx_callback_finish = false; xfer.data = Buffer + tx_index * BUFFER_SIZE; xfer.dataSize = BUFFER_SIZE; #if 1 // xSemaphoreTake(xMutex, portMAX_DELAY); // PRINTF("emptyBlock2-2=%d\r\n",emptyBlock); // xSemaphoreGive(xMutex); memcpy(pTemp, xfer.data, BUFFER_SIZE); for(int i=0; i>1; // pMic[j*SIGLE_SAMPLE + i] = pMic[j*SIGLE_SAMPLE + i]&0x7fffffff|c|0x01; if(pMic[j*SIGLE_SAMPLE + i] != pswp[j*SIGLE_SAMPLE + i]) PRINTF("%08X %08X \r\n", pMic[j*SIGLE_SAMPLE + i],pswp[j*SIGLE_SAMPLE + i]); } } #endif for(int i=0; i