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

/**
******************************************************************************
* @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>&copy; 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****/