MCUXpresso_MIMXRT1021xxxxx/boards/evkmimxrt1020/demo_apps/sai_peripheral/sai_peripheral.c
Yilin Sun 763d32be90
Updated SDK to v2.15.000
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-03-15 22:23:36 +08:00

394 lines
12 KiB
C

/*
* Copyright 2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "sai.h"
#include "fsl_wm8960.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "peripherals.h"
#include "board.h"
#include "fsl_codec_common.h"
#include "fsl_codec_adapter.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* SAI instance and clock */
#define DEMO_CODEC_WM8960
#define DEMO_SAI_IRQ SAI1_IRQn
#define SAI_UserIRQHandler SAI1_IRQHandler
/* IRQ */
#define DEMO_SAI_TX_IRQ SAI1_IRQn
#define DEMO_SAI_RX_IRQ SAI1_IRQn
/* 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 (3U)
/* Clock divider for sai1 clock source */
#define DEMO_SAI1_CLOCK_SOURCE_DIVIDER (15U)
/* 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))
#ifndef DEMO_CODEC_VOLUME
#define DEMO_CODEC_VOLUME 100
#endif
/*******************************************************************************
* Prototypes
******************************************************************************/
#if defined DEMO_SDCARD
#include "ff.h"
#include "diskio.h"
#include "fsl_sd.h"
#include "sdmmc_config.h"
/*!
* @brief wait card insert function.
*/
static status_t sdcardWaitCardInsert(void);
static int SD_FatFsInit(void);
#endif
/*******************************************************************************
* 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, .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 + 768/1000)
* = 786.432 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 = 768, /* 30 bit numerator of fractional loop divider. */
.denominator = 1000, /* 30 bit denominator of fractional loop divider */
};
AT_NONCACHEABLE_SECTION_ALIGN(uint8_t audioBuff[BUFFER_SIZE * BUFFER_NUM], 4);
extern codec_config_t boardCodecConfig;
volatile bool istxFinished = false;
volatile bool isrxFinished = false;
volatile uint32_t beginCount = 0;
volatile uint32_t sendCount = 0;
volatile uint32_t receiveCount = 0;
volatile bool sdcard = false;
volatile uint32_t fullBlock = 0;
volatile uint32_t emptyBlock = BUFFER_NUM;
#if defined DEMO_SDCARD
/* static values for fatfs */
AT_NONCACHEABLE_SECTION(FATFS g_fileSystem); /* File system object */
AT_NONCACHEABLE_SECTION(FIL g_fileObject); /* File object */
AT_NONCACHEABLE_SECTION(BYTE work[FF_MAX_SS]);
extern sd_card_t g_sd; /* sd card descriptor */
#endif
codec_handle_t codecHandle;
/*******************************************************************************
* Code
******************************************************************************/
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);
}
}
void txCallback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData)
{
sendCount++;
emptyBlock++;
if (sendCount == beginCount)
{
istxFinished = true;
SAI_TransferTerminateSendEDMA(base, handle);
sendCount = 0;
}
}
void rxCallback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData)
{
receiveCount++;
fullBlock++;
if (receiveCount == beginCount)
{
isrxFinished = true;
SAI_TransferTerminateReceiveEDMA(base, handle);
receiveCount = 0;
}
}
#if defined DEMO_SDCARD
static status_t sdcardWaitCardInsert(void)
{
BOARD_SD_Config(&g_sd, NULL, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, NULL);
/* SD host init function */
if (SD_HostInit(&g_sd) != kStatus_Success)
{
PRINTF("\r\nSD host init fail\r\n");
return kStatus_Fail;
}
/* power off card */
SD_SetCardPower(&g_sd, false);
/* wait card insert */
if (SD_PollingCardInsert(&g_sd, kSD_Inserted) == kStatus_Success)
{
PRINTF("\r\nCard inserted.\r\n");
/* power on the card */
SD_SetCardPower(&g_sd, true);
}
else
{
PRINTF("\r\nCard detect fail.\r\n");
return kStatus_Fail;
}
return kStatus_Success;
}
int SD_FatFsInit()
{
/* If there is SDCard, Initialize SDcard and Fatfs */
FRESULT error;
static const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
static const TCHAR recordpathBuffer[] = DEMO_RECORD_PATH;
PRINTF("\r\nPlease insert a card into board.\r\n");
if (sdcardWaitCardInsert() != kStatus_Success)
{
return -1;
}
error = f_mount(&g_fileSystem, driverNumberBuffer, 1U);
if (error == FR_OK)
{
PRINTF("Mount volume Successfully.\r\n");
}
else if (error == FR_NO_FILESYSTEM)
{
#if FF_USE_MKFS
PRINTF("\r\nMake file system......The time may be long if the card capacity is big.\r\n");
if (f_mkfs(driverNumberBuffer, 0, work, sizeof work) != FR_OK)
{
PRINTF("Make file system failed.\r\n");
return -1;
}
#else
PRINTF("No file system detected, Please check.\r\n");
return -1;
#endif /* FF_USE_MKFS */
}
else
{
PRINTF("Mount volume failed.\r\n");
return -1;
}
#if (FF_FS_RPATH >= 2U)
error = f_chdrive((char const *)&driverNumberBuffer[0U]);
if (error)
{
PRINTF("Change drive failed.\r\n");
return -1;
}
#endif
PRINTF("\r\nCreate directory......\r\n");
error = f_mkdir((char const *)&recordpathBuffer[0U]);
if (error)
{
if (error == FR_EXIST)
{
PRINTF("Directory exists.\r\n");
}
else
{
PRINTF("Make directory failed.\r\n");
return -1;
}
}
return 0;
}
#endif /* DEMO_SDCARD */
/*!
* @brief Main function
*/
int main(void)
{
char input = '1';
uint8_t userItem = 1U;
BOARD_ConfigMPU();
BOARD_InitBootPins();
BOARD_InitBootClocks();
CLOCK_InitAudioPll(&audioPllConfig);
BOARD_InitBootPeripherals();
BOARD_InitDebugConsole();
/*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);
PRINTF("SAI Demo started!\n\r");
/* Use default setting to init codec */
if (CODEC_Init(&codecHandle, &boardCodecConfig) != kStatus_Success)
{
assert(false);
}
if (CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight,
DEMO_CODEC_VOLUME) != kStatus_Success)
{
assert(false);
}
/* Enable interrupt to handle FIFO error */
SAI_TxEnableInterrupts(DEMO_SAI_PERIPHERAL, kSAI_FIFOErrorInterruptEnable);
SAI_RxEnableInterrupts(DEMO_SAI_PERIPHERAL, kSAI_FIFOErrorInterruptEnable);
EnableIRQ(DEMO_SAI_TX_IRQ);
EnableIRQ(DEMO_SAI_RX_IRQ);
#if defined DEMO_SDCARD
/* Init SDcard and FatFs */
if (SD_FatFsInit() != 0)
{
PRINTF("SDCARD init failed !\r\n");
}
#endif /* DEMO_SDCARD */
PRINTF("\n\rPlease choose the option :\r\n");
while (1)
{
PRINTF("\r%d. Record and playback at same time\r\n", userItem++);
PRINTF("\r%d. Playback sine wave\r\n", userItem++);
#if defined DEMO_SDCARD
PRINTF("\r%d. Record to SDcard, after record playback it\r\n", userItem++);
#endif /* DEMO_SDCARD */
#if defined DIG_MIC
PRINTF("\r%d. Record using digital mic and playback at the same time\r\n", userItem++);
#endif
PRINTF("\r%d. Quit\r\n", userItem);
input = GETCHAR();
PUTCHAR(input);
PRINTF("\r\n");
if (input == (userItem + 48U))
{
break;
}
switch (input)
{
case '1':
#if defined DIG_MIC
/* Set the audio input source to AUX */
DA7212_ChangeInput((da7212_handle_t *)((uint32_t)(codecHandle.codecDevHandle)), kDA7212_Input_AUX);
#endif
RecordPlayback(DEMO_SAI_PERIPHERAL, 30);
break;
case '2':
PlaybackSine(DEMO_SAI_PERIPHERAL, 250, 5);
break;
#if defined DEMO_SDCARD
case '3':
RecordSDCard(DEMO_SAI_PERIPHERAL, 5);
break;
#endif
#if defined DIG_MIC
case userItem - 1U + 48U:
/* Set the audio input source to DMIC */
DA7212_ChangeInput((da7212_handle_t *)((uint32_t)(codecHandle.codecDevHandle)), kDA7212_Input_MIC1_Dig);
RecordPlayback(DEMO_SAI_PERIPHERAL, 30);
break;
#endif
default:
PRINTF("\rInvallid Input Parameter, please re-enter\r\n");
break;
}
userItem = 1U;
}
if (CODEC_Deinit(&codecHandle) != kStatus_Success)
{
assert(false);
}
PRINTF("\n\r SAI demo finished!\n\r ");
while (1)
{
}
}
void SAI_UserTxIRQHandler(void)
{
/* Clear the FEF flag */
SAI_TxClearStatusFlags(DEMO_SAI_PERIPHERAL, kSAI_FIFOErrorFlag);
SAI_TxSoftwareReset(DEMO_SAI_PERIPHERAL, kSAI_ResetTypeFIFO);
SDK_ISR_EXIT_BARRIER;
}
void SAI_UserRxIRQHandler(void)
{
SAI_RxClearStatusFlags(DEMO_SAI_PERIPHERAL, kSAI_FIFOErrorFlag);
SAI_RxSoftwareReset(DEMO_SAI_PERIPHERAL, kSAI_ResetTypeFIFO);
SDK_ISR_EXIT_BARRIER;
}
void SAI_UserIRQHandler(void)
{
if (SAI_TxGetStatusFlag(DEMO_SAI_PERIPHERAL) & kSAI_FIFOErrorFlag)
{
SAI_UserTxIRQHandler();
}
if (SAI_RxGetStatusFlag(DEMO_SAI_PERIPHERAL) & kSAI_FIFOErrorFlag)
{
SAI_UserRxIRQHandler();
}
SDK_ISR_EXIT_BARRIER;
}