/*
 * Copyright 2025 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */


/*******************************************************************************
 * Includes
 ******************************************************************************/

#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "board.h"
#include "fsl_dma.h"
#include "fsl_i2c.h"
#include "fsl_i2s.h"
#include "fsl_i2s_dma.h"
#include "fsl_codec_common.h"

#include "fsl_sysctl.h"
#include "fsl_wm8904.h"
#include "fsl_codec_adapter.h"
#include "fsl_power.h"

#include "Config.h"
#include "Sweep.h"
#include "FastMath.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/


#define DEMO_I2C                        (I2C4)
#define DEMO_I2S_MASTER_CLOCK_FREQUENCY (24576000)

#define DEMO_DMA                        (DMA0)

#define DEMO_I2S_TX_ToCodec             (I2S7)
#define DEMO_I2S_TX_ToExtern            (I2S1)
//#define DEMO_I2S_RX                   (I2S6)		//change to I2S2, because Rx data is to be from extern
#define DEMO_I2S_RX                     (I2S2)

#define DEMO_I2S_TX_ToCodec_CHANNEL     (19)
#define DEMO_I2S_TX_ToExtern_CHANNEL    (7)
//#define DEMO_I2S_RX_CHANNEL           (16)
#define DEMO_I2S_RX_CHANNEL             (10)

#define DEMO_AUDIO_BIT_WIDTH            (32)

#if (GeneratingToneMode==1)||(GeneratingToneMode==2)
	#define DEMO_I2S_CLOCK_DIVIDER          (CLOCK_GetPll0OutFreq() / 48000U / DEMO_AUDIO_BIT_WIDTH / 2U)
#endif
#if GeneratingToneMode==3
	#define DEMO_I2S_CLOCK_DIVIDER          (CLOCK_GetPll0OutFreq() / 16000U / DEMO_AUDIO_BIT_WIDTH / 2U)
#endif

#define DEMO_I2S_TX_ToCodec_MODE                (kI2S_MasterSlaveNormalMaster)
#define DEMO_I2S_TX_ToExtern_MODE               (kI2S_MasterSlaveNormalSlave)
#define DEMO_I2S_RX_MODE                		(kI2S_MasterSlaveNormalSlave)


#define DEMO_AUDIO_SAMPLE_RATE          (48000)
#define DEMO_AUDIO_PROTOCOL             kCODEC_BusI2S
#ifndef DEMO_CODEC_VOLUME
#define DEMO_CODEC_VOLUME 60U
#endif

#define AudioFrameLengthInSamples		48

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

static void StartI2SAudioIO(void);

static void TxToCodecCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData);
static void TxToExternCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData);
static void RxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData);

/*******************************************************************************
 * Variables
 ******************************************************************************/
wm8904_config_t wm8904Config = {
    .i2cConfig    = {.codecI2CInstance = BOARD_CODEC_I2C_INSTANCE, .codecI2CSourceClock = BOARD_CODEC_I2C_CLOCK_FREQ},
    .recordSource = kWM8904_RecordSourceLineInput,
    .recordChannelLeft  = kWM8904_RecordChannelLeft2,
    .recordChannelRight = kWM8904_RecordChannelRight2,
    .playSource         = kWM8904_PlaySourceDAC,
    .slaveAddress       = WM8904_I2C_ADDRESS,
    .protocol           = kWM8904_ProtocolI2S,
    .format             = {.sampleRate = kWM8904_SampleRate48kHz, .bitWidth = kWM8904_BitWidth32},
    .mclk_HZ            = DEMO_I2S_MASTER_CLOCK_FREQUENCY,
    .master             = false,
};
codec_config_t boardCodecConfig = {.codecDevType = kCODEC_WM8904, .codecDevConfig = &wm8904Config};

static dma_handle_t 	s_DmaTxHandle_ToCodec;
static i2s_config_t 	s_TxConfig_ToCodec;
static i2s_dma_handle_t s_TxHandle_ToCodec;
static i2s_transfer_t 	s_TxTransfer_ToCodec;

