MCUXpresso_MIMXRT1021xxxxx/boards/evkmimxrt1020/demo_apps/sai/playbackSineWave.c
2022-08-23 23:00:33 +08:00

268 lines
8.7 KiB
C

/*
* Copyright 2016-2018 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "sai.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
static float32_t do_fft(
uint32_t sampleRate, uint32_t bitWidth, uint8_t *buffer, float32_t *fftData, float32_t *fftResult);
/*******************************************************************************
* Variables
******************************************************************************/
static float32_t ffData[2 * BUFFER_SIZE];
static float32_t ffResult[BUFFER_SIZE];
extern sai_edma_handle_t txHandle;
extern sai_edma_handle_t rxHandle;
extern uint8_t audioBuff[BUFFER_SIZE * BUFFER_NUM];
extern volatile bool istxFinished;
extern volatile bool isrxFinished;
extern volatile uint32_t beginCount;
extern volatile uint32_t sendCount;
extern volatile uint32_t receiveCount;
extern bool sdcard;
extern volatile uint32_t fullBlock;
extern volatile uint32_t emptyBlock;
/*******************************************************************************
* Code
******************************************************************************/
static float32_t do_fft(
uint32_t sampleRate, uint32_t bitWidth, uint8_t *buffer, float32_t *fftData, float32_t *fftResult)
{
/* Counter variable for navigating buffers */
uint32_t counter;
/* Return value for wav frequency in hertz */
float32_t wavFreqHz;
/* CMSIS status & FFT instance */
arm_status status; /* ARM status variable */
arm_cfft_radix2_instance_f32 fft; /* ARM FFT instance */
/* Frequency analysis variables */
float32_t maxValue; /* max value for greatest FFT bin amplitude */
uint32_t testIndex = 0; /* value for storing the bin location with maxValue */
uint32_t complexBuffSize = BUFFER_SIZE * 2;
uint32_t fftSize = BUFFER_SIZE; /* FFT bin size */
uint32_t ifftFlag = 0; /* Flag for the selection of CFFT/CIFFT */
uint32_t doBitReverse = 1; /* Flag for selection of normal order or bit reversed order */
float32_t hzPerBin = 2 * ((float32_t)sampleRate / (float32_t)fftSize); /* Calculate hz per FFT bin */
uint8_t *temp8; /* Point to data for 8 bit samples */
uint8_t temp8Data;
uint16_t *temp16; /* Point to data for 16 bit samples */
int16_t temp16Data;
uint32_t *temp32; /* Point to data for 32 bit samples */
int32_t temp32Data;
/* Set status as success */
status = ARM_MATH_SUCCESS;
/* Wav data variables */
switch (bitWidth)
{
case 8:
temp8 = (uint8_t *)buffer;
temp8Data = 0;
/* Copy wav data to fft input array */
for (counter = 0; counter < complexBuffSize; counter++)
{
if (counter % 2 == 0)
{
temp8Data = (uint8_t)*temp8;
fftData[counter] = (float32_t)temp8Data;
temp8++;
}
else
{
fftData[counter] = 0.0;
}
}
/* Set instance for Real FFT */
status = arm_cfft_radix2_init_f32(&fft, fftSize, ifftFlag, doBitReverse);
/* Perform Real FFT on fftData */
arm_cfft_radix2_f32(&fft, fftData);
/* Populate FFT bins */
arm_cmplx_mag_f32(fftData, fftResult, fftSize);
/* Zero out non-audible, low-frequency noise from FFT Results. */
fftResult[0] = 0.0;
/* Find max bin and location of max (first half of bins as this is the only valid section) */
arm_max_f32(fftResult, fftSize, &maxValue, &testIndex);
break;
case 16:
temp16 = (uint16_t *)buffer;
temp16Data = 0;
/* Copy wav data to fft input array */
for (counter = 0; counter < complexBuffSize; counter++)
{
if (counter % 2 == 0)
{
temp16Data = (int16_t)*temp16;
fftData[counter] = (float32_t)temp16Data;
temp16++;
}
else
{
fftData[counter] = 0.0;
}
}
/* Set instance for Real FFT */
status = arm_cfft_radix2_init_f32(&fft, fftSize, ifftFlag, doBitReverse);
/* Perform Real FFT on fftData */
arm_cfft_radix2_f32(&fft, fftData);
/* Populate FFT bins */
arm_cmplx_mag_f32(fftData, fftResult, fftSize);
/* Zero out non-audible, low-frequency noise from FFT Results. */
fftResult[0] = 0.0;
/* Find max bin and location of max (first half of bins as this is the only valid section) */
arm_max_f32(fftResult, fftSize, &maxValue, &testIndex);
break;
case 32:
temp32 = (uint32_t *)buffer;
temp32Data = 0;
/* Copy wav data to fft input array */
for (counter = 0; counter < complexBuffSize; counter++)
{
if (counter % 2 == 0)
{
temp32Data = (int32_t)*temp32;
fftData[counter] = (float32_t)temp32Data;
temp32++;
}
else
{
fftData[counter] = 0.0;
}
}
/* Set instance for Real FFT */
status = arm_cfft_radix2_init_f32(&fft, fftSize, ifftFlag, doBitReverse);
/* Perform Real FFT on fftData */
arm_cfft_radix2_f32(&fft, fftData);
/* Populate FFT bins */
arm_cmplx_mag_f32(fftData, fftResult, fftSize);
/* Zero out non-audible, low-frequency noise from FFT Results. */
fftResult[0] = 0.0;
/* Find max bin and location of max (first half of bins as this is the only valid section) */
arm_max_f32(fftResult, fftSize, &maxValue, &testIndex);
break;
default:
__asm("NOP");
break;
}
if (status != ARM_MATH_SUCCESS)
{
wavFreqHz = 0; /* If an error has occurred set frequency of wav data to 0Hz */
PRINTF("\r\nFFT compuation error.\r\n");
}
else
{
/* Set wavFreqHz to bin location of max amplitude multiplied by the hz per bin */
wavFreqHz = testIndex * hzPerBin;
}
return wavFreqHz;
}
void PlaybackSine(I2S_Type *base, uint32_t SineWaveFreqHz, uint32_t time_s)
{
uint32_t count = DEMO_AUDIO_SAMPLE_RATE / SineWaveFreqHz;
uint32_t i = 0;
uint32_t val = 0;
sai_transfer_t xfer = {0};
float32_t freq = 0;
uint32_t totalNum = 0, index = 0;
/* Clear the status */
istxFinished = false;
sendCount = 0;
emptyBlock = BUFFER_NUM;
/* Gnerate the sine wave data */
for (i = 0; i < count; i++)
{
val = arm_sin_q15(0x8000 * i / count);
audioBuff[4 * i] = val & 0xFFU;
audioBuff[4 * i + 1U] = (val >> 8U) & 0xFFU;
audioBuff[4 * i + 2U] = val & 0xFFU;
audioBuff[4 * i + 3U] = (val >> 8U) & 0xFFU;
}
/* Repeat the cycle */
for (i = 1; i < (BUFFER_SIZE * BUFFER_NUM) / (4 * count); i++)
{
memcpy(audioBuff + (i * 4 * count), audioBuff, (4 * count));
}
/* Send times according to the time need to playback */
beginCount = DEMO_AUDIO_SAMPLE_RATE * time_s * 4 / BUFFER_SIZE;
/* Compute the frequency of the data using FFT */
freq = do_fft(DEMO_AUDIO_SAMPLE_RATE, DEMO_AUDIO_BIT_WIDTH, audioBuff, ffData, ffResult);
PRINTF("\r\n Data frequency is %f\r\n", freq);
/* Reset SAI Tx internal logic */
SAI_TxSoftwareReset(base, kSAI_ResetTypeSoftware);
/* Do the playback */
xfer.data = audioBuff;
xfer.dataSize = BUFFER_SIZE;
while (totalNum < beginCount)
{
/* Transfer data already prepared, so while there is any
empty slot, just transfer */
if (emptyBlock > 0)
{
xfer.data = audioBuff + index * BUFFER_SIZE;
/* Shall make sure the sai buffer queue is not full */
if (SAI_TransferSendEDMA(base, &txHandle, &xfer) == kStatus_Success)
{
index = (index + 1U) % BUFFER_NUM;
totalNum++;
emptyBlock--;
}
}
}
/* Wait for the send finished */
while (istxFinished != true)
{
}
}