You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2098 lines
72 KiB
2098 lines
72 KiB
2 years ago
|
/**
|
||
|
******************************************************************************
|
||
|
* @file stm32l496g_discovery_audio.c
|
||
|
* @author MCD Application Team
|
||
|
* @brief This file provides a set of functions needed to manage the
|
||
|
* Audio driver for the STM32L496G-Discovery board.
|
||
|
******************************************************************************
|
||
|
* @attention
|
||
|
*
|
||
|
* <h2><center>© Copyright (c) 2017 STMicroelectronics.
|
||
|
* All rights reserved.</center></h2>
|
||
|
*
|
||
|
* This software component is licensed by ST under BSD 3-Clause license,
|
||
|
* the "License"; You may not use this file except in compliance with the
|
||
|
* License. You may obtain a copy of the License at:
|
||
|
* opensource.org/licenses/BSD-3-Clause
|
||
|
*
|
||
|
******************************************************************************
|
||
|
*/
|
||
|
|
||
|
/*==============================================================================
|
||
|
User NOTES
|
||
|
|
||
|
1. How To use this driver:
|
||
|
--------------------------
|
||
|
+ This driver supports STM32L4xx devices on STM32L496G-Discovery (MB1261) Discovery boards.
|
||
|
a) to play an audio file through headset. All functions names start by BSP_AUDIO_OUT_xxx.
|
||
|
b) to record an audio file through digital microphones (MP34DT01TR ST mems)
|
||
|
or analog microphone (headset microphone). All functions names start by BSP_AUDIO_IN_xxx.
|
||
|
|
||
|
a) PLAY A FILE:
|
||
|
==============
|
||
|
+ Call the function BSP_AUDIO_OUT_Init(
|
||
|
OutputDevice: physical output mode (only OUTPUT_DEVICE_HEADPHONE).
|
||
|
Volume : Initial volume to be set (0 is min (mute), 100 is max (100%)
|
||
|
AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...)
|
||
|
this parameter is relative to the audio file/stream type.
|
||
|
)
|
||
|
This function configures all the hardware required for the audio application (codec, I2C, SAI,
|
||
|
GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK.
|
||
|
If the returned value is different from AUDIO_OK or the function is stuck then the communication with
|
||
|
the audio codec has failed.
|
||
|
- OUTPUT_DEVICE_HEADPHONE: only Headphone output is available on this board.
|
||
|
|
||
|
+ Call the function BSP_AUDIO_OUT_RegisterCallbacks to register user callbacks
|
||
|
required to manage audio data streaming towards the audio codec (ErrorCallback(),
|
||
|
HalfTransfer_CallBack() and TransferComplete_CallBack()).
|
||
|
|
||
|
+ Call the function BSP_AUDIO_OUT_Play() to start audio playback (for the first time).
|
||
|
+ Call the function BSP_AUDIO_OUT_Pause() to pause audio playback.
|
||
|
+ Call the function BSP_AUDIO_OUT_Resume() to resume audio playback.
|
||
|
Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called
|
||
|
for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case).
|
||
|
Note. This function should be called only when the audio file is played or paused (not stopped).
|
||
|
+ Call the function BSP_AUDIO_OUT_Stop() to stop audio playback.
|
||
|
+ To modify the volume level, the sampling frequency, the device output mode,
|
||
|
the mute status or the audio configuration or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(),
|
||
|
AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetOutputMode(), BSP_AUDIO_OUT_SetMute()and
|
||
|
BSP_AUDIO_OUT_ChangeAudioConfig().
|
||
|
|
||
|
Driver architecture:
|
||
|
--------------------
|
||
|
+ This driver provides the audio layer high level API: it consists in functions
|
||
|
exported in the stm32l496g_discovery_audio.h file (e.g. BSP_AUDIO_OUT_Init(),
|
||
|
BSP_AUDIO_OUT_Play(), ...).
|
||
|
+ This driver also includes the Media Access Layer (MAL): it consists in
|
||
|
functions allowing to access setup the audio devices. These functions
|
||
|
are included as local functions into the stm32l496g_discovery_audio.c file
|
||
|
(e.g. AUDIO_SAIx_Init()).
|
||
|
|
||
|
Known Limitations:
|
||
|
------------------
|
||
|
1- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some
|
||
|
user interrupt routines (in this case, interrupts could be disabled just before the start of
|
||
|
communication then re-enabled when it is over). Note that this communication is only done at
|
||
|
the configuration phase (BSP_AUDIO_OUT_Init() or BSP_AUDIO_OUT_Stop()) and when Volume control modification is
|
||
|
performed (BSP_AUDIO_OUT_SetVolume() or BSP_AUDIO_OUT_SetMute()or BSP_AUDIO_OUT_SetOutputMode()).
|
||
|
When the audio data is played, no communication is required with the audio codec.
|
||
|
2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size,
|
||
|
File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.
|
||
|
3- Supports only 16-bits audio data size.
|
||
|
|
||
|
b) RECORD A FILE:
|
||
|
================
|
||
|
+ Call the function BSP_AUDIO_IN_InitEx(
|
||
|
InputDevice: physical input mode (INPUT_DEVICE_DIGITAL_MIC
|
||
|
INPUT_DEVICE_DIGITAL_MIC1, INPUT_DEVICE_DIGITAL_MIC2
|
||
|
or INPUT_DEVICE_ANALOG_MIC)
|
||
|
AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...)
|
||
|
)
|
||
|
This function configures all the hardware required for the audio application (DFSDM or SAI,
|
||
|
GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if the
|
||
|
configuration completes successfully.
|
||
|
- INPUT_DEVICE_DIGITAL_MIC: Record from digital microphones mounted on board.
|
||
|
- INPUT_DEVICE_DIGITAL_MIC1: Record from digital microphone 1 mounted on board (left microphone).
|
||
|
- INPUT_DEVICE_DIGITAL_MIC2: Record from digital microphone 2 mounted on board (right microphone).
|
||
|
- INPUT_DEVICE_ANALOG_MIC: Record from headset microphone.
|
||
|
|
||
|
+ Call the function BSP_AUDIO_IN_RegisterCallbacks to register user callbacks
|
||
|
used to stream audio data toward the record buffer (ErrorCallback(),
|
||
|
HalfTransfer_CallBack() and TransferComplete_CallBack()).
|
||
|
|
||
|
+ Call the function BSP_AUDIO_IN_Record(
|
||
|
pbuf Main buffer pointer for the recorded data storing
|
||
|
size Current size of the recorded buffer
|
||
|
)
|
||
|
to start recording from the microphone.
|
||
|
|
||
|
+ Call the function BSP_AUDIO_IN_STOP() to stop recording.
|
||
|
==============================================================================*/
|
||
|
|
||
|
/* Includes ------------------------------------------------------------------*/
|
||
|
#include <string.h>
|
||
|
#include "stm32l496g_discovery_audio.h"
|
||
|
|
||
|
/** @addtogroup BSP
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/** @addtogroup STM32L496G_DISCOVERY
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO STM32L496G-DISCOVERY AUDIO
|
||
|
* @brief This file includes the low layer driver for cs42l51 Audio Codec
|
||
|
* available on STM32L496G-Discovery board (MB1261).
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/* Private typedef -----------------------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Types Private Types
|
||
|
* @{
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
AUDIO_DrvTypeDef *AudioDrv; /* Audio codec driver */
|
||
|
uint32_t OutputDevice; /* Output device */
|
||
|
uint32_t Frequency; /* Playback frequency */
|
||
|
uint32_t Volume; /* Playback volume */
|
||
|
Audio_CallbackTypeDef CbError; /* pointer to the callback function invoked when error occurs */
|
||
|
Audio_CallbackTypeDef CbHalfTransfer; /* pointer to the callback function invoked when half transfer occurs */
|
||
|
Audio_CallbackTypeDef CbTransferComplete; /* pointer to the callback function invoked when transfer complete occurs */
|
||
|
} AUDIO_OUT_TypeDef;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
AUDIO_DrvTypeDef *AudioDrv; /* Audio codec driver */
|
||
|
DFSDM_Channel_HandleTypeDef hDfsdmLeftChannel; /* DFSDM channel handle used for left channel */
|
||
|
DFSDM_Channel_HandleTypeDef hDfsdmRightChannel; /* DFSDM channel handle used for right channel */
|
||
|
DMA_HandleTypeDef hDmaDfsdmLeft; /* DMA handle used for DFSDM regular conversions on left channel */
|
||
|
DMA_HandleTypeDef hDmaDfsdmRight; /* DMA handle used for DFSDM regular conversions on right channel */
|
||
|
int32_t *LeftRecBuff; /* Buffers for left samples */
|
||
|
int32_t *RightRecBuff; /* Buffers for right samples */
|
||
|
uint32_t InputDevice; /* Input device */
|
||
|
uint32_t Frequency; /* Record Frequency */
|
||
|
uint32_t BitResolution; /* Record bit resolution */
|
||
|
uint32_t ChannelNbr; /* Record Channel Number */
|
||
|
uint16_t *pRecBuf; /* Pointer to record user buffer */
|
||
|
uint32_t RecSize; /* Size to record in mono, double size to record in stereo */
|
||
|
Audio_CallbackTypeDef CbError; /* pointer to the callback function invoked when a DMA transfer fails */
|
||
|
Audio_CallbackTypeDef CbHalfTransfer; /* pointer to the callback function invoked when half of the DMA transfer is completed */
|
||
|
Audio_CallbackTypeDef CbTransferComplete; /* pointer to the callback function invoked when the DMA transfer is completed */
|
||
|
} AUDIO_IN_TypeDef;
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Private defines ------------------------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Constants Private Constants
|
||
|
* @{
|
||
|
*/
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Private macros ------------------------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Macros Private Macros
|
||
|
* @{
|
||
|
*/
|
||
|
/*### PLAY ###*/
|
||
|
/* SCK(kHz) = SAI_CK_x/(SAIClockDivider*2*256) */
|
||
|
#define SAIClockDivider(__FREQUENCY__) \
|
||
|
(__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 12 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 2 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 6 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 1 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 3 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 2 : 1 \
|
||
|
|
||
|
/*### RECORD ###*/
|
||
|
#define DFSDMOverSampling(__FREQUENCY__) \
|
||
|
(__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 256 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 256 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 128 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 128 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 64 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 64 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 32 : 16 \
|
||
|
|
||
|
#define DFSDMClockDivider(__FREQUENCY__) \
|
||
|
(__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 24 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 4 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 24 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 24 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 4 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 32 : 32 \
|
||
|
|
||
|
#define DFSDMFilterOrder(__FREQUENCY__) \
|
||
|
(__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? DFSDM_FILTER_SINC3_ORDER \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? DFSDM_FILTER_SINC3_ORDER \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? DFSDM_FILTER_SINC3_ORDER \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? DFSDM_FILTER_SINC3_ORDER \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? DFSDM_FILTER_SINC4_ORDER \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? DFSDM_FILTER_SINC3_ORDER \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC4_ORDER : DFSDM_FILTER_SINC5_ORDER \
|
||
|
|
||
|
#define DFSDMRightBitShift(__FREQUENCY__) \
|
||
|
(__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 8 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 8 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 6 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 6 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 8 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 2 \
|
||
|
: (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 4 : 4 \
|
||
|
|
||
|
/* Saturate the record PCM sample */
|
||
|
#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Private variables ---------------------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Variables Private Variables
|
||
|
* @{
|
||
|
*/
|
||
|
/* Audio output context information */
|
||
|
static AUDIO_OUT_TypeDef hAudioOut = {0};
|
||
|
|
||
|
/* Audio input context information */
|
||
|
static AUDIO_IN_TypeDef hAudioIn = {0};
|
||
|
|
||
|
/* SAI DMA handle */
|
||
|
static DMA_HandleTypeDef hDmaSaiTx;
|
||
|
static DMA_HandleTypeDef hDmaSaiRx;
|
||
|
|
||
|
static uint32_t DmaLeftRecHalfBuffCplt;
|
||
|
static uint32_t DmaLeftRecBuffCplt;
|
||
|
static uint32_t DmaRightRecHalfBuffCplt;
|
||
|
static uint32_t DmaRightRecBuffCplt;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Exported variables ---------------------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO_Exported_Variables Exported Variables
|
||
|
* @{
|
||
|
*/
|
||
|
/* SAIx handle */
|
||
|
SAI_HandleTypeDef BSP_AUDIO_hSai_Tx;
|
||
|
SAI_HandleTypeDef BSP_AUDIO_hSai_Rx;
|
||
|
|
||
|
/* DFSDM filter handle */
|
||
|
DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmLeftFilter;
|
||
|
DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmRightFilter;
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Private function prototypes -----------------------------------------------*/
|
||
|
/** @defgroup STM32L496G_DISCOVERY_AUDIO_Private_Functions Private Functions
|
||
|
* @{
|
||
|
*/
|
||
|
static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq);
|
||
|
static uint8_t AUDIO_SAIx_DeInit(void);
|
||
|
static uint8_t AUDIO_DFSDMx_Init(uint32_t AudioFreq);
|
||
|
static uint8_t AUDIO_DFSDMx_DeInit(void);
|
||
|
static uint8_t AUDIO_SAIPLLConfig(uint32_t AudioFreq);
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* Exported functions --------------------------------------------------------*/
|
||
|
/** @addtogroup STM32L496G_DISCOVERY_AUDIO_Exported_Functions
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Configures the audio codec related peripherals.
|
||
|
* @param OutputDevice: OUTPUT_DEVICE_HEADPHONE.
|
||
|
* @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
|
||
|
* @param AudioFreq: Audio frequency used to play the audio stream.
|
||
|
* @retval BSP AUDIO status
|
||
|
* @note The SAI PLL input clock must be configure in the user application.
|
||
|
* The SAI PLL configuration done within this function assumes that
|
||
|
* the SAI PLL input clock runs at 8 MHz.
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice,
|
||
|
uint8_t Volume,
|
||
|
uint32_t AudioFreq)
|
||
|
{
|
||
|
/* Initialize the audio output context */
|
||
|
hAudioOut.AudioDrv = &cs42l51_drv;
|
||
|
hAudioOut.OutputDevice = OutputDevice;
|
||
|
hAudioOut.Frequency = AudioFreq;
|
||
|
hAudioOut.Volume = Volume;
|
||
|
hAudioOut.CbError = (Audio_CallbackTypeDef)NULL;
|
||
|
hAudioOut.CbHalfTransfer = (Audio_CallbackTypeDef)NULL;
|
||
|
hAudioOut.CbTransferComplete = (Audio_CallbackTypeDef)NULL;
|
||
|
|
||
|
/* Check if input device is currently used */
|
||
|
if (hAudioIn.InputDevice != 0)
|
||
|
{
|
||
|
/* If input device is currently used, SAI PLL is already initialized */
|
||
|
/* Check that AudioFreq for record and playback is the same */
|
||
|
if (hAudioIn.Frequency != hAudioOut.Frequency)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Configure the SAI PLL according to the requested audio frequency */
|
||
|
if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* If input device is analogic mic, SAI is already initialized */
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
/* SAI data transfer preparation: prepare the Media to be used for the audio
|
||
|
transfer from memory to SAI peripheral. */
|
||
|
if (AUDIO_SAIx_Init(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Initialize the audio codec internal registers */
|
||
|
if (hAudioOut.AudioDrv->Init(AUDIO_I2C_ADDRESS,
|
||
|
(hAudioOut.OutputDevice | hAudioIn.InputDevice),
|
||
|
Volume,
|
||
|
AudioFreq) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-Initializes audio codec related peripherals
|
||
|
* @retval BSP AUDIO status
|
||
|
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_DeInit(void)
|
||
|
{
|
||
|
if (hAudioIn.InputDevice == INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
/* Reset playback path on audio codec */
|
||
|
if (hAudioIn.AudioDrv->Init(AUDIO_I2C_ADDRESS,
|
||
|
hAudioIn.InputDevice,
|
||
|
(uint8_t) hAudioOut.Volume,
|
||
|
hAudioIn.Frequency) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* De-initializes SAI interface */
|
||
|
if (AUDIO_SAIx_DeInit() != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* DeInit audio codec */
|
||
|
hAudioOut.AudioDrv->DeInit();
|
||
|
}
|
||
|
|
||
|
/* Disable SAI PLL if no more device is used */
|
||
|
if (hAudioIn.InputDevice == 0)
|
||
|
{
|
||
|
if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Reset the audio output context */
|
||
|
memset(&hAudioOut, 0, sizeof(hAudioOut));
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Starts playing audio stream from a data buffer for a determined size.
|
||
|
* @param pData: pointer on PCM samples buffer
|
||
|
* @param Size: Number of audio data HALF WORD.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_Play(uint16_t *pData, uint32_t Size)
|
||
|
{
|
||
|
/* Initiate a DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_Transmit_DMA(&BSP_AUDIO_hSai_Tx, (uint8_t *)pData, DMA_MAX(Size)) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Call the audio Codec Play function */
|
||
|
if (hAudioOut.AudioDrv->Play(AUDIO_I2C_ADDRESS, pData, Size) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sends n-Bytes on the SAI interface.
|
||
|
* @param pData: pointer on PCM samples buffer
|
||
|
* @param Size: number of data to be written
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
|
||
|
{
|
||
|
/* Initiate a DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_Transmit_DMA(&BSP_AUDIO_hSai_Tx, (uint8_t *)pData, Size) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function Pauses the audio file stream. In case
|
||
|
* of using DMA, the DMA Pause feature is used.
|
||
|
* @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
|
||
|
* BSP_AUDIO_OUT_Resume() function should be called for resume
|
||
|
* (use of BSP_AUDIO_OUT_Play() function for resume could lead
|
||
|
* to unexpected behavior).
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_Pause(void)
|
||
|
{
|
||
|
/* Call the Audio Codec Pause function */
|
||
|
if (hAudioOut.AudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Pause DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_DMAPause(&BSP_AUDIO_hSai_Tx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief This function Resumes the audio file stream.
|
||
|
* @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
|
||
|
* BSP_AUDIO_OUT_Resume() function should be called for resume
|
||
|
* (use of BSP_AUDIO_OUT_Play() function for resume could lead to
|
||
|
* unexpected behavior).
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_Resume(void)
|
||
|
{
|
||
|
/* Call the Audio Codec Resume function */
|
||
|
if (hAudioOut.AudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Resume DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_DMAResume(&BSP_AUDIO_hSai_Tx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Stops audio playing and Power down the Audio Codec.
|
||
|
* @param Option: could be one of the following parameters
|
||
|
* - CODEC_PDWN_SW: for software power off (by writing registers).
|
||
|
* Then no need to reconfigure the Codec after power on.
|
||
|
* - CODEC_PDWN_HW: completely shut down the codec (physically).
|
||
|
* Then need to reconfigure the Codec after power on.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
|
||
|
{
|
||
|
/* Prevent unused argument(s) compilation warning */
|
||
|
UNUSED(Option);
|
||
|
|
||
|
/* Call Audio Codec Stop function */
|
||
|
if (hAudioOut.AudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Wait at least 100ms */
|
||
|
HAL_Delay(100);
|
||
|
|
||
|
/* Stop DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_DMAStop(&BSP_AUDIO_hSai_Tx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Controls the current audio volume level.
|
||
|
* @param Volume: Volume level to be set in percentage from 0% to 100% (0 for
|
||
|
* Mute and 100 for Max volume level).
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
|
||
|
{
|
||
|
/* Call the codec volume control function with converted volume value */
|
||
|
if (hAudioOut.AudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
hAudioOut.Volume = Volume;
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Enables or disables the MUTE mode by software
|
||
|
* @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to
|
||
|
* unmute the codec and restore previous volume level.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
|
||
|
{
|
||
|
/* Call the Codec Mute function */
|
||
|
if (hAudioOut.AudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Switch dynamically (while audio file is being played) the output
|
||
|
* target (speaker or headphone).
|
||
|
* @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER,
|
||
|
* OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
|
||
|
{
|
||
|
/* Call the Codec output device function */
|
||
|
if (hAudioOut.AudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Updates the audio frequency.
|
||
|
* @param AudioFreq: Audio frequency used to play the audio stream.
|
||
|
* @note The SAI PLL input clock must be configure in the user application.
|
||
|
* The SAI PLL configuration done within this function assumes that
|
||
|
* the SAI PLL input clock runs at 8 MHz.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
|
||
|
{
|
||
|
uint8_t TxData[2] = {0x00, 0x00};
|
||
|
|
||
|
/* Configure the SAI PLL according to the requested audio frequency */
|
||
|
if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Disable SAI peripheral to allow access to SAI internal registers */
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
|
||
|
|
||
|
/* Update the SAI audio frequency configuration */
|
||
|
BSP_AUDIO_hSai_Tx.Init.Mckdiv = SAIClockDivider(AudioFreq);
|
||
|
HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
|
||
|
BSP_AUDIO_hSai_Rx.Init.Mckdiv = SAIClockDivider(AudioFreq);
|
||
|
HAL_SAI_Init(&BSP_AUDIO_hSai_Rx);
|
||
|
|
||
|
/* Enable SAI peripheral to generate MCLK */
|
||
|
__HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
/* Transmit one byte to start FS generation */
|
||
|
if (HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
hAudioOut.Frequency = AudioFreq;
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Changes the Audio Out Configuration.
|
||
|
* @param AudioOutOption: specifies the audio out new configuration
|
||
|
* This parameter can be any value of @ref BSP_Audio_Out_Option
|
||
|
* @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
|
||
|
* audio out configuration.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void BSP_AUDIO_OUT_ChangeAudioConfig(uint32_t AudioOutOption)
|
||
|
{
|
||
|
uint8_t TxData[2] = {0x00, 0x00};
|
||
|
|
||
|
/********** Playback Buffer circular/normal mode **********/
|
||
|
if (AudioOutOption & BSP_AUDIO_OUT_CIRCULARMODE)
|
||
|
{
|
||
|
/* Deinitialize the Stream to update DMA mode */
|
||
|
HAL_DMA_DeInit(BSP_AUDIO_hSai_Tx.hdmatx);
|
||
|
|
||
|
/* Update the SAI audio Transfer DMA mode */
|
||
|
BSP_AUDIO_hSai_Tx.hdmatx->Init.Mode = DMA_CIRCULAR;
|
||
|
|
||
|
/* Configure the DMA Stream with new Transfer DMA mode */
|
||
|
HAL_DMA_Init(BSP_AUDIO_hSai_Tx.hdmatx);
|
||
|
}
|
||
|
else /* BSP_AUDIO_OUT_NORMALMODE */
|
||
|
{
|
||
|
/* Deinitialize the Stream to update DMA mode */
|
||
|
HAL_DMA_DeInit(BSP_AUDIO_hSai_Tx.hdmatx);
|
||
|
|
||
|
/* Update the SAI audio Transfer DMA mode */
|
||
|
BSP_AUDIO_hSai_Tx.hdmatx->Init.Mode = DMA_NORMAL;
|
||
|
|
||
|
/* Configure the DMA Stream with new Transfer DMA mode */
|
||
|
HAL_DMA_Init(BSP_AUDIO_hSai_Tx.hdmatx);
|
||
|
}
|
||
|
|
||
|
/********** Playback Buffer stereo/mono mode **********/
|
||
|
if (AudioOutOption & BSP_AUDIO_OUT_STEREOMODE)
|
||
|
{
|
||
|
/* Disable SAI peripheral to allow access to SAI internal registers */
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
|
||
|
/* Update the SAI audio frame slot configuration */
|
||
|
BSP_AUDIO_hSai_Tx.Init.MonoStereoMode = SAI_STEREOMODE;
|
||
|
HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
|
||
|
|
||
|
/* Enable SAI peripheral to generate MCLK */
|
||
|
__HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
/* Transmit one byte to start FS generation */
|
||
|
HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000);
|
||
|
}
|
||
|
else /* BSP_AUDIO_OUT_MONOMODE */
|
||
|
{
|
||
|
/* Disable SAI peripheral to allow access to SAI internal registers */
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
|
||
|
/* Update the SAI audio frame slot configuration */
|
||
|
BSP_AUDIO_hSai_Tx.Init.MonoStereoMode = SAI_MONOMODE;
|
||
|
HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
|
||
|
|
||
|
/* Enable SAI peripheral to generate MCLK */
|
||
|
__HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
/* Transmit one byte to start FS generation */
|
||
|
HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief register user callback functions
|
||
|
* @param ErrorCallback: pointer to the error callback function
|
||
|
* @param HalfTransferCallback: pointer to the half transfer callback function
|
||
|
* @param TransferCompleteCallback: pointer to the transfer complete callback function
|
||
|
* @retval None
|
||
|
*/
|
||
|
void BSP_AUDIO_OUT_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
|
||
|
Audio_CallbackTypeDef HalfTransferCallback,
|
||
|
Audio_CallbackTypeDef TransferCompleteCallback)
|
||
|
{
|
||
|
hAudioOut.CbError = ErrorCallback;
|
||
|
hAudioOut.CbHalfTransfer = HalfTransferCallback;
|
||
|
hAudioOut.CbTransferComplete = TransferCompleteCallback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Tx Transfer completed callbacks.
|
||
|
* @param hsai: SAI handle
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
/* Invoke the registered 'TransferComplete' function (if any) */
|
||
|
if (hAudioOut.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioOut.CbTransferComplete();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Tx Half Transfer completed callbacks.
|
||
|
* @param hsai: SAI handle
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
/* Invoke the registered 'HalfTransfer' callback function (if any) */
|
||
|
if (hAudioOut.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioOut.CbHalfTransfer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief SAI error callbacks.
|
||
|
* @param hsai: SAI handle
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
/* Invoke the registered 'ErrorCallback' callback function (if any) */
|
||
|
if (hAudioOut.CbError != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioOut.CbError();
|
||
|
}
|
||
|
/* Invoke the registered 'ErrorCallback' callback function (if any) */
|
||
|
if (hAudioIn.CbError != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioIn.CbError();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/** @addtogroup STM32L496G_EVAL_AUDIO_Exported_Functions
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Initializes micropone related peripherals.
|
||
|
* @note This function assumes that the SAI input clock (through PLL_M)
|
||
|
* is already configured and ready to be used.
|
||
|
* @param AudioFreq: Audio frequency to be configured for the SAI peripheral.
|
||
|
* @param BitRes: Audio frequency to be configured for the SAI peripheral.
|
||
|
* @param ChnlNbr: Audio frequency to be configured for the SAI peripheral.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
|
||
|
{
|
||
|
return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC, AudioFreq, BitRes, ChnlNbr);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Initialize wave recording.
|
||
|
* @param InputDevice: INPUT_DEVICE_DIGITAL_MIC, INPUT_DEVICE_DIGITAL_MIC1,
|
||
|
* INPUT_DEVICE_DIGITAL_MIC2 or INPUT_DEVICE_ANALOG_MIC.
|
||
|
* @param AudioFreq: Audio frequency to be configured.
|
||
|
* @param BitRes: Audio bit resolution to be configured..
|
||
|
* @param ChnlNbr: Number of channel to be configured.
|
||
|
* @retval AUDIO_OK if correct communication, else wrong communication
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
|
||
|
{
|
||
|
/* Update the audio input context */
|
||
|
hAudioIn.AudioDrv = &cs42l51_drv;
|
||
|
hAudioIn.InputDevice = InputDevice;
|
||
|
hAudioIn.Frequency = AudioFreq;
|
||
|
hAudioIn.BitResolution = BitRes;
|
||
|
hAudioIn.ChannelNbr = ChnlNbr;
|
||
|
hAudioIn.CbError = (Audio_CallbackTypeDef)NULL;
|
||
|
hAudioIn.CbHalfTransfer = (Audio_CallbackTypeDef)NULL;
|
||
|
hAudioIn.CbTransferComplete = (Audio_CallbackTypeDef)NULL;
|
||
|
|
||
|
/* Check channel number according device : only record mono with analog mic and stereo with digital mic are allowed */
|
||
|
if (((InputDevice == INPUT_DEVICE_DIGITAL_MIC) && (ChnlNbr == 1)) ||
|
||
|
((InputDevice == INPUT_DEVICE_DIGITAL_MIC1) && (ChnlNbr == 2)) ||
|
||
|
((InputDevice == INPUT_DEVICE_DIGITAL_MIC2) && (ChnlNbr == 2)) ||
|
||
|
((InputDevice == INPUT_DEVICE_ANALOG_MIC) && (ChnlNbr == 2)))
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Check if output device is currently used */
|
||
|
if (hAudioOut.OutputDevice != 0)
|
||
|
{
|
||
|
/* If output device is currently used, SAI PLL is already initialized */
|
||
|
/* Check that AudioFreq for record and playback is the same */
|
||
|
if (hAudioIn.Frequency != hAudioOut.Frequency)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Configure the SAI PLL according to the requested audio frequency */
|
||
|
if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
/* Initializes the Digital Filter for Sigma-Delta Modulators interface */
|
||
|
if (AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* If output device is currently used, SAI is already initialized */
|
||
|
if (hAudioOut.OutputDevice == 0)
|
||
|
{
|
||
|
/* SAI data transfer preparation: prepare the Media to be used for the audio
|
||
|
transfer from SAI peripheral to memory. */
|
||
|
if (AUDIO_SAIx_Init(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Initialize the audio codec internal registers */
|
||
|
if (hAudioIn.AudioDrv->Init(AUDIO_I2C_ADDRESS,
|
||
|
(hAudioOut.OutputDevice | hAudioIn.InputDevice),
|
||
|
hAudioOut.Volume,
|
||
|
AudioFreq) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Initialise transfer control flag */
|
||
|
DmaLeftRecHalfBuffCplt = 0;
|
||
|
DmaLeftRecBuffCplt = 0;
|
||
|
DmaRightRecHalfBuffCplt = 0;
|
||
|
DmaRightRecBuffCplt = 0;
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-Initializes microphone related peripherals.
|
||
|
* @retval BSP AUDIO status
|
||
|
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_DeInit(void)
|
||
|
{
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
/* De-initializes the Digital Filter for Sigma-Delta Modulators interface */
|
||
|
if (AUDIO_DFSDMx_DeInit() != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* Check if output device is currently used */
|
||
|
if (hAudioOut.OutputDevice != 0)
|
||
|
{
|
||
|
/* Reset record path on audio codec */
|
||
|
if (hAudioOut.AudioDrv->Init(AUDIO_I2C_ADDRESS,
|
||
|
hAudioOut.OutputDevice,
|
||
|
(uint8_t) hAudioOut.Volume,
|
||
|
hAudioOut.Frequency) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* De-initializes SAI interface */
|
||
|
if (AUDIO_SAIx_DeInit() != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* DeInit audio codec */
|
||
|
hAudioIn.AudioDrv->DeInit();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Disable SAI PLL if no more device is used */
|
||
|
if (hAudioOut.OutputDevice == 0)
|
||
|
{
|
||
|
if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Reset the audio input context */
|
||
|
memset(&hAudioIn, 0, sizeof(hAudioIn));
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Starts audio recording.
|
||
|
* @param pbuf: Main buffer pointer for the recorded data storing
|
||
|
* @param size: Current size of the recorded buffer
|
||
|
* @note The Right channel is start at first with synchro on start of Left channel
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_Record(uint16_t *pbuf, uint32_t size)
|
||
|
{
|
||
|
hAudioIn.pRecBuf = pbuf;
|
||
|
hAudioIn.RecSize = size;
|
||
|
|
||
|
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/* Allocate hAudioIn.LeftRecBuff buffer */
|
||
|
#if defined(BSP_AUDIO_USE_RTOS)
|
||
|
hAudioIn.LeftRecBuff = (int32_t *)k_malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
|
||
|
#else
|
||
|
hAudioIn.LeftRecBuff = (int32_t *)malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
|
||
|
#endif
|
||
|
if (hAudioIn.LeftRecBuff == NULL)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/* Allocate hAudioIn.RightRecBuff buffer */
|
||
|
#if defined(BSP_AUDIO_USE_RTOS)
|
||
|
hAudioIn.RightRecBuff = (int32_t *)k_malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
|
||
|
#else
|
||
|
hAudioIn.RightRecBuff = (int32_t *)malloc((size / hAudioIn.ChannelNbr) * sizeof(int32_t));
|
||
|
#endif
|
||
|
if (hAudioIn.RightRecBuff == NULL)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/* Call the Media layer start function for right channel */
|
||
|
if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmRightFilter,
|
||
|
(int32_t *)hAudioIn.RightRecBuff,
|
||
|
(hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/* Call the Media layer start function for left channel */
|
||
|
if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter,
|
||
|
(int32_t *)hAudioIn.LeftRecBuff,
|
||
|
(hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* Call the audio Codec Play function */
|
||
|
if (hAudioIn.AudioDrv->Play(AUDIO_I2C_ADDRESS, pbuf, size) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Start the process receive DMA */
|
||
|
if (HAL_OK != HAL_SAI_Receive_DMA(&BSP_AUDIO_hSai_Rx, (uint8_t *)pbuf, size))
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Updates the audio frequency.
|
||
|
* @param AudioFreq: Audio frequency used to record the audio stream.
|
||
|
* @note This API should be called after the BSP_AUDIO_IN_Init() to adjust the
|
||
|
* audio frequency.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_SetFrequency(uint32_t AudioFreq)
|
||
|
{
|
||
|
uint8_t TxData[2] = {0x00, 0x00};
|
||
|
|
||
|
/* Configure the SAI PLL according to the requested audio frequency */
|
||
|
if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
/* De-initializes the Digital Filter for Sigma-Delta Modulators interface */
|
||
|
if (AUDIO_DFSDMx_DeInit() != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Initializes the Digital Filter for Sigma-Delta Modulators interface */
|
||
|
if (AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* Disable SAI peripheral to allow access to SAI internal registers */
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
|
||
|
|
||
|
/* Update the SAI audio frequency configuration */
|
||
|
BSP_AUDIO_hSai_Tx.Init.Mckdiv = SAIClockDivider(AudioFreq);
|
||
|
HAL_SAI_Init(&BSP_AUDIO_hSai_Tx);
|
||
|
BSP_AUDIO_hSai_Rx.Init.Mckdiv = SAIClockDivider(AudioFreq);
|
||
|
HAL_SAI_Init(&BSP_AUDIO_hSai_Rx);
|
||
|
|
||
|
/* Enable SAI peripheral to generate MCLK */
|
||
|
__HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
/* Transmit one byte to start FS generation */
|
||
|
if (HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hAudioIn.Frequency = AudioFreq;
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Regular conversion complete callback.
|
||
|
* @note In interrupt mode, user has to read conversion value in this function
|
||
|
using HAL_DFSDM_FilterGetRegularValue.
|
||
|
* @param hdfsdm_filter : DFSDM filter handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||
|
{
|
||
|
uint32_t index;
|
||
|
uint32_t recbufsize = (hAudioIn.RecSize / hAudioIn.ChannelNbr);
|
||
|
|
||
|
if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)
|
||
|
{
|
||
|
for (index = (recbufsize / 2); index < recbufsize; index++)
|
||
|
{
|
||
|
hAudioIn.pRecBuf[2 * index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
|
||
|
hAudioIn.pRecBuf[(2 * index) + 1] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
|
||
|
}
|
||
|
}
|
||
|
else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
for (index = (recbufsize / 2); index < recbufsize; index++)
|
||
|
{
|
||
|
hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
|
||
|
}
|
||
|
}
|
||
|
else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
for (index = (recbufsize / 2); index < recbufsize; index++)
|
||
|
{
|
||
|
hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Invoke the registered 'TransferCompete' callback function (if any) */
|
||
|
if (hAudioIn.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
if (hdfsdm_filter == &BSP_AUDIO_hDfsdmLeftFilter)
|
||
|
{
|
||
|
if (DmaLeftRecBuffCplt)
|
||
|
{
|
||
|
BSP_ErrorHandler();
|
||
|
}
|
||
|
|
||
|
DmaLeftRecBuffCplt = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (DmaRightRecBuffCplt)
|
||
|
{
|
||
|
BSP_ErrorHandler();
|
||
|
}
|
||
|
|
||
|
DmaRightRecBuffCplt = 1;
|
||
|
}
|
||
|
|
||
|
if (((DmaLeftRecBuffCplt != 0) && (DmaRightRecBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)) ||
|
||
|
((DmaLeftRecBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)) ||
|
||
|
((DmaRightRecBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
|
||
|
{
|
||
|
hAudioIn.CbTransferComplete();
|
||
|
DmaLeftRecBuffCplt = 0;
|
||
|
DmaRightRecBuffCplt = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Half regular conversion complete callback.
|
||
|
* @param hdfsdm_filter : DFSDM filter handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||
|
{
|
||
|
uint32_t index;
|
||
|
uint32_t recbufsize = (hAudioIn.RecSize / hAudioIn.ChannelNbr);
|
||
|
|
||
|
if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)
|
||
|
{
|
||
|
for (index = 0; index < (recbufsize / 2); index++)
|
||
|
{
|
||
|
hAudioIn.pRecBuf[2 * index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
|
||
|
hAudioIn.pRecBuf[(2 * index) + 1] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
|
||
|
}
|
||
|
}
|
||
|
else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
for (index = 0; index < (recbufsize / 2); index++)
|
||
|
{
|
||
|
hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32768, 32767));
|
||
|
}
|
||
|
}
|
||
|
else if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
for (index = 0; index < (recbufsize / 2); index++)
|
||
|
{
|
||
|
hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.RightRecBuff[index] >> 8), -32768, 32767));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Invoke the registered 'HalfTransfer' callback function (if any) */
|
||
|
if (hAudioIn.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
if (hdfsdm_filter == &BSP_AUDIO_hDfsdmLeftFilter)
|
||
|
{
|
||
|
if (DmaLeftRecHalfBuffCplt)
|
||
|
{
|
||
|
BSP_ErrorHandler();
|
||
|
}
|
||
|
|
||
|
DmaLeftRecHalfBuffCplt = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (DmaRightRecHalfBuffCplt)
|
||
|
{
|
||
|
BSP_ErrorHandler();
|
||
|
}
|
||
|
|
||
|
DmaRightRecHalfBuffCplt = 1;
|
||
|
}
|
||
|
|
||
|
if (((DmaLeftRecHalfBuffCplt != 0) && (DmaRightRecHalfBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC)) ||
|
||
|
((DmaLeftRecHalfBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC1)) ||
|
||
|
((DmaRightRecHalfBuffCplt != 0) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
|
||
|
{
|
||
|
hAudioIn.CbHalfTransfer();
|
||
|
DmaLeftRecHalfBuffCplt = 0;
|
||
|
DmaRightRecHalfBuffCplt = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Error callback.
|
||
|
* @param hdfsdm_filter : DFSDM filter handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_FilterErrorCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||
|
{
|
||
|
/* Invoke the registered 'ErrorCallback' callback function (if any) */
|
||
|
if (hAudioIn.CbError != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioIn.CbError();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief SAI Rx Transfer completed callbacks.
|
||
|
* @param hsai: SAI handle
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
/* Invoke the registered 'TransferComplete' function (if any) */
|
||
|
if (hAudioIn.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioIn.CbTransferComplete();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief SAI Rx Half Transfer completed callbacks.
|
||
|
* @param hsai: SAI handle
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
/* Invoke the registered 'HalfTransfer' callback function (if any) */
|
||
|
if (hAudioIn.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
|
||
|
{
|
||
|
hAudioIn.CbHalfTransfer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Stops audio recording.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_Stop(void)
|
||
|
{
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/* Call the Media layer stop function for right channel */
|
||
|
if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/* Call the Media layer stop function for left channel */
|
||
|
if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/* Free hAudioIn.LeftRecBuff buffer */
|
||
|
#if defined(BSP_AUDIO_USE_RTOS)
|
||
|
k_free((void *)hAudioIn.LeftRecBuff);
|
||
|
#else
|
||
|
free((void *)hAudioIn.LeftRecBuff);
|
||
|
#endif
|
||
|
}
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/* Free hAudioIn.RightRecBuff buffer */
|
||
|
#if defined(BSP_AUDIO_USE_RTOS)
|
||
|
k_free((void *)hAudioIn.RightRecBuff);
|
||
|
#else
|
||
|
free((void *)hAudioIn.RightRecBuff);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* Call Audio Codec Stop function */
|
||
|
if (hAudioIn.AudioDrv->Stop(AUDIO_I2C_ADDRESS, CODEC_PDWN_HW) != 0)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Wait at least 100ms */
|
||
|
HAL_Delay(100);
|
||
|
|
||
|
/* Stop DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_DMAStop(&BSP_AUDIO_hSai_Rx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Pauses the audio file stream.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_Pause(void)
|
||
|
{
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
/* Call the Media layer stop function */
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
if (HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* Pause DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_DMAPause(&BSP_AUDIO_hSai_Rx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Resumes the audio file stream.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
uint8_t BSP_AUDIO_IN_Resume(void)
|
||
|
{
|
||
|
if (hAudioIn.InputDevice != INPUT_DEVICE_ANALOG_MIC)
|
||
|
{
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/* Call the Media layer start function for right channel */
|
||
|
if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmRightFilter,
|
||
|
(int32_t *)hAudioIn.RightRecBuff,
|
||
|
(hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/* Call the Media layer start function for left channel */
|
||
|
if (HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter,
|
||
|
(int32_t *)hAudioIn.LeftRecBuff,
|
||
|
(hAudioIn.RecSize / hAudioIn.ChannelNbr)) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* INPUT_DEVICE_ANALOG_MIC */
|
||
|
/* Resume DMA transfer of PCM samples towards the serial audio interface */
|
||
|
if (HAL_SAI_DMAResume(&BSP_AUDIO_hSai_Rx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief register user callback functions
|
||
|
* @param ErrorCallback: pointer to the error callback function
|
||
|
* @param HalfTransferCallback: pointer to the half transfer callback function
|
||
|
* @param TransferCompleteCallback: pointer to the transfer complete callback function
|
||
|
* @retval None
|
||
|
*/
|
||
|
void BSP_AUDIO_IN_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
|
||
|
Audio_CallbackTypeDef HalfTransferCallback,
|
||
|
Audio_CallbackTypeDef TransferCompleteCallback)
|
||
|
{
|
||
|
hAudioIn.CbError = ErrorCallback;
|
||
|
hAudioIn.CbHalfTransfer = HalfTransferCallback;
|
||
|
hAudioIn.CbTransferComplete = TransferCompleteCallback;
|
||
|
}
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/* private functions --------------------------------------------------------*/
|
||
|
/** @addtogroup STM32L496G_DISCOVERY_AUDIO_Private_Functions
|
||
|
* @{
|
||
|
*/
|
||
|
/**
|
||
|
* @brief Initializes the Audio Codec audio interface (SAI).
|
||
|
* @param AudioFreq: Audio frequency to be configured for the SAI peripheral.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq)
|
||
|
{
|
||
|
uint8_t TxData[2] = {0x00, 0x00};
|
||
|
|
||
|
/* Initialize the BSP_AUDIO_hSai_Xx instances parameter */
|
||
|
BSP_AUDIO_hSai_Tx.Instance = SAI1_Block_A;
|
||
|
BSP_AUDIO_hSai_Rx.Instance = SAI1_Block_B;
|
||
|
|
||
|
/* Disable SAI peripheral to allow access to SAI internal registers */
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
|
||
|
|
||
|
/*******************************/
|
||
|
/* SAI block used for playback */
|
||
|
/*******************************/
|
||
|
/* Configure SAI_Block_x used for transmit
|
||
|
LSBFirst: Disabled
|
||
|
DataSize: 16 */
|
||
|
BSP_AUDIO_hSai_Tx.Init.AudioMode = SAI_MODEMASTER_TX;
|
||
|
BSP_AUDIO_hSai_Tx.Init.Synchro = SAI_ASYNCHRONOUS;
|
||
|
BSP_AUDIO_hSai_Tx.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
|
||
|
BSP_AUDIO_hSai_Tx.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
|
||
|
BSP_AUDIO_hSai_Tx.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
|
||
|
BSP_AUDIO_hSai_Tx.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
|
||
|
BSP_AUDIO_hSai_Tx.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
|
||
|
BSP_AUDIO_hSai_Tx.Init.Mckdiv = SAIClockDivider(AudioFreq);
|
||
|
BSP_AUDIO_hSai_Tx.Init.MonoStereoMode = SAI_STEREOMODE;
|
||
|
BSP_AUDIO_hSai_Tx.Init.CompandingMode = SAI_NOCOMPANDING;
|
||
|
BSP_AUDIO_hSai_Tx.Init.TriState = SAI_OUTPUT_NOTRELEASED;
|
||
|
BSP_AUDIO_hSai_Tx.Init.Protocol = SAI_FREE_PROTOCOL;
|
||
|
BSP_AUDIO_hSai_Tx.Init.DataSize = SAI_DATASIZE_16;
|
||
|
BSP_AUDIO_hSai_Tx.Init.FirstBit = SAI_FIRSTBIT_MSB;
|
||
|
BSP_AUDIO_hSai_Tx.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
|
||
|
|
||
|
/* Configure SAI_Block_x Frame
|
||
|
Frame Length: 32
|
||
|
Frame active Length: 16
|
||
|
FS Definition: Start frame + Channel Side identification
|
||
|
FS Polarity: FS active Low
|
||
|
FS Offset: FS asserted one bit before the first bit of slot 0 */
|
||
|
BSP_AUDIO_hSai_Tx.FrameInit.FrameLength = 32;
|
||
|
BSP_AUDIO_hSai_Tx.FrameInit.ActiveFrameLength = 16;
|
||
|
BSP_AUDIO_hSai_Tx.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
|
||
|
BSP_AUDIO_hSai_Tx.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
|
||
|
BSP_AUDIO_hSai_Tx.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
|
||
|
|
||
|
/* Configure SAI Block_x Slot
|
||
|
Slot First Bit Offset: 0
|
||
|
Slot Size : 16
|
||
|
Slot Number: 2
|
||
|
Slot Active: Slots 0 and 1 actives */
|
||
|
BSP_AUDIO_hSai_Tx.SlotInit.FirstBitOffset = 0;
|
||
|
BSP_AUDIO_hSai_Tx.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
|
||
|
BSP_AUDIO_hSai_Tx.SlotInit.SlotNumber = 2;
|
||
|
BSP_AUDIO_hSai_Tx.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
|
||
|
|
||
|
/*****************************/
|
||
|
/* SAI block used for record */
|
||
|
/*****************************/
|
||
|
/* Configure SAI_Block_x used for receive
|
||
|
LSBFirst: Disabled
|
||
|
DataSize: 16 */
|
||
|
BSP_AUDIO_hSai_Rx.Init.AudioMode = SAI_MODESLAVE_RX;
|
||
|
BSP_AUDIO_hSai_Rx.Init.Synchro = SAI_SYNCHRONOUS;
|
||
|
BSP_AUDIO_hSai_Rx.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
|
||
|
BSP_AUDIO_hSai_Rx.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
|
||
|
BSP_AUDIO_hSai_Rx.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
|
||
|
BSP_AUDIO_hSai_Rx.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
|
||
|
BSP_AUDIO_hSai_Rx.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
|
||
|
BSP_AUDIO_hSai_Rx.Init.Mckdiv = SAIClockDivider(AudioFreq);
|
||
|
BSP_AUDIO_hSai_Rx.Init.MonoStereoMode = SAI_MONOMODE;
|
||
|
BSP_AUDIO_hSai_Rx.Init.CompandingMode = SAI_NOCOMPANDING;
|
||
|
BSP_AUDIO_hSai_Rx.Init.TriState = SAI_OUTPUT_NOTRELEASED;
|
||
|
BSP_AUDIO_hSai_Rx.Init.Protocol = SAI_FREE_PROTOCOL;
|
||
|
BSP_AUDIO_hSai_Rx.Init.DataSize = SAI_DATASIZE_16;
|
||
|
BSP_AUDIO_hSai_Rx.Init.FirstBit = SAI_FIRSTBIT_MSB;
|
||
|
BSP_AUDIO_hSai_Rx.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
|
||
|
|
||
|
/* Configure SAI_Block_x Frame
|
||
|
Frame Length: 32
|
||
|
Frame active Length: 16
|
||
|
FS Definition: Start frame + Channel Side identification
|
||
|
FS Polarity: FS active Low
|
||
|
FS Offset: FS asserted one bit before the first bit of slot 0 */
|
||
|
BSP_AUDIO_hSai_Rx.FrameInit.FrameLength = 32;
|
||
|
BSP_AUDIO_hSai_Rx.FrameInit.ActiveFrameLength = 16;
|
||
|
BSP_AUDIO_hSai_Rx.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
|
||
|
BSP_AUDIO_hSai_Rx.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
|
||
|
BSP_AUDIO_hSai_Rx.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
|
||
|
|
||
|
/* Configure SAI Block_x Slot
|
||
|
Slot First Bit Offset: 0
|
||
|
Slot Size : 16
|
||
|
Slot Number: 2
|
||
|
Slot Active: Slots 0 and 1 actives */
|
||
|
BSP_AUDIO_hSai_Rx.SlotInit.FirstBitOffset = 0;
|
||
|
BSP_AUDIO_hSai_Rx.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
|
||
|
BSP_AUDIO_hSai_Rx.SlotInit.SlotNumber = 2;
|
||
|
BSP_AUDIO_hSai_Rx.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
|
||
|
|
||
|
/*********************************/
|
||
|
/* Initializes the SAI peripheral*/
|
||
|
/*********************************/
|
||
|
if (HAL_SAI_Init(&BSP_AUDIO_hSai_Tx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
if (HAL_SAI_Init(&BSP_AUDIO_hSai_Rx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/******************************************/
|
||
|
/* Enable SAI peripheral to generate MCLK */
|
||
|
/******************************************/
|
||
|
__HAL_SAI_ENABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
/* Transmit one byte to start FS generation */
|
||
|
if (HAL_SAI_Transmit(&BSP_AUDIO_hSai_Tx, TxData, 2, 1000) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-initializes the Audio Codec audio interface (SAI).
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
static uint8_t AUDIO_SAIx_DeInit(void)
|
||
|
{
|
||
|
/* Disable the SAI audio block */
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Tx);
|
||
|
__HAL_SAI_DISABLE(&BSP_AUDIO_hSai_Rx);
|
||
|
|
||
|
/* De-initializes the SAI peripheral */
|
||
|
if (HAL_SAI_DeInit(&BSP_AUDIO_hSai_Tx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
if (HAL_SAI_DeInit(&BSP_AUDIO_hSai_Rx) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief SAI MSP Init
|
||
|
* @param hsai : pointer to a SAI_HandleTypeDef structure
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||
|
|
||
|
/* Enable SAI clock */
|
||
|
__HAL_RCC_SAI1_CLK_ENABLE();
|
||
|
|
||
|
if (hsai->Instance == SAI1_Block_A)
|
||
|
{
|
||
|
/* SAI pins configuration: FS, SCK, MCLK and SD pins */
|
||
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||
|
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||
|
GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_2;
|
||
|
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_MCLK_A */
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_4;
|
||
|
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_FS_A */
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_10;
|
||
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* SAI1_SCK_A */
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_6;
|
||
|
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_SD_A */
|
||
|
|
||
|
/* Configure the hDmaSaiTx handle parameters */
|
||
|
__HAL_RCC_DMA2_CLK_ENABLE();
|
||
|
hDmaSaiTx.Init.Request = DMA_REQUEST_1;
|
||
|
hDmaSaiTx.Init.Direction = DMA_MEMORY_TO_PERIPH;
|
||
|
hDmaSaiTx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||
|
hDmaSaiTx.Init.MemInc = DMA_MINC_ENABLE;
|
||
|
hDmaSaiTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||
|
hDmaSaiTx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||
|
hDmaSaiTx.Init.Mode = DMA_CIRCULAR;
|
||
|
hDmaSaiTx.Init.Priority = DMA_PRIORITY_HIGH;
|
||
|
hDmaSaiTx.Instance = DMA2_Channel1;
|
||
|
/* Associate the DMA handle */
|
||
|
__HAL_LINKDMA(hsai, hdmatx, hDmaSaiTx);
|
||
|
/* Deinitialize the Stream for new transfer */
|
||
|
HAL_DMA_DeInit(&hDmaSaiTx);
|
||
|
/* Configure the DMA Stream */
|
||
|
HAL_DMA_Init(&hDmaSaiTx);
|
||
|
/* SAI DMA IRQ Channel configuration */
|
||
|
HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 5, 0);
|
||
|
HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
|
||
|
}
|
||
|
else /* SAI1_BlockB */
|
||
|
{
|
||
|
/* SAI pins configuration: SD pin */
|
||
|
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||
|
GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_3;
|
||
|
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SAI1_SD_B */
|
||
|
|
||
|
/* Configure the hDmaSaiRx handle parameters */
|
||
|
__HAL_RCC_DMA2_CLK_ENABLE();
|
||
|
hDmaSaiRx.Init.Request = DMA_REQUEST_1;
|
||
|
hDmaSaiRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||
|
hDmaSaiRx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||
|
hDmaSaiRx.Init.MemInc = DMA_MINC_ENABLE;
|
||
|
hDmaSaiRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||
|
hDmaSaiRx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||
|
hDmaSaiRx.Init.Mode = DMA_CIRCULAR;
|
||
|
hDmaSaiRx.Init.Priority = DMA_PRIORITY_HIGH;
|
||
|
hDmaSaiRx.Instance = DMA2_Channel2;
|
||
|
/* Associate the DMA handle */
|
||
|
__HAL_LINKDMA(hsai, hdmarx, hDmaSaiRx);
|
||
|
/* Deinitialize the Stream for new transfer */
|
||
|
HAL_DMA_DeInit(&hDmaSaiRx);
|
||
|
/* Configure the DMA Stream */
|
||
|
HAL_DMA_Init(&hDmaSaiRx);
|
||
|
/* SAI DMA IRQ Channel configuration */
|
||
|
HAL_NVIC_SetPriority(DMA2_Channel2_IRQn, 5, 0);
|
||
|
HAL_NVIC_EnableIRQ(DMA2_Channel2_IRQn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief SAI MSP De-init
|
||
|
* @param hsai : pointer to a SAI_HandleTypeDef structure
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai)
|
||
|
{
|
||
|
if (hsai->Instance == SAI1_Block_A)
|
||
|
{
|
||
|
/* Disable SAI DMA Channel IRQ */
|
||
|
HAL_NVIC_DisableIRQ(DMA2_Channel1_IRQn);
|
||
|
|
||
|
/* Reset the DMA Stream configuration*/
|
||
|
HAL_DMA_DeInit(&hDmaSaiTx);
|
||
|
|
||
|
/* De-initialize FS, SCK, MCK and SD pins*/
|
||
|
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2); /* SAI1_MCLK_A */
|
||
|
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4); /* SAI1_FS_A */
|
||
|
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10); /* SAI1_SCK_A */
|
||
|
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_6); /* SAI1_SD_A */
|
||
|
|
||
|
/* Don't disable SAI clock used for other SAI block */
|
||
|
/*__HAL_RCC_SAI1_CLK_DISABLE(); */
|
||
|
}
|
||
|
else /* SAI1_BlockB */
|
||
|
{
|
||
|
/* Disable SAI DMA Channel IRQ */
|
||
|
HAL_NVIC_DisableIRQ(DMA2_Channel2_IRQn);
|
||
|
|
||
|
/* Reset the DMA Stream configuration*/
|
||
|
HAL_DMA_DeInit(&hDmaSaiRx);
|
||
|
|
||
|
/* De-initialize SD pin */
|
||
|
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_3); /* SAI1_SD_B */
|
||
|
|
||
|
/* Disable SAI clock */
|
||
|
__HAL_RCC_SAI1_CLK_DISABLE();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/** @addtogroup STM32L496G_DISCOVERY_AUDIO_Private_Functions
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @brief Initializes the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
|
||
|
* @param AudioFreq: Audio frequency to be used to set correctly the DFSDM peripheral.
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
static uint8_t AUDIO_DFSDMx_Init(uint32_t AudioFreq)
|
||
|
{
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/*####CHANNEL 3####*/
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Activation = ENABLE;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
|
||
|
/* Set the DFSDM clock OUT audio frequency configuration */
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Divider = DFSDMClockDivider(AudioFreq);
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS;
|
||
|
/* Request to sample stable data for LEFT micro on Rising edge */
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.Awd.Oversampling = 10;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.Offset = 0;
|
||
|
hAudioIn.hDfsdmLeftChannel.Init.RightBitShift = DFSDMRightBitShift(AudioFreq);
|
||
|
hAudioIn.hDfsdmLeftChannel.Instance = DFSDM1_Channel3;
|
||
|
|
||
|
/* Init the DFSDM Channel */
|
||
|
if (HAL_DFSDM_ChannelInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/*####CHANNEL 2####*/
|
||
|
hAudioIn.hDfsdmRightChannel.Init.OutputClock.Activation = ENABLE;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
|
||
|
/* Set the DFSDM clock OUT audio frequency configuration */
|
||
|
hAudioIn.hDfsdmRightChannel.Init.OutputClock.Divider = DFSDMClockDivider(AudioFreq);
|
||
|
hAudioIn.hDfsdmRightChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS;
|
||
|
/* Request to sample stable data for LEFT micro on Rising edge */
|
||
|
hAudioIn.hDfsdmRightChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.Awd.Oversampling = 10;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.Offset = 0;
|
||
|
hAudioIn.hDfsdmRightChannel.Init.RightBitShift = DFSDMRightBitShift(AudioFreq);
|
||
|
hAudioIn.hDfsdmRightChannel.Instance = DFSDM1_Channel2;
|
||
|
|
||
|
/* Init the DFSDM Channel */
|
||
|
if (HAL_DFSDM_ChannelInit(&hAudioIn.hDfsdmRightChannel) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
/*####FILTER 0####*/
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.FastMode = ENABLE;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.DmaMode = ENABLE;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ScanMode = DISABLE;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.DmaMode = DISABLE;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.SincOrder = DFSDMFilterOrder(AudioFreq);
|
||
|
/* Set the DFSDM Filters Oversampling to have correct sample rate */
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.Oversampling = DFSDMOverSampling(AudioFreq);
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.IntOversampling = 1;
|
||
|
BSP_AUDIO_hDfsdmLeftFilter.Instance = DFSDM1_Filter0;
|
||
|
|
||
|
/* Init the DFSDM Filter */
|
||
|
if (HAL_DFSDM_FilterInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure regular channel */
|
||
|
if (HAL_DFSDM_FilterConfigRegChannel(&BSP_AUDIO_hDfsdmLeftFilter,
|
||
|
DFSDM_CHANNEL_3,
|
||
|
DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/*####FILTER 1####*/
|
||
|
if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER;
|
||
|
}
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.FastMode = ENABLE;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.RegularParam.DmaMode = ENABLE;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.ScanMode = DISABLE;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.DmaMode = DISABLE;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.FilterParam.SincOrder = DFSDMFilterOrder(AudioFreq);
|
||
|
/* Set the DFSDM Filters Oversampling to have correct sample rate */
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.FilterParam.Oversampling = DFSDMOverSampling(AudioFreq);
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Init.FilterParam.IntOversampling = 1;
|
||
|
BSP_AUDIO_hDfsdmRightFilter.Instance = DFSDM1_Filter1;
|
||
|
|
||
|
/* Init the DFSDM Filter */
|
||
|
if (HAL_DFSDM_FilterInit(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
/* Configure regular channel */
|
||
|
if (HAL_DFSDM_FilterConfigRegChannel(&BSP_AUDIO_hDfsdmRightFilter,
|
||
|
DFSDM_CHANNEL_2,
|
||
|
DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-initializes the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
|
||
|
* @retval BSP AUDIO status
|
||
|
*/
|
||
|
static uint8_t AUDIO_DFSDMx_DeInit(void)
|
||
|
{
|
||
|
/* De-initializes the DFSDM filters to allow access to DFSDM internal registers */
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
if (HAL_DFSDM_FilterDeInit(&BSP_AUDIO_hDfsdmRightFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
if (HAL_DFSDM_FilterDeInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* De-initializes the DFSDM channels to allow access to DFSDM internal registers */
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC2) == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
if (HAL_DFSDM_ChannelDeInit(&hAudioIn.hDfsdmRightChannel) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
if ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) == INPUT_DEVICE_DIGITAL_MIC1)
|
||
|
{
|
||
|
if (HAL_DFSDM_ChannelDeInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* DFSDM reset */
|
||
|
__HAL_RCC_DFSDM1_FORCE_RESET();
|
||
|
__HAL_RCC_DFSDM1_RELEASE_RESET();
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Initializes the DFSDM channel MSP.
|
||
|
* @param hdfsdm_channel : DFSDM channel handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel)
|
||
|
{
|
||
|
if (((hdfsdm_channel->Instance == DFSDM1_Channel3) && ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) != 0)) || \
|
||
|
((hdfsdm_channel->Instance == DFSDM1_Channel2) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
|
||
|
{
|
||
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||
|
|
||
|
/* Enable DFSDM clock */
|
||
|
__HAL_RCC_DFSDM1_CLK_ENABLE();
|
||
|
|
||
|
/* DFSDM pins configuration: DFSDM1_CKOUT, DFSDM1_DATIN3 pins */
|
||
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||
|
GPIO_InitStruct.Alternate = GPIO_AF6_DFSDM1;
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_2;
|
||
|
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* DFSDM1_CKOUT */
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_7;
|
||
|
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* DFSDM1_DATIN3 */
|
||
|
|
||
|
/* Enable MIC_VDD (PH1) */
|
||
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
||
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||
|
GPIO_InitStruct.Pin = GPIO_PIN_1;
|
||
|
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
|
||
|
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, GPIO_PIN_SET);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-initializes the DFSDM channel MSP.
|
||
|
* @param hdfsdm_channel : DFSDM channel handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel)
|
||
|
{
|
||
|
if (((hdfsdm_channel->Instance == DFSDM1_Channel3) && ((hAudioIn.InputDevice & INPUT_DEVICE_DIGITAL_MIC1) != 0)) || \
|
||
|
((hdfsdm_channel->Instance == DFSDM1_Channel2) && (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)))
|
||
|
{
|
||
|
/* Disable MIC_VDD (PH1) */
|
||
|
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, GPIO_PIN_RESET);
|
||
|
HAL_GPIO_DeInit(GPIOH, GPIO_PIN_1);
|
||
|
|
||
|
/* De-initialize DFSDM1_CKOUT, DFSDM1_DATIN3 pins */
|
||
|
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2); /* DFSDM1_CKOUT */
|
||
|
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_7); /* DFSDM1_DATIN3 */
|
||
|
|
||
|
/* Disable DFSDM1 */
|
||
|
__HAL_RCC_DFSDM1_CLK_DISABLE();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Initializes the DFSDM filter MSP.
|
||
|
* @param hdfsdm_filter : DFSDM filter handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||
|
{
|
||
|
if (hdfsdm_filter->Instance == DFSDM1_Filter0)
|
||
|
{
|
||
|
/* Enable the DMA clock */
|
||
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
||
|
|
||
|
/* Configure the hAudioIn.hDmaDfsdmLeft handle parameters */
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.Request = DMA_REQUEST_0;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.PeriphInc = DMA_PINC_DISABLE;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.MemInc = DMA_MINC_ENABLE;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.Mode = DMA_CIRCULAR;
|
||
|
hAudioIn.hDmaDfsdmLeft.Init.Priority = DMA_PRIORITY_HIGH;
|
||
|
hAudioIn.hDmaDfsdmLeft.Instance = DMA1_Channel4;
|
||
|
|
||
|
/* Associate the DMA handle */
|
||
|
__HAL_LINKDMA(hdfsdm_filter, hdmaReg, hAudioIn.hDmaDfsdmLeft);
|
||
|
|
||
|
/* Reset DMA handle state */
|
||
|
__HAL_DMA_RESET_HANDLE_STATE(&hAudioIn.hDmaDfsdmLeft);
|
||
|
|
||
|
/* Configure the DMA Channel */
|
||
|
HAL_DMA_Init(&hAudioIn.hDmaDfsdmLeft);
|
||
|
|
||
|
/* DMA IRQ Channel configuration */
|
||
|
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 5, 0);
|
||
|
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
|
||
|
}
|
||
|
else /* DFSDM1_Filter1 */
|
||
|
{
|
||
|
if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC2)
|
||
|
{
|
||
|
/* Enable the DMA clock needed if only MIC2 is used */
|
||
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
||
|
}
|
||
|
|
||
|
/* Configure the hAudioIn.hDmaDfsdmRight handle parameters */
|
||
|
hAudioIn.hDmaDfsdmRight.Init.Request = DMA_REQUEST_0;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.PeriphInc = DMA_PINC_DISABLE;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.MemInc = DMA_MINC_ENABLE;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.Mode = DMA_CIRCULAR;
|
||
|
hAudioIn.hDmaDfsdmRight.Init.Priority = DMA_PRIORITY_HIGH;
|
||
|
hAudioIn.hDmaDfsdmRight.Instance = DMA1_Channel5;
|
||
|
|
||
|
/* Associate the DMA handle */
|
||
|
__HAL_LINKDMA(hdfsdm_filter, hdmaReg, hAudioIn.hDmaDfsdmRight);
|
||
|
|
||
|
/* Reset DMA handle state */
|
||
|
__HAL_DMA_RESET_HANDLE_STATE(&hAudioIn.hDmaDfsdmRight);
|
||
|
|
||
|
/* Configure the DMA Channel */
|
||
|
HAL_DMA_Init(&hAudioIn.hDmaDfsdmRight);
|
||
|
|
||
|
/* DMA IRQ Channel configuration */
|
||
|
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 5, 0);
|
||
|
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief De-initializes the DFSDM filter MSP.
|
||
|
* @param hdfsdm_filter : DFSDM filter handle.
|
||
|
* @retval None
|
||
|
*/
|
||
|
void HAL_DFSDM_FilterMspDeInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
|
||
|
{
|
||
|
if (hdfsdm_filter->Instance == DFSDM1_Filter0)
|
||
|
{
|
||
|
/* Disable DMA Channel IRQ */
|
||
|
HAL_NVIC_DisableIRQ(DMA1_Channel4_IRQn);
|
||
|
|
||
|
/* De-initialize the DMA Channel */
|
||
|
HAL_DMA_DeInit(&hAudioIn.hDmaDfsdmLeft);
|
||
|
}
|
||
|
else /* DFSDM1_Filter1 */
|
||
|
{
|
||
|
/* Disable DMA Channel IRQ */
|
||
|
HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn);
|
||
|
|
||
|
/* De-initialize the DMA Channel */
|
||
|
HAL_DMA_DeInit(&hAudioIn.hDmaDfsdmRight);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Configures the SAI PLL clock according to the required audio frequency.
|
||
|
* @param Frequency: Audio frequency.
|
||
|
* @retval BSP AUDIO status
|
||
|
* @note The SAI PLL input clock must be configured in the user application.
|
||
|
* The SAI PLL configuration done within this function assumes that
|
||
|
* the SAI PLL input clock runs at 8 MHz.
|
||
|
*/
|
||
|
static uint8_t AUDIO_SAIPLLConfig(uint32_t Frequency)
|
||
|
{
|
||
|
RCC_PeriphCLKInitTypeDef RCC_ExCLKInitStruct;
|
||
|
|
||
|
/* Retrieve actual RCC configuration */
|
||
|
HAL_RCCEx_GetPeriphCLKConfig(&RCC_ExCLKInitStruct);
|
||
|
|
||
|
if ((Frequency == AUDIO_FREQUENCY_11K)
|
||
|
|| (Frequency == AUDIO_FREQUENCY_22K)
|
||
|
|| (Frequency == AUDIO_FREQUENCY_44K))
|
||
|
{
|
||
|
/* Configure PLLSAI prescalers */
|
||
|
/* SAI clock config
|
||
|
PLLSAI2_VCO= 8 Mhz * PLLSAI1N = 8 * 24 = VCO_192M
|
||
|
SAI_CK_x = PLLSAI2_VCO/PLLSAI1P = 192/17 = 11.294 Mhz */
|
||
|
RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
|
||
|
RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2N = 24;
|
||
|
RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2P = 17;
|
||
|
RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2ClockOut = RCC_PLLSAI2_SAI2CLK;
|
||
|
RCC_ExCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI2;
|
||
|
}
|
||
|
else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
|
||
|
{
|
||
|
/* SAI clock config
|
||
|
PLLSAI2_VCO= 8 Mhz * PLLSAI1N = 8 * 43 = VCO_344M
|
||
|
SAI_CK_x = PLLSAI1_VCO/PLLSAI2P = 344/7 = 49.142 Mhz */
|
||
|
RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
|
||
|
RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2N = 43;
|
||
|
RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2P = 7;
|
||
|
RCC_ExCLKInitStruct.PLLSAI2.PLLSAI2ClockOut = RCC_PLLSAI2_SAI2CLK;
|
||
|
RCC_ExCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI2;
|
||
|
}
|
||
|
|
||
|
if (HAL_RCCEx_PeriphCLKConfig(&RCC_ExCLKInitStruct) != HAL_OK)
|
||
|
{
|
||
|
return AUDIO_ERROR;
|
||
|
}
|
||
|
|
||
|
return AUDIO_OK;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|