static dma_handle_t 	s_DmaTxHandle_ToExtern;
static i2s_config_t 	s_TxConfig_ToExtern;
static i2s_dma_handle_t s_TxHandle_ToExtern;
static i2s_transfer_t 	s_TxTransfer_ToExtern;

static dma_handle_t 	s_DmaRxHandle;
static i2s_config_t 	s_RxConfig;
static i2s_dma_handle_t s_RxHandle;
static i2s_transfer_t 	s_RxTransfer;


extern codec_config_t boardCodecConfig;
codec_handle_t codecHandle;

int I2STxBufToCodecA [AudioFrameLengthInSamples*2]; //ping buffer for tx I2S audio to codec, L R mixed/interleaved
int I2STxBufToCodecB [AudioFrameLengthInSamples*2]; //pong buffer for tx I2S audio to codec, L R mixed/interleaved
int I2STxBufToExternA[AudioFrameLengthInSamples*2]; //ping buffer for tx I2S audio to extern, L R mixed/interleaved
int I2STxBufToExternB[AudioFrameLengthInSamples*2]; //pong buffer for tx I2S audio to extern, L R mixed/interleaved
int I2SRxBufA        [AudioFrameLengthInSamples*2]; //ping buffer for rx I2S audio from extern, L R mixed/interleaved
int I2SRxBufB        [AudioFrameLengthInSamples*2]; //pong buffer for rx I2S audio from extern, L R mixed/interleaved

/*******************************************************************************
 * Code
 ******************************************************************************/
void BOARD_InitSysctrl(void)
{
    SYSCTL_Init(SYSCTL);
    /* select signal source for share set */
    SYSCTL_SetShareSignalSrc(SYSCTL, kSYSCTL_ShareSet0, kSYSCTL_SharedCtrlSignalSCK, kSYSCTL_Flexcomm7);
    SYSCTL_SetShareSignalSrc(SYSCTL, kSYSCTL_ShareSet0, kSYSCTL_SharedCtrlSignalWS, kSYSCTL_Flexcomm7);
    /* select share set for special flexcomm signal */
    SYSCTL_SetShareSet(SYSCTL, kSYSCTL_Flexcomm1, kSYSCTL_FlexcommSignalSCK, kSYSCTL_ShareSet0);
    SYSCTL_SetShareSet(SYSCTL, kSYSCTL_Flexcomm1, kSYSCTL_FlexcommSignalWS, kSYSCTL_ShareSet0);
    SYSCTL_SetShareSet(SYSCTL, kSYSCTL_Flexcomm2, kSYSCTL_FlexcommSignalSCK, kSYSCTL_ShareSet0);
    SYSCTL_SetShareSet(SYSCTL, kSYSCTL_Flexcomm2, kSYSCTL_FlexcommSignalWS, kSYSCTL_ShareSet0);
}

#define     LedG_On                   GPIO_PinWrite(GPIO, 1, 7, 0)
#define     LedG_Off                  GPIO_PinWrite(GPIO, 1, 7, 1)


/*!
 * @brief Main function
 */
