Audio Demo with DISCO Board, takes control samples, waits for user input, samples regularly.
Dependencies: CMSIS_DSP_401 STM32L4xx_HAL_Driver mbed-src_DISO_AUDIO_DEMO
Diff: stm32l476g_discovery_audio.c
- Revision:
- 0:3eee9435dd17
diff -r 000000000000 -r 3eee9435dd17 stm32l476g_discovery_audio.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stm32l476g_discovery_audio.c Sun Dec 13 19:12:11 2015 +0000 @@ -0,0 +1,1071 @@ +/** + ****************************************************************************** + * @file stm32l476g_discovery_audio.c + * @author MCD Application Team + * @version V1.0.1 + * @date 16-September-2015 + * @brief This file provides a set of functions needed to manage the + * Audio driver for the STM32L476G-Discovery board. + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/*============================================================================== + User NOTES + +1. How To use this driver: +-------------------------- + + This driver supports STM32L4xx devices on STM32L476G-Discovery (MB1184) Discovery boards. + a) to play an audio file (all functions names start by BSP_AUDIO_OUT_xxx) + b) to record an audio file through MP34DT01TR, ST MEMS (all functions names start by BSP_AUDIO_IN_xxx) + +a) PLAY A FILE: +============== + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + 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_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + + + 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 playabck + + 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 stm32l476g_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 stm32l476g_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_Init( + AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...) + ) + This function configures all the hardware required for the audio application (DFSDM, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if the + configuration completes successfully. + + + 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 AUDIO_IN_STOP() to stop recording +==============================================================================*/ + +/* Includes ------------------------------------------------------------------*/ +#include <string.h> +#include "stm32l476g_discovery_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32L476G_DISCOVERY + * @{ + */ + +/** @defgroup STM32L476G_DISCOVERY_AUDIO STM32L476G-DISCOVERY AUDIO + * @brief This file includes the low layer driver for cs43l22 Audio Codec + * available on STM32L476G-Discovery board(MB1184). + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Types Private Types + * @{ + */ +typedef struct +{ + + Audio_CallbackTypeDef CbError; /* pointer to the callback function invoked when ... */ + Audio_CallbackTypeDef CbHalfTransfer; /* pointer to the callback function invoked when ... */ + Audio_CallbackTypeDef CbTransferComplete; /* pointer to the callback function invoked when ... */ +} AUDIO_OUT_TypeDef; + +typedef struct +{ + DFSDM_Channel_HandleTypeDef hDfsdmLeftChannel; /* DFSDM channel handle used for left channel */ + DMA_HandleTypeDef hDmaDfsdmLeft; /* DMA handle used for DFSDM regular conversions on left channel */ + int32_t * LeftRecBuff; /* Buffers for left samples */ + 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 STM32L476G_DISCOVERY_AUDIO_Private_Constants Private Constants + * @{ + */ +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup STM32L476G_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_SINC4_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC4_ORDER : DFSDM_FILTER_SINC5_ORDER \ + +#define DFSDMRightBitShift(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 2 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 3 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 3 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 0 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 3 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 3 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 7 : 0 \ + +/* Saturate the record PCM sample */ +#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N))) + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ +/** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Variables Private Variables + * @{ + */ +/* Audio output context information */ +static AUDIO_OUT_TypeDef hAudioOut; + +/* Audio input context information */ +static AUDIO_IN_TypeDef hAudioIn; + +/* SAI DMA handle */ +static DMA_HandleTypeDef hDmaSai; +/** + * @} + */ + +/* Exported variables ---------------------------------------------------------*/ +/** @defgroup STM32L476G_DISCOVERY_AUDIO_Exported_Variables Exported Variables + * @{ + */ +/* SAIx handle */ +SAI_HandleTypeDef BSP_AUDIO_hSai; + +/* DFSDM filter handle */ +DFSDM_Filter_HandleTypeDef BSP_AUDIO_hDfsdmLeftFilter; +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ +/** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Functions Private Functions + * @{ + */ +static void AUDIO_CODEC_Reset(void); +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 STM32L476G_DISCOVERY_AUDIO_Exported_Functions + * @{ + */ + +/** + * @brief Configures the audio codec related peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream.ion. + * @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. + */ + +/** + * @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(); + } +} + +/** + * @} + */ + +/** @addtogroup STM32L476G_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) +{ + /* Update the audio input context */ + hAudioIn.Frequency = AudioFreq; + hAudioIn.BitResolution = BitRes; + hAudioIn.ChannelNbr = ChnlNbr; + hAudioIn.CbError = (Audio_CallbackTypeDef)NULL; + hAudioIn.CbHalfTransfer = (Audio_CallbackTypeDef)NULL; + hAudioIn.CbTransferComplete = (Audio_CallbackTypeDef)NULL; + + /* Configure the SAI PLL according to the requested audio frequency */ + if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK) + { + return AUDIO_ERROR; + } + + /* Initializes the Digital Filter for Sigma-Delta Modulators interface */ + if(AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK) + { + return AUDIO_ERROR; + } + + return AUDIO_OK; + } + +/** + * @brief De-Initializes microphone related peripherals. + * @retval BSP AUDIO status + + */ +uint8_t BSP_AUDIO_IN_DeInit(void) +{ + /* De-initializes the Digital Filter for Sigma-Delta Modulators interface */ + if (AUDIO_DFSDMx_DeInit() != 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; + + /* Allocate hAudioIn.LeftRecBuff buffer */ +#if defined(BSP_AUDIO_USE_RTOS) + hAudioIn.LeftRecBuff = (int32_t *)k_malloc(size * sizeof(int32_t)); +#else + hAudioIn.LeftRecBuff = (int32_t *)malloc(size * sizeof(int32_t)); +#endif + if(hAudioIn.LeftRecBuff == NULL) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for left channel */ + if(HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter, + (int32_t*)hAudioIn.LeftRecBuff, + (hAudioIn.RecSize/DEFAULT_AUDIO_IN_CHANNEL_NBR)) != HAL_OK) + { + 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) +{ + /* Configure the SAI PLL according to the requested audio frequency */ + if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK) + { + return AUDIO_ERROR; + } + + /* 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; + } + + 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/DEFAULT_AUDIO_IN_CHANNEL_NBR); + + for(index = (recbufsize/2); index < recbufsize; index++) + { + hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32760, 32760)); + } + + /* Invoke the registered 'TransferComplete' function (if any) */ + if (hAudioIn.CbTransferComplete != (Audio_CallbackTypeDef)NULL) + { + hAudioIn.CbTransferComplete(); + } +} + +/** + * @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/DEFAULT_AUDIO_IN_CHANNEL_NBR); + + + for(index = 0; index < (recbufsize/2); index++) + { + hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32760, 32760)); + } + + /* Invoke the registered 'HalfTransfer' callback function (if any) */ + if (hAudioIn.CbHalfTransfer != (Audio_CallbackTypeDef)NULL) + { + hAudioIn.CbHalfTransfer(); + } +} + +/** + * @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 Stops audio recording. + * @retval BSP AUDIO status + */ +uint8_t BSP_AUDIO_IN_Stop(void) +{ + /* Call the Media layer stop function for left channel */ + if(HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK ) + { + return AUDIO_ERROR; + } + + /* Free hAudioIn.LeftRecBuff buffer */ +#if defined(BSP_AUDIO_USE_RTOS) + k_free((void *)hAudioIn.LeftRecBuff); +#else + free((void *)hAudioIn.LeftRecBuff); +#endif + + return AUDIO_OK; +} + +/** + * @brief Pauses the audio file stream. + * @retval BSP AUDIO status + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer stop function */ + if(HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != 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) +{ + /* Call the Media layer start function for left channel */ + if(HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter, + (int32_t*)hAudioIn.LeftRecBuff, + (hAudioIn.RecSize/DEFAULT_AUDIO_IN_CHANNEL_NBR)) != 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 STM32L476G_DISCOVERY_AUDIO_Private_Functions + * @{ + */ +/** + * @brief Initializes the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval BSP AUDIO status + */ +static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&BSP_AUDIO_hSai); + + /* Initialize the BSP_AUDIO_hSai Instance parameter */ + BSP_AUDIO_hSai.Instance = AUDIO_SAIx; + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + BSP_AUDIO_hSai.Init.AudioMode = SAI_MODEMASTER_TX; + BSP_AUDIO_hSai.Init.Synchro = SAI_ASYNCHRONOUS; + BSP_AUDIO_hSai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + BSP_AUDIO_hSai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; + BSP_AUDIO_hSai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + BSP_AUDIO_hSai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + BSP_AUDIO_hSai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV; + BSP_AUDIO_hSai.Init.Mckdiv = SAIClockDivider(AudioFreq); + BSP_AUDIO_hSai.Init.MonoStereoMode = SAI_STEREOMODE; + BSP_AUDIO_hSai.Init.CompandingMode = SAI_NOCOMPANDING; + BSP_AUDIO_hSai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + BSP_AUDIO_hSai.Init.Protocol = SAI_FREE_PROTOCOL; + BSP_AUDIO_hSai.Init.DataSize = SAI_DATASIZE_16; + BSP_AUDIO_hSai.Init.FirstBit = SAI_FIRSTBIT_MSB; + BSP_AUDIO_hSai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + + /* 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.FrameInit.FrameLength = 32; + BSP_AUDIO_hSai.FrameInit.ActiveFrameLength = 16; + BSP_AUDIO_hSai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + BSP_AUDIO_hSai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + BSP_AUDIO_hSai.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.SlotInit.FirstBitOffset = 0; + BSP_AUDIO_hSai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + BSP_AUDIO_hSai.SlotInit.SlotNumber = 2; + BSP_AUDIO_hSai.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1; + + /* Initializes the SAI peripheral*/ + if (HAL_SAI_Init(&BSP_AUDIO_hSai) != HAL_OK) + { + return AUDIO_ERROR; + } + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&BSP_AUDIO_hSai); + + 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); + + /* De-initializes the SAI peripheral */ + if (HAL_SAI_DeInit(&BSP_AUDIO_hSai) != HAL_OK) + { + return AUDIO_ERROR; + } + + /* Disable SAIx PLL */ + if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_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 */ + AUDIO_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_SAIx_MCK_SCK_SD_FS_ENABLE(); + + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + GPIO_InitStruct.Pin = AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SCK_PIN | AUDIO_SAIx_SD_PIN | AUDIO_SAIx_MCK_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = AUDIO_SAIx_MCK_SCK_SD_FS_AF; + HAL_GPIO_Init(AUDIO_SAIx_MCK_SCK_SD_FS_GPIO_PORT, &GPIO_InitStruct); + + /* Enable the DMA clock */ + AUDIO_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_SAIx) + { + /* Configure the hDmaSai handle parameters */ + hDmaSai.Init.Request = DMA_REQUEST_1; + hDmaSai.Init.Direction = DMA_MEMORY_TO_PERIPH; + hDmaSai.Init.PeriphInc = DMA_PINC_DISABLE; + hDmaSai.Init.MemInc = DMA_MINC_ENABLE; + hDmaSai.Init.PeriphDataAlignment = AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE; + hDmaSai.Init.MemDataAlignment = AUDIO_SAIx_DMAx_MEM_DATA_SIZE; + hDmaSai.Init.Mode = DMA_NORMAL; + hDmaSai.Init.Priority = DMA_PRIORITY_HIGH; + + hDmaSai.Instance = AUDIO_SAIx_DMAx_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hDmaSai); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hDmaSai); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hDmaSai); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_SAIx_DMAx_IRQ); +} + +/** + * @brief SAI MSP De-init + * @param hsai : pointer to a SAI_HandleTypeDef structure + * @retval None + */ +void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai) +{ + /* Disable SAI DMA Channel IRQ */ + HAL_NVIC_DisableIRQ(AUDIO_SAIx_DMAx_IRQ); + + /* Reset the DMA Stream configuration*/ + HAL_DMA_DeInit(&hDmaSai); + + /* Disable the DMA clock */ + AUDIO_SAIx_DMAx_CLK_DISABLE(); + + /* De-initialize FS, SCK, MCK and SD pins*/ + HAL_GPIO_DeInit(AUDIO_SAIx_MCK_SCK_SD_FS_GPIO_PORT, + AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SCK_PIN | AUDIO_SAIx_SD_PIN | AUDIO_SAIx_MCK_PIN); + + /* Disable GPIO clock */ + AUDIO_SAIx_MCK_SCK_SD_FS_DISABLE(); + + /* Disable SAI clock */ + AUDIO_SAIx_CLK_DISABLE(); +} + +/** + * @brief Resets the audio codec. It restores the default configuration of the + * codec (this function shall be called before initializing the codec). + * @retval None + */ + + +/** + * @} + */ + +/** @addtogroup STM32L476G_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) +{ + /*####CHANNEL 2####*/ + 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 = DFSDM_Channel2; + + /* Init the DFSDM Channel */ + if (HAL_DFSDM_ChannelInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK) + { + return AUDIO_ERROR; + } + + /*####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 = AUDIO_DFSDMx_LEFT_FILTER; + + /* 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_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 (HAL_DFSDM_FilterDeInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK) + { + return AUDIO_ERROR; + } + + /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */ + if (HAL_DFSDM_ChannelDeInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK) + { + return AUDIO_ERROR; + } + + /* Disable DFSDM clock */ + AUDIO_DFSDMx_CLK_DISABLE(); + + /* Disable SAIx PLL */ + if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK) + { + return AUDIO_ERROR; + } + + /* DFSDM reset */ + __HAL_RCC_DFSDM_FORCE_RESET(); + __HAL_RCC_DFSDM_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) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable DFSDM clock */ + AUDIO_DFSDMx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE(); + + /* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN pins ------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN | AUDIO_DFSDMx_DMIC_DATIN_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = AUDIO_DFSDMx_CKOUT_DMIC_DATIN_AF; + HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct); +} + +/** + * @brief De-initializes the DFSDM channel MSP. + * @param hdfsdm_channel : DFSDM channel handle. + * @retval None + */ +void HAL_DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable GPIO clock */ + AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE(); + + /* DFSDM pins configuration: DFSDM_CKOUT */ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct); + HAL_GPIO_WritePin(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, AUDIO_DFSDMx_CKOUT_PIN, GPIO_PIN_RESET); + + + /* De-initialize DMIC_DATIN pin */ + HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, AUDIO_DFSDMx_DMIC_DATIN_PIN); +} + +/** + * @brief Initializes the DFSDM filter MSP. + * @param hdfsdm_filter : DFSDM filter handle. + * @retval None + */ +void HAL_DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) +{ + /* Enable DFSDM clock */ + AUDIO_DFSDMx_CLK_ENABLE(); + + /* Enable the DMA clock */ + AUDIO_DFSDMx_DMAx_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 = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hAudioIn.hDmaDfsdmLeft.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hAudioIn.hDmaDfsdmLeft.Init.Mode = DMA_CIRCULAR; + hAudioIn.hDmaDfsdmLeft.Init.Priority = DMA_PRIORITY_HIGH; + + hAudioIn.hDmaDfsdmLeft.Instance = AUDIO_DFSDMx_DMAx_LEFT_CHANNEL; + + /* 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(AUDIO_DFSDMx_DMAx_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_LEFT_IRQ); + } + + /** + * @brief De-initializes the DFSDM filter MSP. + * @param hdfsdm_filter : DFSDM filter handle. + * @retval None + */ +void HAL_DFSDM_FilterMspDeInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) +{ + /* Disable DMA Channel IRQ */ + HAL_NVIC_DisableIRQ(AUDIO_DFSDMx_DMAx_LEFT_IRQ); + + /* De-initialize the DMA Channel */ + HAL_DMA_DeInit(&hAudioIn.hDmaDfsdmLeft); + + /* Disable the DMA clock */ + AUDIO_DFSDMx_DMAx_CLK_DISABLE(); +} + +/** + * @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; + + /* Retreive 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 + PLLSAI1_VCO= 8 Mhz * PLLSAI1N = 8 * 24 = VCO_192M + SAI_CK_x = PLLSAI1_VCO/PLLSAI1P = 192/17 = 11.294 Mhz */ + RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; + RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1N = 24; + RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1P = 17; + RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK; + RCC_ExCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI1_VCO= 8 Mhz * PLLSAI1N = 8 * 43 = VCO_344M + SAI_CK_x = PLLSAI1_VCO/PLLSAI1P = 344/7 = 49.142 Mhz */ + RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; + RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1N = 43; + RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1P = 7; + RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK; + RCC_ExCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; + } + + if (HAL_RCCEx_PeriphCLKConfig(&RCC_ExCLKInitStruct) != HAL_OK) + { + return AUDIO_ERROR; + } + + return AUDIO_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + +