364 lines
10 KiB
C
364 lines
10 KiB
C
/*
|
|
* Copyright 2020-2021 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
/* Board includes */
|
|
#include "pin_mux.h"
|
|
#include "clock_config.h"
|
|
#include "board.h"
|
|
#include "main.h"
|
|
#include "cmd.h"
|
|
|
|
#include "fsl_sd.h"
|
|
#include "ff.h"
|
|
#include "diskio.h"
|
|
#include "fsl_sd_disk.h"
|
|
#include "sdmmc_config.h"
|
|
|
|
#include "fsl_debug_console.h"
|
|
|
|
#include "fsl_gpio.h"
|
|
#include "fsl_iomuxc.h"
|
|
#include "fsl_dmamux.h"
|
|
#include "fsl_codec_common.h"
|
|
/* Flexram reallocation needed in MCUXpresso for VIT support to extend OCRAM */
|
|
#ifdef __MCUXPRESSO
|
|
#include "fsl_flexram.h"
|
|
#endif
|
|
#include "fsl_wm8960.h"
|
|
#include "app_definitions.h"
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
#define APP_SHELL_TASK_STACK_SIZE (1024)
|
|
#define SDCARD_TASK_STACK_SIZE (512)
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
|
|
int BOARD_CODEC_Init(void);
|
|
static void APP_SDCARD_DetectCallBack(bool isInserted, void *userData);
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
codec_handle_t codecHandle = {0};
|
|
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_AudioSampleRate48KHz, .bitWidth = kWM8960_AudioBitWidth16bit},
|
|
.master_slave = false,
|
|
};
|
|
codec_config_t boardCodecConfig = {.codecDevType = kCODEC_WM8960, .codecDevConfig = &wm8960Config};
|
|
|
|
#if (defined __GNUC__ && !defined __MCUXPRESSO)
|
|
extern uint32_t __bss_ocram_start__;
|
|
extern uint32_t __bss_ocram_end__;
|
|
#endif
|
|
|
|
static app_handle_t app;
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* AUDIO PLL setting: Frequency = Fref * (DIV_SELECT + NUM / DENOM)
|
|
* = 24 * (30 + 66/625)
|
|
* = 722.5344 MHz
|
|
*/
|
|
const clock_audio_pll_config_t audioPllConfig = {
|
|
.loopDivider = 30, /* 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 = 66, /* 30 bit numerator of fractional loop divider. */
|
|
.denominator = 625, /* 30 bit denominator of fractional loop divider */
|
|
};
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
int BOARD_CODEC_Init(void)
|
|
{
|
|
CODEC_Init(&codecHandle, &boardCodecConfig);
|
|
|
|
/* Initial volume kept low for hearing safety. */
|
|
CODEC_SetVolume(&codecHandle, kCODEC_PlayChannelHeadphoneLeft | kCODEC_PlayChannelHeadphoneRight, DEMO_VOLUME);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SystemInitHook(void)
|
|
{
|
|
#if defined(__MCUXPRESSO)
|
|
IOMUXC_GPR->GPR17 = (kFLEXRAM_BankDTCM << 0) | (kFLEXRAM_BankOCRAM << 2) | (kFLEXRAM_BankOCRAM << 4) |
|
|
(kFLEXRAM_BankOCRAM << 6) | (kFLEXRAM_BankOCRAM << 8) | (kFLEXRAM_BankOCRAM << 10) |
|
|
(kFLEXRAM_BankOCRAM << 12) | (kFLEXRAM_BankOCRAM << 14) | (kFLEXRAM_BankOCRAM << 16) |
|
|
(kFLEXRAM_BankOCRAM << 18) | (kFLEXRAM_BankOCRAM << 20) | (kFLEXRAM_BankOCRAM << 22) |
|
|
(kFLEXRAM_BankOCRAM << 24) | (kFLEXRAM_BankOCRAM << 26) | (kFLEXRAM_BankOCRAM << 28) |
|
|
(kFLEXRAM_BankOCRAM << 30);
|
|
|
|
IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_MASK;
|
|
#endif
|
|
|
|
#if (defined __GNUC__ && !defined __MCUXPRESSO)
|
|
/* Initialization of OCRAM BSS section. */
|
|
uint32_t startAddr; /* Address of the source memory. */
|
|
uint32_t endAddr; /* End of copied memory. */
|
|
|
|
/* Get the addresses for the OCRAM BSS section (zero-initialized data). */
|
|
startAddr = (uint32_t)&__bss_ocram_start__;
|
|
endAddr = (uint32_t)&__bss_ocram_end__;
|
|
|
|
/* Reset the .bss section. */
|
|
while (startAddr < endAddr)
|
|
{
|
|
/* Clear one byte. */
|
|
*((uint8_t *)startAddr) = 0U;
|
|
|
|
/* Increment the pointer. */
|
|
startAddr++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef VIT_PROC
|
|
void update_MPU_config(void)
|
|
{
|
|
/* Disable I cache and D cache */
|
|
if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR))
|
|
{
|
|
SCB_DisableICache();
|
|
}
|
|
if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR))
|
|
{
|
|
SCB_DisableDCache();
|
|
}
|
|
|
|
/* Disable MPU */
|
|
ARM_MPU_Disable();
|
|
|
|
/* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */
|
|
MPU->RBAR = ARM_MPU_RBAR(7, 0x20200000U);
|
|
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB);
|
|
|
|
/* Enable MPU */
|
|
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
|
|
|
|
/* Enable I cache and D cache */
|
|
SCB_EnableDCache();
|
|
SCB_EnableICache();
|
|
}
|
|
#endif
|
|
|
|
|
|
static void APP_SDCARD_DetectCallBack(bool isInserted, void *userData)
|
|
{
|
|
app_handle_t *app = (app_handle_t *)userData;
|
|
|
|
app->sdcardInserted = isInserted;
|
|
xSemaphoreGiveFromISR(app->sdcardSem, NULL);
|
|
}
|
|
|
|
bool SDCARD_inserted(void)
|
|
{
|
|
return (app.sdcardInserted);
|
|
}
|
|
|
|
void APP_SDCARD_Task(void *param)
|
|
{
|
|
const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'};
|
|
FRESULT error;
|
|
app_handle_t *app = (app_handle_t *)param;
|
|
|
|
app->sdcardSem = xSemaphoreCreateBinary();
|
|
|
|
BOARD_SD_Config(&g_sd, APP_SDCARD_DetectCallBack, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, app);
|
|
|
|
PRINTF("[APP_SDCARD_Task] start\r\n");
|
|
|
|
/* SD host init function */
|
|
if (SD_HostInit(&g_sd) != kStatus_Success)
|
|
{
|
|
PRINTF("[APP_SDCARD_Task] SD host init failed.\r\n");
|
|
vTaskSuspend(NULL);
|
|
}
|
|
|
|
/* Small delay for SD card detection logic to process */
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
|
|
while (1)
|
|
{
|
|
/* Block waiting for SDcard detect interrupt */
|
|
xSemaphoreTake(app->sdcardSem, portMAX_DELAY);
|
|
|
|
if (app->sdcardInserted != app->sdcardInsertedPrev)
|
|
{
|
|
app->sdcardInsertedPrev = app->sdcardInserted;
|
|
|
|
SD_SetCardPower(&g_sd, false);
|
|
|
|
if (app->sdcardInserted)
|
|
{
|
|
/* power on the card */
|
|
SD_SetCardPower(&g_sd, true);
|
|
if (f_mount(&app->fileSystem, driverNumberBuffer, 0U))
|
|
{
|
|
PRINTF("[APP_SDCARD_Task] Mount volume failed.\r\n");
|
|
continue;
|
|
}
|
|
|
|
#if (FF_FS_RPATH >= 2U)
|
|
error = f_chdrive((char const *)&driverNumberBuffer[0U]);
|
|
if (error)
|
|
{
|
|
PRINTF("[APP_SDCARD_Task] Change drive failed.\r\n");
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
PRINTF("[APP_SDCARD_Task] SD card drive mounted\r\n");
|
|
|
|
xSemaphoreGive(app->sdcardSem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void APP_Shell_Task(void *param)
|
|
{
|
|
PRINTF("[APP_Shell_Task] start\r\n");
|
|
|
|
/* Handle shell commands. */
|
|
shellCmd();
|
|
vTaskSuspend(NULL);
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int ret;
|
|
|
|
BOARD_ConfigMPU();
|
|
#ifdef VIT_PROC
|
|
update_MPU_config();
|
|
#endif
|
|
BOARD_InitBootPins();
|
|
BOARD_BootClockRUN();
|
|
/* 1. Init SAI clock .*/
|
|
CLOCK_InitAudioPll(&audioPllConfig);
|
|
BOARD_InitDebugConsole();
|
|
|
|
/*Clock setting for LPI2C*/
|
|
CLOCK_SetMux(kCLOCK_Lpi2cMux, BOARD_CODEC_I2C_CLOCK_SOURCE_SELECT);
|
|
CLOCK_SetDiv(kCLOCK_Lpi2cDiv, BOARD_CODEC_I2C_CLOCK_SOURCE_DIVIDER);
|
|
|
|
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);
|
|
|
|
DMAMUX_Init(DEMO_DMAMUX);
|
|
DMAMUX_SetSource(DEMO_DMAMUX, DEMO_TX_CHANNEL, (uint8_t)DEMO_SAI_TX_SOURCE);
|
|
DMAMUX_EnableChannel(DEMO_DMAMUX, DEMO_TX_CHANNEL);
|
|
DMAMUX_SetSource(DEMO_DMAMUX, DEMO_RX_CHANNEL, (uint8_t)DEMO_SAI_RX_SOURCE);
|
|
DMAMUX_EnableChannel(DEMO_DMAMUX, DEMO_RX_CHANNEL);
|
|
|
|
PRINTF("\r\n");
|
|
PRINTF("*******************************\r\n");
|
|
PRINTF("Maestro audio record demo start\r\n");
|
|
PRINTF("*******************************\r\n");
|
|
PRINTF("\r\n");
|
|
|
|
/* Initialize OSA*/
|
|
OSA_Init();
|
|
|
|
ret = BOARD_CODEC_Init();
|
|
if (ret)
|
|
{
|
|
PRINTF("CODEC_Init failed\r\n");
|
|
return -1;
|
|
}
|
|
|
|
if (xTaskCreate(APP_SDCARD_Task, "SDCard Task", SDCARD_TASK_STACK_SIZE, &app, configMAX_PRIORITIES - 4, NULL) !=
|
|
pdPASS)
|
|
{
|
|
PRINTF("\r\nFailed to create application task\r\n");
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
/* Set shell command task priority = 1 */
|
|
if (xTaskCreate(APP_Shell_Task, "Shell Task", APP_SHELL_TASK_STACK_SIZE, &app, configMAX_PRIORITIES - 5,
|
|
&app.shell_task_handle) != pdPASS)
|
|
{
|
|
PRINTF("\r\nFailed to create application task\r\n");
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
/* Run RTOS */
|
|
vTaskStartScheduler();
|
|
|
|
/* Should not reach this statement */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Loop forever if stack overflow is detected.
|
|
*
|
|
* If configCHECK_FOR_STACK_OVERFLOW is set to 1,
|
|
* this hook provides a location for applications to
|
|
* define a response to a stack overflow.
|
|
*
|
|
* Use this hook to help identify that a stack overflow
|
|
* has occurred.
|
|
*
|
|
*/
|
|
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
|
{
|
|
portDISABLE_INTERRUPTS();
|
|
|
|
/* Loop forever */
|
|
for (;;)
|
|
;
|
|
}
|
|
|
|
/**
|
|
* @brief Warn user if pvPortMalloc fails.
|
|
*
|
|
* Called if a call to pvPortMalloc() fails because there is insufficient
|
|
* free memory available in the FreeRTOS heap. pvPortMalloc() is called
|
|
* internally by FreeRTOS API functions that create tasks, queues, software
|
|
* timers, and semaphores. The size of the FreeRTOS heap is set by the
|
|
* configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h.
|
|
*
|
|
*/
|
|
void vApplicationMallocFailedHook()
|
|
{
|
|
PRINTF(("\r\nERROR: Malloc failed to allocate memory\r\n"));
|
|
|
|
/* Loop forever */
|
|
for (;;)
|
|
;
|
|
}
|