int main(void)
{
    /* set BOD VBAT level to 1.65V */
    POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
    CLOCK_EnableClock(kCLOCK_InputMux);
    CLOCK_EnableClock(kCLOCK_Iocon);
    CLOCK_EnableClock(kCLOCK_Gpio0);
    CLOCK_EnableClock(kCLOCK_Gpio1);


    /* USART0 clock */
    CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

    /* I2C clock */
    CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4);

    PMC->PDRUNCFGCLR0 |= PMC_PDRUNCFG0_PDEN_XTAL32M_MASK;   /*!< Ensure XTAL16M is on  */
    PMC->PDRUNCFGCLR0 |= PMC_PDRUNCFG0_PDEN_LDOXO32M_MASK;  /*!< Ensure XTAL16M is on  */
    SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /*!< Ensure CLK_IN is on  */
    ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK;

    /*!< Switch PLL0 clock source selector to XTAL16M */
    CLOCK_AttachClk(kEXT_CLK_to_PLL0);

    const pll_setup_t pll0Setup = {
        .pllctrl = SYSCON_PLL0CTRL_CLKEN_MASK | SYSCON_PLL0CTRL_SELI(2U) | SYSCON_PLL0CTRL_SELP(31U),


#if SetFsTo_24KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(250U),// --> Fs: 24KHz		 KHz
#endif
#if SetFsTo_25KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(240U),// --> Fs: 25KHz		 KHz
#endif
#if SetFsTo_33KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(182U),// --> Fs: 32.96703297 KHz
#endif
#if SetFsTo_47KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(127U),// --> Fs: 47.24409449 KHz
#endif
#if SetFsTo_48KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(125U),// --> Fs: 48			 KHz  --- this is original
		//.pllndec = SYSCON_PLL0NDEC_NDIV(126U),	//Fs: 48, change a little bit --- increase Fs by 1/125
		//.pllndec = SYSCON_PLL0NDEC_NDIV(124U),	//Fs: 48, change a little bit --- decrease Fs by 1/125
#endif
#if SetFsTo_97KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(62U),//	 --> Fs: 96.77419355 KHz
#endif
#if SetFsTo_150KHz==1
		.pllndec = SYSCON_PLL0NDEC_NDIV(40U),//	 --> Fs: 150		 KHz
#endif

        .pllpdec = SYSCON_PLL0PDEC_PDIV(8U),
        .pllsscg = {0x0U, (SYSCON_PLL0SSCG1_MDIV_EXT(3072U) | SYSCON_PLL0SSCG1_SEL_EXT_MASK)},
        .pllRate = 24576000U,
        .flags   = PLL_SETUPFLAG_WAITLOCK};
    /*!< Configure PLL to the desired values */
    CLOCK_SetPLL0Freq(&pll0Setup);

    CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 0U, true);
    CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 1U, false);

    /* I2S clocks */
    CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM1);
    CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM2);
    CLOCK_AttachClk(kPLL0_DIV_to_FLEXCOMM7);

    /* Attach PLL clock to MCLK for I2S, no divider */
    CLOCK_AttachClk(kPLL0_to_MCLK);
    SYSCON->MCLKDIV = SYSCON_MCLKDIV_DIV(0U);
    SYSCON->MCLKIO  = 1U;

    /* reset FLEXCOMM for I2C */
    RESET_PeripheralReset(kFC4_RST_SHIFT_RSTn);

    /* reset FLEXCOMM for DMA0 */
    RESET_PeripheralReset(kDMA0_RST_SHIFT_RSTn);

    /* reset FLEXCOMM for I2S */
    RESET_PeripheralReset(kFC1_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kFC2_RST_SHIFT_RSTn);
    RESET_PeripheralReset(kFC7_RST_SHIFT_RSTn);

    /* reset NVIC for FLEXCOMM6 and FLEXCOMM7 */
    NVIC_ClearPendingIRQ(FLEXCOMM1_IRQn);
    NVIC_ClearPendingIRQ(FLEXCOMM2_IRQn);
    NVIC_ClearPendingIRQ(FLEXCOMM7_IRQn);

    /* Enable interrupts for I2S */
    EnableIRQ(FLEXCOMM1_IRQn);
    EnableIRQ(FLEXCOMM2_IRQn);
    EnableIRQ(FLEXCOMM7_IRQn);

    /* Initialize the rest */
    BOARD_InitBootPins();
    BOARD_BootClockFROHF96M();
    BOARD_InitDebugConsole();
    BOARD_InitSysctrl();

	#if GeneratingToneMode==2
    	LedG_On;
		powFastCreate();				//initial fast math function  (fast power)
    	LedG_Off;
	#endif

	memset(I2STxBufToCodecA,0,sizeof(I2STxBufToCodecA));
	memset(I2STxBufToCodecB,0,sizeof(I2STxBufToCodecB));
	memset(I2STxBufToExternA,0,sizeof(I2STxBufToExternA));
	memset(I2STxBufToExternB,0,sizeof(I2STxBufToExternB));
	memset(I2SRxBufA,0,sizeof(I2SRxBufA));
	memset(I2SRxBufB,0,sizeof(I2SRxBufB));

	#if GeneratingToneMode==1
    	//Fs is set to 48KHz, fixed freq is the starting freq of SineToneGenerator
		//                                          Amplitude(),      FreqBeg,   FreqEnd,  Sweeping Duration,   Fs
		//                                       in between +/- 1      Hz          Hz            Sec            Hz
		InitSineToneGenerator(&SineToneGenerator,     0.99,          1111.0f,   2000.0f,       20.0f,        48000);
	#endif
	#if GeneratingToneMode==2
		//Fs is set to 16KHz, sweeping
		//                                          Amplitude(),      FreqBeg,   FreqEnd,  Sweeping Duration,   Fs
		//                                       in between +/- 1      Hz          Hz            Sec            Hz
		InitSineToneGenerator(&SineToneGenerator,     0.99,           20.0f,    16483.5f,       20.0f,        32967);
		//InitSineToneGenerator(&SineToneGenerator,     0.99,           20.0f,    24000.0f,       20.0f,        48000);
	#endif
	#if GeneratingToneMode==3
		//Fs is set to 16KHz, sweeping
		//                                          Amplitude(),      FreqBeg,   FreqEnd,  Sweeping Duration,   Fs
		//                                       in between +/- 1      Hz          Hz            Sec            Hz
		InitSineToneGenerator(&SineToneGenerator,     0.99,           20.0f,    8000.0f,       20.0f,        16000);
	#endif

    PRINTF("Configure codec\r\n");

    /* protocol: i2s
     * sampleRate: 48K
     * bitwidth:16
     */
    if (CODEC_Init(&codecHandle, &boardCodecConfig) != kStatus_Success)
    {
        PRINTF("codec_Init failed!\r\n");
        assert(false);
    }

    /* Initial volume kept low for hearing safety.
     * Adjust it to your needs, 0-100, 0 for mute, 100 for maximum volume.
     */
    if (CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight,
                        DEMO_CODEC_VOLUME) != kStatus_Success)
    {
        assert(false);
    }

    PRINTF("Configure I2S\r\n");


    /*
     * masterSlave = kI2S_MasterSlaveNormalMaster;
     * mode = kI2S_ModeI2sClassic;
     * rightLow = false;
     * leftJust = false;
     * pdmData = false;
     * sckPol = false;
     * wsPol = false;
     * divider = 1;
     * oneChannel = false;
     * dataLength = 32;
     * frameLength = 32*2;
     * position = 0;
     * watermark = 4;
     * txEmptyZero = true;
     * pack48 = false;
     */
    I2S_TxGetDefaultConfig(&s_TxConfig_ToCodec);
    s_TxConfig_ToCodec.divider     = DEMO_I2S_CLOCK_DIVIDER;
    s_TxConfig_ToCodec.masterSlave = DEMO_I2S_TX_ToCodec_MODE;
    s_TxConfig_ToCodec.dataLength  = DEMO_AUDIO_BIT_WIDTH;
    s_TxConfig_ToCodec.frameLength = DEMO_AUDIO_BIT_WIDTH * 2;
    I2S_TxInit(DEMO_I2S_TX_ToCodec, &s_TxConfig_ToCodec);

    /*
     * masterSlave = kI2S_MasterSlaveNormalSlave;
     * mode = kI2S_ModeI2sClassic;
     * rightLow = false;
     * leftJust = false;
     * pdmData = false;
     * sckPol = false;
     * wsPol = false;
     * divider = 1;
     * oneChannel = false;
     * dataLength = 32;
     * frameLength = 32*2;
     * position = 0;
     * watermark = 4;
     * txEmptyZero = true;
     * pack48 = false;
     */
    I2S_TxGetDefaultConfig(&s_TxConfig_ToExtern);
    s_TxConfig_ToExtern.divider     = DEMO_I2S_CLOCK_DIVIDER;
    s_TxConfig_ToExtern.masterSlave = DEMO_I2S_TX_ToExtern_MODE;
    s_TxConfig_ToExtern.dataLength  = DEMO_AUDIO_BIT_WIDTH;
    s_TxConfig_ToExtern.frameLength = DEMO_AUDIO_BIT_WIDTH * 2;
    I2S_TxInit(DEMO_I2S_TX_ToExtern, &s_TxConfig_ToExtern);

    /*
     * masterSlave = kI2S_MasterSlaveNormalSlave;
     * mode = kI2S_ModeI2sClassic;
     * rightLow = false;
     * leftJust = false;
     * pdmData = false;
     * sckPol = false;
     * wsPol = false;
     * divider = 1;
     * oneChannel = false;
     * dataLength = 32;
     * frameLength = 32*2;
     * position = 0;
     * watermark = 4;
     * txEmptyZero = false;
     * pack48 = true;
     */
    I2S_RxGetDefaultConfig(&s_RxConfig);
    s_RxConfig.divider     = DEMO_I2S_CLOCK_DIVIDER;
    s_RxConfig.masterSlave = DEMO_I2S_RX_MODE;
    s_RxConfig.dataLength  = DEMO_AUDIO_BIT_WIDTH;
    s_RxConfig.frameLength = DEMO_AUDIO_BIT_WIDTH * 2;
    I2S_RxInit(DEMO_I2S_RX, &s_RxConfig);

    DMA_Init(DEMO_DMA);

    DMA_EnableChannel(DEMO_DMA, DEMO_I2S_TX_ToCodec_CHANNEL);
    DMA_EnableChannel(DEMO_DMA, DEMO_I2S_TX_ToExtern_CHANNEL);
    DMA_EnableChannel(DEMO_DMA, DEMO_I2S_RX_CHANNEL);

    DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S_TX_ToCodec_CHANNEL, kDMA_ChannelPriority2);
    DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S_TX_ToExtern_CHANNEL, kDMA_ChannelPriority3);
    DMA_SetChannelPriority(DEMO_DMA, DEMO_I2S_RX_CHANNEL, kDMA_ChannelPriority4);

    DMA_CreateHandle(&s_DmaTxHandle_ToCodec, DEMO_DMA, DEMO_I2S_TX_ToCodec_CHANNEL);
    DMA_CreateHandle(&s_DmaTxHandle_ToExtern, DEMO_DMA, DEMO_I2S_TX_ToExtern_CHANNEL);
    DMA_CreateHandle(&s_DmaRxHandle, DEMO_DMA, DEMO_I2S_RX_CHANNEL);

    StartI2SAudioIO();

    while (1)
    {
    }
}

volatile int BufABSelect=0;
static void StartI2SAudioIO(void)
{
    PRINTF("Start I2S Audio IO\r\n");

    s_TxTransfer_ToCodec.data     = (uint8_t *)I2STxBufToCodecA;
    s_TxTransfer_ToCodec.dataSize = sizeof(I2STxBufToCodecA);
    I2S_TxTransferCreateHandleDMA(DEMO_I2S_TX_ToCodec, &s_TxHandle_ToCodec, &s_DmaTxHandle_ToCodec, TxToCodecCallback, (void *)&s_TxTransfer_ToCodec);

    s_TxTransfer_ToExtern.data     = (uint8_t *)I2STxBufToExternA;
    s_TxTransfer_ToExtern.dataSize = sizeof(I2STxBufToExternA);
    I2S_TxTransferCreateHandleDMA(DEMO_I2S_TX_ToExtern, &s_TxHandle_ToExtern, &s_DmaTxHandle_ToExtern, TxToExternCallback, (void *)&s_TxTransfer_ToExtern);

    s_RxTransfer.data     = (uint8_t *)I2SRxBufA;
    s_RxTransfer.dataSize = sizeof(I2SRxBufA);
    I2S_RxTransferCreateHandleDMA(DEMO_I2S_RX, &s_RxHandle, &s_DmaRxHandle, RxCallback, (void *)&s_RxTransfer);

    /* need to queue two transmit buffers so when the first one
     * finishes transfer, the other immediatelly starts */
    I2S_TxTransferSendDMA(DEMO_I2S_TX_ToCodec, &s_TxHandle_ToCodec, s_TxTransfer_ToCodec);
    I2S_TxTransferSendDMA(DEMO_I2S_TX_ToCodec, &s_TxHandle_ToCodec, s_TxTransfer_ToCodec);

    /* need to queue two transmit buffers so when the first one
     * finishes transfer, the other immediatelly starts */
    I2S_TxTransferSendDMA(DEMO_I2S_TX_ToExtern, &s_TxHandle_ToExtern, s_TxTransfer_ToExtern);
    I2S_TxTransferSendDMA(DEMO_I2S_TX_ToExtern, &s_TxHandle_ToExtern, s_TxTransfer_ToExtern);

    /* need to queue two receive buffers so when the first one is filled,
     * the other is immediatelly starts to be filled */
    I2S_RxTransferReceiveDMA(DEMO_I2S_RX, &s_RxHandle, s_RxTransfer);
    I2S_RxTransferReceiveDMA(DEMO_I2S_RX, &s_RxHandle, s_RxTransfer);
}
int LedBlinkCnt=0;
static void TxToCodecCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData)
{
    i2s_transfer_t *transfer = (i2s_transfer_t *)userData;

	#if 1
		LedBlinkCnt++;

		if(LedBlinkCnt==400)
		{
			LedG_On;
		}
		if(LedBlinkCnt==402)
		{
			LedG_Off;
		}
		if(LedBlinkCnt==800)
		{
			LedBlinkCnt=1;
		}
	#endif

    BufABSelect=1-BufABSelect;
    if(BufABSelect)
    {
    	//send audio to codec
    	transfer->data=(uint8_t *)I2STxBufToCodecA;
        I2S_TxTransferSendDMA(base, handle, *transfer);

        //get the audio from extern I2S Rx, will be sent to codec
        memcpy(I2STxBufToCodecA,I2SRxBufA,sizeof(I2STxBufToCodecA));
    }else
    {
    	//send audio to codec
    	transfer->data=(uint8_t *)I2STxBufToCodecB;
        I2S_TxTransferSendDMA(base, handle, *transfer);

        //prepare the audio data to be sent out next time
        //get the audio from extern I2S Rx, will be sent to codec
        memcpy(I2STxBufToCodecB,I2SRxBufB,sizeof(I2STxBufToCodecB));
    }
}
static void TxToExternCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData)
{
    i2s_transfer_t *transfer = (i2s_transfer_t *)userData;

    if(BufABSelect)
    {
    	//send audio to extern
    	transfer->data=(uint8_t *)I2STxBufToExternA;
        I2S_TxTransferSendDMA(base, handle, *transfer);

        //prepare the audio data to be sent out next time
		#if GeneratingToneMode==1
			GenerateSineToneSingleFreq(&SineToneGenerator, I2STxBufToExternA, AudioFrameLengthInSamples,1);
		#endif
		#if (GeneratingToneMode==2)||(GeneratingToneMode==3)
			GenerateSineTone(&SineToneGenerator, I2STxBufToExternA, AudioFrameLengthInSamples,1);
		#endif
    }else
    {
    	//send audio to extern
    	transfer->data=(uint8_t *)I2STxBufToExternB;
        I2S_TxTransferSendDMA(base, handle, *transfer);

        //prepare the audio data to be sent out next time
		#if GeneratingToneMode==1
			GenerateSineToneSingleFreq(&SineToneGenerator, I2STxBufToExternB, AudioFrameLengthInSamples,1);
		#endif
		#if (GeneratingToneMode==2)||(GeneratingToneMode==3)
			GenerateSineTone(&SineToneGenerator, I2STxBufToExternB, AudioFrameLengthInSamples,1);
		#endif
    }
}
static void RxCallback(I2S_Type *base, i2s_dma_handle_t *handle, status_t completionStatus, void *userData)
{
    i2s_transfer_t *transfer = (i2s_transfer_t *)userData;
    if(BufABSelect)
    {
    	transfer->data=(uint8_t *)I2SRxBufB;
        I2S_RxTransferReceiveDMA(base, handle, *transfer);
    }else
    {
    	transfer->data=(uint8_t *)I2SRxBufA;
        I2S_RxTransferReceiveDMA(base, handle, *transfer);
    }
}
