Files
admin dac37fd077
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s
Sync inav to Gitea
2026-08-03 16:37:40 +08:00

5040 lines
163 KiB
C

/**
******************************************************************************
* @file stm32h7b3i_eval_audio.c
* @author MCD Application Team
* @brief This file provides the Audio driver for the STM32H7B3I_EVAL
* board.
@verbatim
How To use this driver:
-----------------------
+ This driver supports stm32h7xx devices on STM32H7B3I_EVAL (MB1331) boards.
+ Call the function BSP_AUDIO_OUT_Init() for AUDIO OUT initialization:
Instance: Select the output instance. It can only be 0 (SAI) or 1 (I2S)
AudioInit: Audio Out structure to select the following parameters
- Device: Select the output device (headphone, speaker, hdmi ..)
- SampleRate: Select the output sample rate (8Khz .. 96Khz)
- BitsPerSample: Select the output resolution (16 or 32bits per sample)
- ChannelsNbr: Select the output channels number(1 for mono, 2 for stereo)
- Volume: Select the output volume(0% .. 100%)
This function configures all the hardware required for the audio application (codec, I2C, I2S ,SAI,
GPIOs, DMA and interrupt if needed). This function returns BSP_ERROR_NONE if configuration is OK.
If the returned value is different from BSP_ERROR_NONE or the function is stuck then the communication with
the codec or the MFX has failed (try to un-plug the power or reset device in this case).
User can update the I2S/SAI or the clock configurations by overriding the weak MX functions MX_I2S6_Init(),
MX_I2S6_ClockConfig(),MX_SAI1_Block_A_Init() and MX_SAI1_ClockConfig()
User can override the default MSP configuration and register his own MSP callbacks (defined at application level)
by calling BSP_AUDIO_OUT_RegisterMspCallbacks() function
User can restore the default MSP configuration by calling BSP_AUDIO_OUT_RegisterDefaultMspCallbacks()
To use these two functions, user have to enable USE_HAL_I2S_REGISTER_CALLBACKS and USE_HAL_SAI_REGISTER_CALLBACKS
within stm32h7xx_hal_conf.h file
+ Call the function BSP_AUDIO_OUT_Play() to play audio stream:
Instance: Select the output instance. It can only be 0 (SAI) or 1 (I2S)
pBuf: pointer to the audio data file address
NbrOfBytes: Total size of the buffer to be sent in Bytes
+ Call the function BSP_AUDIO_OUT_Pause() to pause playing
+ Call the function BSP_AUDIO_OUT_Resume() to resume playing.
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 playing.
+ Call the function BSP_AUDIO_OUT_Mute() to mute the player.
+ Call the function BSP_AUDIO_OUT_UnMute() to unmute the player.
+ Call the function BSP_AUDIO_OUT_IsMute() to get the mute state(BSP_AUDIO_MUTE_ENABLED or BSP_AUDIO_MUTE_DISABLED).
+ Call the function BSP_AUDIO_OUT_SetDevice() to update the AUDIO OUT device.
+ Call the function BSP_AUDIO_OUT_GetDevice() to get the AUDIO OUT device.
+ Call the function BSP_AUDIO_OUT_SetSampleRate() to update the AUDIO OUT sample rate.
+ Call the function BSP_AUDIO_OUT_GetSampleRate() to get the AUDIO OUT sample rate.
+ Call the function BSP_AUDIO_OUT_SetBitsPerSample() to update the AUDIO OUT resolution.
+ Call the function BSP_AUDIO_OUT_GetBitPerSample() to get the AUDIO OUT resolution.
+ Call the function BSP_AUDIO_OUT_SetChannelsNbr() to update the AUDIO OUT number of channels.
+ Call the function BSP_AUDIO_OUT_GetChannelsNbr() to get the AUDIO OUT number of channels.
+ Call the function BSP_AUDIO_OUT_SetVolume() to update the AUDIO OUT volume.
+ Call the function BSP_AUDIO_OUT_GetVolume() to get the AUDIO OUT volume.
+ Call the function BSP_AUDIO_OUT_GetState() to get the AUDIO OUT state.
+ BSP_AUDIO_OUT_SetDevice(), BSP_AUDIO_OUT_SetSampleRate(), BSP_AUDIO_OUT_SetBitsPerSample() and
BSP_AUDIO_OUT_SetChannelsNbr() cannot be called while the state is AUDIO_OUT_STATE_PLAYING.
+ For each mode, you may need to implement the relative callback functions into your code.
The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in
the STM32H7B3I_EVAL_audio.h file. (refer to the example for more details on the callbacks implementations)
+ Call the function BSP_AUDIO_IN_Init() for AUDIO IN initialization:
Instance : Select the input instance. Can be 0 (SAI), 1 (I2S) or 2 (DFSDM)
AudioInit: Audio In structure to select the following parameters
- Device: Select the input device (analog, digital micx)
- SampleRate: Select the input sample rate (8Khz .. 96Khz)
- BitsPerSample: Select the input resolution (16 or 32bits per sample)
- ChannelsNbr: Select the input channels number(1 for mono, 2 for stereo)
- Volume: Select the input volume(0% .. 100%)
This function configures all the hardware required for the audio application (codec, I2C, SAI, I2S, DFSDM
GPIOs, DMA and interrupt if needed). This function returns BSP_ERROR_NONE if configuration is OK.
If the returned value is different from BSP_ERROR_NONE or the function is stuck then the communication with
the codec or the MFX has failed (try to un-plug the power or reset device in this case).
User can update the DFSDM/SAI or the clock configurations by overriding the weak MX functions MX_SAIx_Init(),
MX_SAIx_ClockConfig(), MX_DFSDMx_Init() and MX_DFSDMx_ClockConfig()
User can override the default MSP configuration and register his own MSP callbacks (defined at application level)
by calling BSP_AUDIO_IN_RegisterMspCallbacks() function
User can restore the default MSP configuration by calling BSP_AUDIO_IN_RegisterDefaultMspCallbacks()
To use these two functions, user have to enable USE_HAL_SAI_REGISTER_CALLBACKS and/or USE_HAL_DFSDM_REGISTER_CALLBACKS
within stm32h7xx_hal_conf.h file
+ Call the function BSP_AUDIO_IN_Record() to record audio stream. The recorded data are stored to user buffer in raw
(L, R, L, R ...)
Instance : Select the input instance. Can be 0 (SAI), 1 (I2S) or 2 (DFSDM)
pBuf: pointer to user buffer
NbrOfBytes: Total size of the buffer to be sent in Bytes
+ Call the function BSP_AUDIO_IN_Pause() to pause recording
+ Call the function BSP_AUDIO_IN_Resume() to resume recording.
+ Call the function BSP_AUDIO_IN_Stop() to stop recording.
+ Call the function BSP_AUDIO_IN_SetDevice() to update the AUDIO IN device.
+ Call the function BSP_AUDIO_IN_GetDevice() to get the AUDIO IN device.
+ Call the function BSP_AUDIO_IN_SetSampleRate() to update the AUDIO IN sample rate.
+ Call the function BSP_AUDIO_IN_GetSampleRate() to get the AUDIO IN sample rate.
+ Call the function BSP_AUDIO_IN_SetBitPerSample() to update the AUDIO IN resolution.
+ Call the function BSP_AUDIO_IN_GetBitPerSample() to get the AUDIO IN resolution.
+ Call the function BSP_AUDIO_IN_SetChannelsNbr() to update the AUDIO IN number of channels.
+ Call the function BSP_AUDIO_IN_GetChannelsNbr() to get the AUDIO IN number of channels.
+ Call the function BSP_AUDIO_IN_SetVolume() to update the AUDIO IN volume.
+ Call the function BSP_AUDIO_IN_GetVolume() to get the AUDIO IN volume.
+ Call the function BSP_AUDIO_IN_GetState() to get the AUDIO IN state.
+ Call the function BSP_AUDIO_IN_RecordChannels() to record audio stream. The recorded data are stored to user buffers separately
(L, L, ...) (R, R ...). User has to process his data at application level.
Instance : Select the input instance. Can be 2 (DFSDM)
pBuf: pointer to user buffers table
NbrOfBytes: Total size of the buffer to be sent in Bytes
+ Call the function BSP_AUDIO_IN_PauseChannels() to pause recording:
Instance : Select the input instance. Can be 2 (DFSDM)
Device: Select the input device (digital micX)
+ Call the function BSP_AUDIO_IN_ResumeChannels() to resume recording.
Instance : Select the input instance. Can be 2 (DFSDM)
Device: Select the input device (digital micX)
+ Call the function BSP_AUDIO_IN_StopChannels() to stop recording.
Instance : Select the input instance. Can be 2 (DFSDM)
Device: Select the input device (digital micX)
+ For each mode, you may need to implement the relative callback functions into your code.
The Callback functions are named AUDIO_IN_XXX_CallBack() and only their prototypes are declared in
the stm32h7b3i_eval_audio.h file. (refer to the example for more details on the callbacks implementations)
+ The driver API and the callback functions are at the end of the stm32h7b3i_eval_audio.h file.
@endverbatim
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32h7b3i_eval_audio.h"
#include "stm32h7b3i_eval_bus.h"
/** @addtogroup BSP
* @{
*/
/** @addtogroup STM32H7B3I_EVAL
* @{
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO AUDIO
* @brief This file includes the low layer driver for cs42l51 Audio Codec
* available on STM32H7B3I_EVAL board(MB1331).
* @{
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_Private_Defines STM32H7B3I_EVAL_AUDIO Private Defines
* @{
*/
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_Private_Macros AUDIO Private Macros
* @{
*/
/*### RECORD ###*/
#define DFSDM_OVER_SAMPLING(__FREQUENCY__) \
((__FREQUENCY__) == (AUDIO_FREQUENCY_8K)) ? (256U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_11K)) ? (256U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_16K)) ? (128U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_22K)) ? (128U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_32K)) ? (64U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_44K)) ? (64U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_48K)) ? (32U) : (16U)
#define DFSDM_CLOCK_DIVIDER(__FREQUENCY__) \
((__FREQUENCY__) == (AUDIO_FREQUENCY_8K)) ? (24U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_11K)) ? (4U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_16K)) ? (24U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_22K)) ? (4U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_32K)) ? (24U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_44K)) ? (4U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_48K)) ? (32U) : (32U)
#define DFSDM_FILTER_ORDER(__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 DFSDM_MIC_BIT_SHIFT(__FREQUENCY__) \
((__FREQUENCY__) == (AUDIO_FREQUENCY_8K)) ? (5U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_11K)) ? (6U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_16K)) ? (3U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_22K)) ? (3U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_32K)) ? (6U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_44K)) ? (0U) \
: ((__FREQUENCY__) == (AUDIO_FREQUENCY_48K)) ? (2U) : (2U)
/* Saturate the record PCM sample */
#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_Exported_Variables AUDIO Exported Variables
* @{
*/
/* Audio in and out component object */
void *Audio_CompObj = NULL;
/* Play */
SAI_HandleTypeDef haudio_out_sai = {0};
I2S_HandleTypeDef haudio_out_i2s = {0};
AUDIO_OUT_Ctx_t Audio_Out_Ctx[AUDIO_OUT_INSTANCES_NBR];
/* Record */
DFSDM_Filter_HandleTypeDef haudio_in_dfsdm_filter[DFSDM_MIC_NUMBER];
DFSDM_Channel_HandleTypeDef haudio_in_dfsdm_channel[DFSDM_MIC_NUMBER];
SAI_HandleTypeDef haudio_in_sai = {0};
I2S_HandleTypeDef haudio_in_i2s = {0};
AUDIO_IN_Ctx_t Audio_In_Ctx[AUDIO_IN_INSTANCES_NBR];
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_Private_Variables AUDIO Private Variables
* @{
*/
/* Audio in and out driver */
static AUDIO_Drv_t *Audio_Drv = NULL;
/* Recording DFSDM DMA handles */
static DMA_HandleTypeDef hDmaDfsdm[DFSDM_MIC_NUMBER];
/* Recording Buffer Trigger */
static __IO uint32_t RecBuffTrigger = 0;
static __IO uint32_t RecBuffHalf = 0;
ALIGN_32BYTES(static int32_t MicRecBuff[2][DEFAULT_AUDIO_IN_BUFFER_SIZE]);
static __IO uint32_t MicBuffIndex[DFSDM_MIC_NUMBER];
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_Private_Function_Prototypes AUDIO Private Function Prototypes
* @{
*/
/* SAI Msp config */
static void SAI_MspInit(SAI_HandleTypeDef *hsai);
static void SAI_MspDeInit(SAI_HandleTypeDef *hsai);
/* SAI callbacks */
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
static void SAI_TxCpltCallback(SAI_HandleTypeDef *hsai);
static void SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai);
static void SAI_RxCpltCallback(SAI_HandleTypeDef *hsai);
static void SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai);
static void SAI_ErrorCallback(SAI_HandleTypeDef *hsai);
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
/* I2S Msp config */
static void I2S_MspInit(I2S_HandleTypeDef *hi2s);
static void I2S_MspDeInit(I2S_HandleTypeDef *hi2s);
/* I2S callbacks */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
static void I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s);
static void I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s);
static void I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s);
static void I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s);
static void I2S_ErrorCallback(I2S_HandleTypeDef *hi2s);
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
/* DFSDM Channel Msp config */
static void DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hDfsdmChannel);
static void DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hDfsdmChannel);
/* DFSDM Filter Msp config */
static void DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hDfsdmFilter);
static void DFSDM_FilterMspDeInit(DFSDM_Filter_HandleTypeDef *hDfsdmFilter);
/* DFSDM Filter conversion callbacks */
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1)
static void DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter);
static void DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter);
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) */
#if (USE_AUDIO_CODEC_CS42L51 == 1)
static int32_t CS42L51_Probe(void);
static int32_t CS42L51_PowerUp(void);
static int32_t CS42L51_PowerDown(void);
#endif
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_OUT_Exported_Functions AUDIO OUT Exported Functions
* @{
*/
/**
* @brief Configures the audio peripherals.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param AudioInit AUDIO OUT init Structure
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_Init(uint32_t Instance, BSP_AUDIO_Init_t *AudioInit)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Fill Audio_Out_Ctx structure */
Audio_Out_Ctx[Instance].Device = AudioInit->Device;
Audio_Out_Ctx[Instance].Instance = Instance;
Audio_Out_Ctx[Instance].SampleRate = AudioInit->SampleRate;
Audio_Out_Ctx[Instance].BitsPerSample = AudioInit->BitsPerSample;
Audio_Out_Ctx[Instance].ChannelsNbr = AudioInit->ChannelsNbr;
Audio_Out_Ctx[Instance].Volume = AudioInit->Volume;
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_RESET;
#if (USE_AUDIO_CODEC_CS42L51 == 1)
if ((Audio_In_Ctx[0].State == AUDIO_IN_STATE_RESET) && (Audio_In_Ctx[1].State == AUDIO_IN_STATE_RESET))
{
if (CS42L51_PowerUp() != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
if (CS42L51_Probe() != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
}
#endif
if (ret == BSP_ERROR_NONE)
{
if (Instance == 0U)
{
/* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
if (MX_SAI1_ClockConfig(&haudio_out_sai, AudioInit->SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
else
{
/* SAI data transfer preparation:
Prepare the Media to be used for the audio transfer from memory to SAI peripheral */
haudio_out_sai.Instance = AUDIO_OUT_SAIx;
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register the MSP Callbacks */
if (Audio_Out_Ctx[Instance].IsMspCallbacksValid == 0U)
{
if (BSP_AUDIO_OUT_RegisterDefaultMspCallbacks(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#else
SAI_MspInit(&haudio_out_sai);
#endif
}
}
else
{
/* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
if (MX_I2S6_ClockConfig(&haudio_out_i2s, AudioInit->SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
else
{
/* I2S data transfer preparation:
Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
haudio_out_i2s.Instance = AUDIO_OUT_I2Sx;
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/* Register the MSP Callbacks */
if (Audio_Out_Ctx[Instance].IsMspCallbacksValid == 0U)
{
if (BSP_AUDIO_OUT_RegisterDefaultMspCallbacks(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#else
I2S_MspInit(&haudio_out_i2s);
#endif
}
}
if (ret == BSP_ERROR_NONE)
{
if (Instance == 0U)
{
MX_SAI_Config mx_sai_config;
/* Prepare haudio_out_sai handle */
mx_sai_config.AudioFrequency = AudioInit->SampleRate;
mx_sai_config.AudioMode = SAI_MODEMASTER_TX;
mx_sai_config.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
mx_sai_config.MonoStereoMode = (AudioInit->ChannelsNbr == 1U) ? SAI_MONOMODE : SAI_STEREOMODE;
if (AudioInit->BitsPerSample == AUDIO_RESOLUTION_24B)
{
mx_sai_config.DataSize = SAI_DATASIZE_24;
mx_sai_config.FrameLength = 64;
mx_sai_config.ActiveFrameLength = 32;
}
else
{
mx_sai_config.DataSize = SAI_DATASIZE_16;
mx_sai_config.FrameLength = 32;
mx_sai_config.ActiveFrameLength = 16;
}
mx_sai_config.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
mx_sai_config.Synchro = SAI_ASYNCHRONOUS;
mx_sai_config.SynchroExt = SAI_SYNCEXT_DISABLE;
mx_sai_config.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
/* SAI peripheral initialization: this __weak function can be redefined by the application */
if (MX_SAI1_Block_A_Init(&haudio_out_sai, &mx_sai_config) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register SAI TC, HT and Error callbacks */
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_COMPLETE_CB_ID, SAI_TxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_HALFCOMPLETE_CB_ID, SAI_TxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_ERROR_CB_ID, SAI_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif
}
else
{
MX_I2S_Config mx_i2s_config;
mx_i2s_config.AudioMode = I2S_MODE_MASTER_TX;
mx_i2s_config.SampleRate = AudioInit->SampleRate;
/* I2S peripheral initialization: this __weak function can be redefined by the application */
if (MX_I2S6_Init(&haudio_out_i2s, &mx_i2s_config) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
else if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_TX_COMPLETE_CB_ID, I2S_TxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_TX_HALF_COMPLETE_CB_ID, I2S_TxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_ERROR_CB_ID, I2S_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif
}
if (ret == BSP_ERROR_NONE)
{
#if (USE_AUDIO_CODEC_CS42L51 == 1)
CS42L51_Init_t codec_init;
/* Fill codec_init structure */
codec_init.InputDevice = ((Audio_In_Ctx[0].State == AUDIO_IN_STATE_RESET) && (Audio_In_Ctx[1].State == AUDIO_IN_STATE_RESET)) ? \
CS42L51_IN_NONE : ((Audio_In_Ctx[0].Device == AUDIO_IN_DEVICE_ANALOG_LINE1) || \
(Audio_In_Ctx[1].Device == AUDIO_IN_DEVICE_ANALOG_LINE1)) ? CS42L51_IN_LINE1 : CS42L51_IN_MIC1;
codec_init.OutputDevice = CS42L51_OUT_HEADPHONE;
codec_init.Frequency = AudioInit->SampleRate;
codec_init.Resolution = CS42L51_RESOLUTION_16b; /* Not used */
codec_init.Volume = AudioInit->Volume;
if (Instance == 0U)
{
/* Initialize the codec internal registers */
if (Audio_Drv->Init(Audio_CompObj, &codec_init) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
else
{
/* Receive fake I2S data in order to generate MCLK needed by CS42L51 to set its registers */
if (HAL_I2S_Transmit_DMA(&haudio_out_i2s, ((uint16_t *)0x38000000), 16) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
/* Initialize the codec internal registers */
if (Audio_Drv->Init(Audio_CompObj, &codec_init) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Stop receiving fake I2S data */
if (HAL_I2S_DMAStop(&haudio_out_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
}
#endif
/* Update BSP AUDIO OUT state */
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_STOP;
}
}
}
}
return ret;
}
/**
* @brief De-initializes the audio out peripheral.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval None
*/
int32_t BSP_AUDIO_OUT_DeInit(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
else
{
/* Reset audio codec if not currently used by audio in instances */
if ((Audio_In_Ctx[0].State == AUDIO_IN_STATE_RESET) || (Audio_In_Ctx[1].State == AUDIO_IN_STATE_RESET))
{
if (CS42L51_PowerDown() != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
if (Instance == 0U)
{
if (HAL_SAI_DeInit(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 0)
SAI_MspDeInit(&haudio_out_sai);
#endif
}
else
{
if (HAL_I2S_DeInit(&haudio_out_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 0)
I2S_MspDeInit(&haudio_out_i2s);
#endif
}
if (ret == BSP_ERROR_NONE)
{
/* Call the Media layer stop function */
if (Audio_Drv->DeInit(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Update BSP AUDIO OUT state */
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_RESET;
}
}
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Initializes the Audio Codec audio out instance (SAI).
* @param hsai SAI handle
* @param MXConfig SAI confiruration structure
* @note Being __weak it can be overwritten by the application
* @retval HAL status
*/
__weak HAL_StatusTypeDef MX_SAI1_Block_A_Init(SAI_HandleTypeDef *hsai, MX_SAI_Config *MXConfig)
{
HAL_StatusTypeDef ret = HAL_OK;
/* Disable SAI peripheral to allow access to SAI internal registers */
__HAL_SAI_DISABLE(hsai);
/* Configure SAI1_Block_A */
hsai->Init.MonoStereoMode = MXConfig->MonoStereoMode;
hsai->Init.AudioFrequency = MXConfig->AudioFrequency;
hsai->Init.AudioMode = MXConfig->AudioMode;
hsai->Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hsai->Init.Protocol = SAI_FREE_PROTOCOL;
hsai->Init.DataSize = MXConfig->DataSize;
hsai->Init.FirstBit = SAI_FIRSTBIT_MSB;
hsai->Init.ClockStrobing = MXConfig->ClockStrobing;
hsai->Init.Synchro = MXConfig->Synchro;
hsai->Init.OutputDrive = MXConfig->OutputDrive;
hsai->Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
hsai->Init.SynchroExt = MXConfig->SynchroExt;
hsai->Init.CompandingMode = SAI_NOCOMPANDING;
hsai->Init.TriState = SAI_OUTPUT_NOTRELEASED;
hsai->Init.Mckdiv = 0;
hsai->Init.MckOutput = SAI_MCK_OUTPUT_ENABLE;
hsai->Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE;
hsai->Init.PdmInit.Activation = DISABLE;
/* Configure SAI_Block_x Frame */
hsai->FrameInit.FrameLength = MXConfig->FrameLength;
hsai->FrameInit.ActiveFrameLength = MXConfig->ActiveFrameLength;
hsai->FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
hsai->FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
hsai->FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
/* Configure SAI Block_x Slot */
hsai->SlotInit.FirstBitOffset = 0;
if ((MXConfig->DataSize == AUDIO_RESOLUTION_24B) || (MXConfig->DataSize == AUDIO_RESOLUTION_32B))
{
hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
}
else
{
hsai->SlotInit.SlotSize = SAI_SLOTSIZE_16B;
}
hsai->SlotInit.SlotNumber = 2;
hsai->SlotInit.SlotActive = MXConfig->SlotActive;
if (HAL_SAI_Init(hsai) != HAL_OK)
{
ret = HAL_ERROR;
}
return ret;
}
/**
* @brief Initializes the Audio audio out peripheral (I2S).
* @param hi2s I2S handle
* @param MXConfig I2S confiruration structure
* @note Being __weak it can be overwritten by the application
* @retval HAL status
*/
__weak HAL_StatusTypeDef MX_I2S6_Init(I2S_HandleTypeDef *hi2s, MX_I2S_Config *MXConfig)
{
HAL_StatusTypeDef ret = HAL_OK;
/* Disable I2S peripheral to allow access to I2S internal registers */
__HAL_I2S_DISABLE(hi2s);
/* I2S peripheral configuration */
hi2s->Init.Mode = MXConfig->AudioMode;
hi2s->Init.Standard = I2S_STANDARD_PHILIPS;
hi2s->Init.DataFormat = I2S_DATAFORMAT_16B;
hi2s->Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
hi2s->Init.AudioFreq = MXConfig->SampleRate;
hi2s->Init.CPOL = I2S_CPOL_LOW;
hi2s->Init.FirstBit = I2S_FIRSTBIT_MSB;
hi2s->Init.WSInversion = I2S_WS_INVERSION_DISABLE;
hi2s->Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_RIGHT;
hi2s->Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE;
if (HAL_I2S_Init(hi2s) != HAL_OK)
{
ret = HAL_ERROR;
}
/* Enable SAI peripheral */
__HAL_I2S_ENABLE(hi2s);
return ret;
}
/**
* @brief SAI clock Config.
* @param hsai SAI handle
* @param SampleRate Audio frequency used to play the audio stream.
* @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency()
* Being __weak it can be overwritten by the application
* @retval HAL status
*/
__weak HAL_StatusTypeDef MX_SAI1_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t SampleRate)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
/* Set the PLL configuration according to the audio frequency */
if ((SampleRate == AUDIO_FREQUENCY_11K) || (SampleRate == AUDIO_FREQUENCY_22K) || (SampleRate == AUDIO_FREQUENCY_44K))
{
rcc_ex_clk_init_struct.PLL2.PLL2P = 24;
rcc_ex_clk_init_struct.PLL2.PLL2Q = 24;
rcc_ex_clk_init_struct.PLL2.PLL2N = 271;
}
else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
{
rcc_ex_clk_init_struct.PLL2.PLL2P = 7;
rcc_ex_clk_init_struct.PLL2.PLL2Q = 7;
rcc_ex_clk_init_struct.PLL2.PLL2N = 344;
}
rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2;
rcc_ex_clk_init_struct.PLL2.PLL2R = 1;
rcc_ex_clk_init_struct.PLL2.PLL2M = 24;
rcc_ex_clk_init_struct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_0;
rcc_ex_clk_init_struct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;
rcc_ex_clk_init_struct.PLL2.PLL2FRACN = 0;
return HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
}
/**
* @brief I2S clock Config.
* @param hi2s I2S handle
* @param SampleRate Audio frequency used to play the audio stream.
* @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency()
* Being __weak it can be overwritten by the application
* @retval HAL status
*/
__weak HAL_StatusTypeDef MX_I2S6_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t SampleRate)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
/* PLLI2S_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
/* Set the PLL configuration according to the audio frequency */
if ((SampleRate == AUDIO_FREQUENCY_11K) || (SampleRate == AUDIO_FREQUENCY_22K) || (SampleRate == AUDIO_FREQUENCY_44K))
{
rcc_ex_clk_init_struct.PLL2.PLL2P = 24; /* PLLP for DFSDM clock if used in same time with I2S */
rcc_ex_clk_init_struct.PLL2.PLL2Q = 24; /* PLLQ for I2S clock */
rcc_ex_clk_init_struct.PLL2.PLL2N = 271;
}
else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
{
rcc_ex_clk_init_struct.PLL2.PLL2P = 7; /* PLLP for DFSDM clock if used in same time with I2S */
rcc_ex_clk_init_struct.PLL2.PLL2Q = 7; /* PLLQ for I2S clock */
rcc_ex_clk_init_struct.PLL2.PLL2N = 344;
}
rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SPI6 | RCC_PERIPHCLK_SAI1;
rcc_ex_clk_init_struct.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PLL2;
rcc_ex_clk_init_struct.PLL2.PLL2R = 1;
rcc_ex_clk_init_struct.PLL2.PLL2M = 24;
rcc_ex_clk_init_struct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_0;
rcc_ex_clk_init_struct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;
rcc_ex_clk_init_struct.PLL2.PLL2FRACN = 0;
return HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
}
/**
* @brief Default BSP AUDIO OUT Msp Callbacks
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval BSP status
*/
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1) || (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
int32_t BSP_AUDIO_OUT_RegisterDefaultMspCallbacks(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
if (Instance == 0U)
{
__HAL_SAI_RESET_HANDLE_STATE(&haudio_out_sai);
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_MSPINIT_CB_ID, SAI_MspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_MSPDEINIT_CB_ID, SAI_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
Audio_Out_Ctx[Instance].IsMspCallbacksValid = 1;
}
#endif
}
else
{
__HAL_I2S_RESET_HANDLE_STATE(&haudio_out_i2s);
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_MSPINIT_CB_ID, I2S_MspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_MSPDEINIT_CB_ID, I2S_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
Audio_Out_Ctx[Instance].IsMspCallbacksValid = 1;
}
#endif
}
}
/* Return BSP status */
return ret;
}
/**
* @brief BSP AUDIO OUT Msp Callback registering
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param CallBacks pointer to MspInit/MspDeInit callbacks functions
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_RegisterMspCallbacks(uint32_t Instance, BSP_AUDIO_OUT_Cb_t *CallBacks)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
if (Instance == 0U)
{
__HAL_SAI_RESET_HANDLE_STATE(&haudio_out_sai);
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_MSPINIT_CB_ID, CallBacks->pMspSaiInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_MSPDEINIT_CB_ID, CallBacks->pMspSaiDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
Audio_Out_Ctx[Instance].IsMspCallbacksValid = 1;
}
#endif
}
else
{
__HAL_I2S_RESET_HANDLE_STATE(&haudio_out_i2s);
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_MSPINIT_CB_ID, CallBacks->pMspI2sInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_MSPDEINIT_CB_ID, CallBacks->pMspI2sDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
Audio_Out_Ctx[Instance].IsMspCallbacksValid = 1;
}
#endif
}
}
/* Return BSP status */
return ret;
}
#endif /*(USE_HAL_SAI_REGISTER_CALLBACKS == 1) || (USE_HAL_I2S_REGISTER_CALLBACKS == 1)*/
/**
* @brief Starts playing audio stream from a data buffer for a determined size.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param pData pointer on data address
* @param NbrOfBytes Size of total samples in bytes
* BitsPerSample: 16 or 32
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_Play(uint32_t Instance, uint8_t *pData, uint32_t NbrOfBytes)
{
int32_t ret = BSP_ERROR_NONE;
if ((Instance >= AUDIO_OUT_INSTANCES_NBR) || (((NbrOfBytes / (Audio_Out_Ctx[Instance].BitsPerSample / 8U)) > 0xFFFFU)))
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_STOP)
{
ret = BSP_ERROR_BUSY;
}
else
{
if (Instance == 0U)
{
if (HAL_SAI_Transmit_DMA(&haudio_out_sai, pData,
(uint16_t)(NbrOfBytes / (Audio_Out_Ctx[Instance].BitsPerSample / 8U))) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (HAL_I2S_Transmit_DMA(&haudio_out_i2s, (uint16_t *)pData,
(uint16_t)(NbrOfBytes / (Audio_Out_Ctx[Instance].BitsPerSample / 8U))) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
if (Audio_Drv->Play(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Update BSP AUDIO OUT state */
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_PLAYING;
}
}
}
/* Return BSP status */
return ret;
}
/**
* @brief This function Pauses the audio file stream. In case
* of using DMA, the DMA Pause feature is used.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @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 status
*/
int32_t BSP_AUDIO_OUT_Pause(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_PLAYING)
{
ret = BSP_ERROR_BUSY;
}
/* Call the audio codec pause function */
else if (Audio_Drv->Pause(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Pause DMA transfer of audio samples towards the serial audio interface */
if (Instance == 0U)
{
if (HAL_SAI_DMAPause(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (HAL_I2S_DMAPause(&haudio_out_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
/* Workaround */
haudio_out_i2s.Instance->IFCR = 0x800;
}
}
}
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO OUT state */
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_PAUSE;
}
/* Return BSP status */
return ret;
}
/**
* @brief Resumes the audio file stream.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @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 status
*/
int32_t BSP_AUDIO_OUT_Resume(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_PAUSE)
{
ret = BSP_ERROR_BUSY;
}
/* Call the audio codec resume function */
else if (Audio_Drv->Resume(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Resume DMA transfer of audio samples towards the serial audio interface */
if (Instance == 0U)
{
if (HAL_SAI_DMAResume(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (HAL_I2S_DMAResume(&haudio_out_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO OUT state */
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_PLAYING;
}
/* Return BSP status */
return ret;
}
/**
* @brief Stops audio playing and Power down the Audio Codec.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_Stop(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_STOP)
{
/* Nothing to do */
}
else if ((Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_PLAYING) &&
(Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_PAUSE))
{
ret = BSP_ERROR_BUSY;
}
/* Call the Media layer stop function */
else if (Audio_Drv->Stop(Audio_CompObj, CODEC_PDWN_SW) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
if (Instance == 0U)
{
if (HAL_SAI_DMAStop(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (HAL_I2S_DMAStop(&haudio_out_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO OUT state */
Audio_Out_Ctx[Instance].State = AUDIO_OUT_STATE_STOP;
}
/* Return BSP status */
return ret;
}
/**
* @brief Controls the current audio volume level.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param Volume Volume level to be set in percentage from 0% to 100% (0 for
* Mute and 100 for Max volume level).
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_SetVolume(uint32_t Instance, uint32_t Volume)
{
int32_t ret = BSP_ERROR_NONE;
if ((Instance >= AUDIO_OUT_INSTANCES_NBR) || (Volume > 100U))
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Call the codec volume control function with converted volume value */
if (Audio_Drv->SetVolume(Audio_CompObj, AUDIO_VOLUME_OUTPUT, Volume) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else if (Volume == 0U)
{
/* Update Mute State */
Audio_Out_Ctx[Instance].IsMute = BSP_AUDIO_MUTE_ENABLED;
}
else
{
/* Update Mute State */
Audio_Out_Ctx[Instance].IsMute = BSP_AUDIO_MUTE_DISABLED;
}
Audio_Out_Ctx[Instance].Volume = Volume;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get the current audio volume level.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param Volume pointer to volume to be returned
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_GetVolume(uint32_t Instance, uint32_t *Volume)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
else
{
*Volume = Audio_Out_Ctx[Instance].Volume;
}
/* Return BSP status */
return ret;
}
/**
* @brief Enables the MUTE
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_Mute(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
/* Check audio out mute status */
else if (Audio_Out_Ctx[Instance].IsMute == 1U)
{
/* Nothing to do */
}
/* Call the audio codec mute function */
else if (Audio_Drv->SetMute(Audio_CompObj, CODEC_MUTE_ON) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Update audio out mute status */
Audio_Out_Ctx[Instance].IsMute = 1U;
}
/* Return BSP status */
return ret;
}
/**
* @brief Disables the MUTE mode
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_UnMute(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
/* Check audio out mute status */
else if (Audio_Out_Ctx[Instance].IsMute == 0U)
{
/* Nothing to do */
}
/* Call the audio codec mute function */
else if (Audio_Drv->SetMute(Audio_CompObj, CODEC_MUTE_OFF) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Update audio out mute status */
Audio_Out_Ctx[Instance].IsMute = 0U;
}
/* Return BSP status */
return ret;
}
/**
* @brief Check whether the MUTE mode is enabled or not
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param IsMute pointer to mute state
* @retval Mute status
*/
int32_t BSP_AUDIO_OUT_IsMute(uint32_t Instance, uint32_t *IsMute)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
else
{
*IsMute = Audio_Out_Ctx[Instance].IsMute;
}
/* Return BSP status */
return ret;
}
/**
* @brief Switch dynamically (while audio file is played) the output target
* (speaker or headphone).
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param Device The audio output device
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_SetDevice(uint32_t Instance, uint32_t Device)
{
int32_t ret = BSP_ERROR_NONE;
UNUSED(Device);
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_STOP)
{
ret = BSP_ERROR_BUSY;
}
else
{
/* Nothing to do because there is only one device (AUDIO_OUT_DEVICE_HEADPHONE) */
}
/* Return BSP status */
return ret;
}
/**
* @brief Get the Output Device
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param Device The audio output device
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_GetDevice(uint32_t Instance, uint32_t *Device)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
else
{
/* Get Audio_Out_Ctx Device */
*Device = Audio_Out_Ctx[Instance].Device;
}
/* Return BSP status */
return ret;
}
/**
* @brief Updates the audio frequency.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param SampleRate Audio frequency used to play the audio stream.
* @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
* audio frequency.
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_SetSampleRate(uint32_t Instance, uint32_t SampleRate)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_STOP)
{
ret = BSP_ERROR_BUSY;
}
/* Check if record on instance 0 is on going and corresponding sample rate */
else if ((Audio_In_Ctx[0].State != AUDIO_IN_STATE_RESET) &&
(Audio_In_Ctx[0].SampleRate != SampleRate))
{
ret = BSP_ERROR_FEATURE_NOT_SUPPORTED;
}/* Check if sample rate is modified */
else if (Audio_Out_Ctx[Instance].SampleRate == SampleRate)
{
/* Nothing to do */
}
else
{
if (Instance == 0U)
{
/* Update the SAI audio frequency configuration */
haudio_out_sai.Init.AudioFrequency = SampleRate;
/* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
if (MX_SAI1_ClockConfig(&haudio_out_sai, SampleRate) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_Init(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register SAI TC, HT and Error callbacks */
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_COMPLETE_CB_ID, SAI_TxCpltCallback) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_HALFCOMPLETE_CB_ID, SAI_TxHalfCpltCallback) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_ERROR_CB_ID, SAI_ErrorCallback) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
/* Store new sample rate */
Audio_Out_Ctx[Instance].SampleRate = SampleRate;
}
}
else
{
haudio_out_i2s.Init.AudioFreq = SampleRate;
/* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
if (MX_I2S6_ClockConfig(&haudio_out_i2s, SampleRate) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_Init(&haudio_out_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
/* Enable I2S peripheral to generate MCLK */
__HAL_I2S_ENABLE(&haudio_out_i2s);
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/* Register I2S TC, HT and Error callbacks */
if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_TX_COMPLETE_CB_ID, I2S_TxCpltCallback) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_TX_HALF_COMPLETE_CB_ID, I2S_TxHalfCpltCallback) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
if (HAL_I2S_RegisterCallback(&haudio_out_i2s, HAL_I2S_ERROR_CB_ID, I2S_ErrorCallback) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
/* Store new sample rate */
Audio_Out_Ctx[Instance].SampleRate = SampleRate;
}
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Get the audio frequency.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param SampleRate Audio frequency used to play the audio stream.
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_GetSampleRate(uint32_t Instance, uint32_t *SampleRate)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
else
{
*SampleRate = Audio_Out_Ctx[Instance].SampleRate;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get the audio Resolution.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param BitsPerSample Audio Resolution used to play the audio stream.
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_SetBitsPerSample(uint32_t Instance, uint32_t BitsPerSample)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if ((Instance == 0U) && ((BitsPerSample == AUDIO_RESOLUTION_32B) || (BitsPerSample == AUDIO_RESOLUTION_8B)))
{
ret = BSP_ERROR_FEATURE_NOT_SUPPORTED;
}
else if ((Instance == 0U) && (Audio_In_Ctx[0].State != AUDIO_IN_STATE_RESET) &&
(Audio_In_Ctx[0].BitsPerSample != BitsPerSample))
{
ret = BSP_ERROR_FEATURE_NOT_SUPPORTED;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_STOP)
{
ret = BSP_ERROR_BUSY;
}
else if (Instance == 0U)
{
/* Store new bits per sample on audio out context */
Audio_Out_Ctx[Instance].BitsPerSample = BitsPerSample;
/* Update data size, frame length and active frame length parameters of SAI handle */
if (BitsPerSample == AUDIO_RESOLUTION_24B)
{
haudio_out_sai.Init.DataSize = SAI_DATASIZE_24;
haudio_out_sai.FrameInit.FrameLength = 64;
haudio_out_sai.FrameInit.ActiveFrameLength = 32;
}
else
{
haudio_out_sai.Init.DataSize = SAI_DATASIZE_16;
haudio_out_sai.FrameInit.FrameLength = 32;
haudio_out_sai.FrameInit.ActiveFrameLength = 16;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Update SAI state only to keep current MSP functions */
haudio_out_sai.State = HAL_SAI_STATE_RESET;
#else
SAI_MspInit(&haudio_out_sai);
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
/* Re-initialize SAI1 with new parameters */
if (HAL_SAI_Init(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register SAI TC, HT and Error callbacks */
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_COMPLETE_CB_ID, SAI_TxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_HALFCOMPLETE_CB_ID, SAI_TxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_ERROR_CB_ID, SAI_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
}
else
{
/* Only 16Bits is supported for I2S */
}
return ret;
}
/**
* @brief Get the audio Resolution.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param BitsPerSample Audio Resolution used to play the audio stream.
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_GetBitsPerSample(uint32_t Instance, uint32_t *BitsPerSample)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
/* Get the current bits per sample of audio out stream */
else
{
*BitsPerSample = Audio_Out_Ctx[Instance].BitsPerSample;
}
return ret;
}
/**
* @brief Set the audio Channels number.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param ChannelNbr Audio Channels number used to play the audio stream (It can only be 2U for I2S Instance)
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_SetChannelsNbr(uint32_t Instance, uint32_t ChannelNbr)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio out state */
else if (Audio_Out_Ctx[Instance].State != AUDIO_OUT_STATE_STOP)
{
ret = BSP_ERROR_BUSY;
}
else
{
/* In I2S, only stereo mode is supported:
A full frame has to be considered as a Left channel data transmission followed by a Right
channel data transmission. It is not possible to have a partial frame where only the left
channel is sent.
*/
if (Instance == 0U)
{
/* Update mono or stereo mode of SAI handle */
haudio_out_sai.Init.MonoStereoMode = (ChannelNbr == 1U) ? SAI_MONOMODE : SAI_STEREOMODE;
/* Re-initialize SAI1 with new parameter */
if (HAL_SAI_Init(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register SAI TC, HT and Error callbacks */
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_COMPLETE_CB_ID, SAI_TxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_TX_HALFCOMPLETE_CB_ID, SAI_TxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_ERROR_CB_ID, SAI_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
else
{
/* Store new Channel number */
Audio_Out_Ctx[Instance].ChannelsNbr = ChannelNbr;
}
}
else
{
if (ChannelNbr != 2U)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Store new Channel number */
Audio_Out_Ctx[Instance].ChannelsNbr = ChannelNbr;
}
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Get the audio Channels number.
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param ChannelNbr Audio Channels number used to play the audio stream.
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_GetChannelsNbr(uint32_t Instance, uint32_t *ChannelNbr)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_Out_Ctx[Instance].State == AUDIO_OUT_STATE_RESET)
{
ret = BSP_ERROR_BUSY;
}
else
{
/* Get the audio Channels number */
*ChannelNbr = Audio_Out_Ctx[Instance].ChannelsNbr;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get Audio Out state
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @param State Audio Out state
* @retval BSP status
*/
int32_t BSP_AUDIO_OUT_GetState(uint32_t Instance, uint32_t *State)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_OUT_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Return audio Output State */
*State = Audio_Out_Ctx[Instance].State;
}
/* Return BSP status */
return ret;
}
/**
* @brief This function handles Audio Out DMA interrupt requests.
* @param Instance Audio OUT instance
* @retval None
*/
void BSP_AUDIO_OUT_IRQHandler(uint32_t Instance)
{
if (Instance == 0U)
{
/* DMA2 Stream 6 */
HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);
}
else
{
/* BDMA Channel0 */
HAL_DMA_IRQHandler(haudio_out_i2s.hdmatx);
}
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 0) || !defined (USE_HAL_SAI_REGISTER_CALLBACKS)
/**
* @brief Tx Transfer completed callbacks.
* @param hsai SAI handle
* @retval None
*/
void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_TransferComplete_CallBack(0);
}
/**
* @brief Tx Half Transfer completed callbacks.
* @param hsai SAI handle
* @retval None
*/
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_HalfTransfer_CallBack(0);
}
/**
* @brief SAI error callbacks.
* @param hsai SAI handle
* @retval None
*/
void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
{
if (hsai->Instance == AUDIO_OUT_SAIx)
{
BSP_AUDIO_OUT_Error_CallBack(0);
}
else
{
BSP_AUDIO_IN_Error_CallBack(0);
}
}
#endif
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 0) || !defined (USE_HAL_I2S_REGISTER_CALLBACKS)
/**
* @brief Tx Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_TransferComplete_CallBack(1);
}
/**
* @brief Tx Half Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_HalfTransfer_CallBack(1);
}
/**
* @brief Rx Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_IN_TransferComplete_CallBack(1);
}
/**
* @brief Rx Half Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_IN_HalfTransfer_CallBack(1);
}
/**
* @brief I2S error callbacks.
* @param hi2s I2S handle
* @retval None
*/
void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
{
if (hi2s->Instance == AUDIO_OUT_I2Sx)
{
BSP_AUDIO_OUT_Error_CallBack(1);
}
else
{
BSP_AUDIO_IN_Error_CallBack(1);
}
}
#endif
/**
* @brief Manages the DMA full Transfer complete event
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval None
*/
__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(uint32_t Instance)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(Instance);
}
/**
* @brief Manages the DMA Half Transfer complete event
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval None
*/
__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(uint32_t Instance)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(Instance);
}
/**
* @brief Manages the DMA FIFO error event
* @param Instance AUDIO OUT Instance. It can only be 0 (SAI) or 1 (I2S)
* @retval None
*/
__weak void BSP_AUDIO_OUT_Error_CallBack(uint32_t Instance)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(Instance);
}
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_OUT_Private_Functions AUDIO OUT Private Functions
* @{
*/
#if (USE_AUDIO_CODEC_CS42L51 == 1)
/**
* @brief Register Bus IOs if component ID is OK
* @retval error status
*/
static int32_t CS42L51_Probe(void)
{
int32_t ret = BSP_ERROR_NONE;
CS42L51_IO_t IOCtx;
static CS42L51_Object_t CS42L51Obj;
uint32_t cs42l51_id;
/* Configure the audio driver */
IOCtx.Address = AUDIO_I2C_ADDRESS;
IOCtx.Init = BSP_I2C2_Init;
IOCtx.DeInit = BSP_I2C2_DeInit;
IOCtx.ReadReg = BSP_I2C2_ReadReg;
IOCtx.WriteReg = BSP_I2C2_WriteReg;
IOCtx.GetTick = BSP_GetTick;
if (CS42L51_RegisterBusIO(&CS42L51Obj, &IOCtx) != CS42L51_OK)
{
ret = BSP_ERROR_BUS_FAILURE;
}
else if (CS42L51_ReadID(&CS42L51Obj, &cs42l51_id) != CS42L51_OK)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else if ((cs42l51_id & CS42L51_ID_MASK) != CS42L51_ID)
{
ret = BSP_ERROR_UNKNOWN_COMPONENT;
}
else
{
Audio_Drv = (AUDIO_Drv_t *) &CS42L51_Driver;
Audio_CompObj = &CS42L51Obj;
}
return ret;
}
#endif
/**
* @brief Initialize BSP_AUDIO_OUT MSP.
* @param hsai SAI handle
* @retval None
*/
static void SAI_MspInit(SAI_HandleTypeDef *hsai)
{
GPIO_InitTypeDef gpio_init_structure;
static DMA_HandleTypeDef hdma_sai_tx, hdma_sai_rx;
/* Enable SAI clock */
AUDIO_OUT_SAIx_CLK_ENABLE();
/* Enable GPIO clock */
AUDIO_OUT_SAIx_MCLK_ENABLE();
AUDIO_OUT_SAIx_SCK_ENABLE();
AUDIO_OUT_SAIx_SD_ENABLE();
AUDIO_OUT_SAIx_FS_ENABLE();
/* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/
gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN;
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_AF;
HAL_GPIO_Init(AUDIO_OUT_SAIx_FS_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = AUDIO_OUT_SAIx_SCK_PIN;
gpio_init_structure.Alternate = AUDIO_OUT_SAIx_SCK_AF;
HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = AUDIO_OUT_SAIx_SD_PIN;
gpio_init_structure.Alternate = AUDIO_OUT_SAIx_SD_AF;
HAL_GPIO_Init(AUDIO_OUT_SAIx_SD_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN;
gpio_init_structure.Alternate = AUDIO_OUT_SAIx_MCLK_AF;
HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure);
/* Enable the DMA clock */
AUDIO_OUT_SAIx_DMAx_CLK_ENABLE();
if (hsai->Instance == AUDIO_OUT_SAIx)
{
/* Configure the hdma_saiTx handle parameters */
hdma_sai_tx.Init.Request = AUDIO_OUT_SAIx_DMAx_REQUEST;
hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE;
if (Audio_Out_Ctx[0].BitsPerSample == AUDIO_RESOLUTION_16B)
{
hdma_sai_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_sai_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
}
else /* AUDIO_RESOLUTION_24B */
{
hdma_sai_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sai_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
}
hdma_sai_tx.Init.Mode = DMA_CIRCULAR;
hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM;
/* Associate the DMA handle */
__HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx);
/* Deinitialize the Stream for new transfer */
(void)HAL_DMA_DeInit(&hdma_sai_tx);
/* Configure the DMA Stream */
(void)HAL_DMA_Init(&hdma_sai_tx);
/* SAI DMA IRQ Channel configuration */
HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, BSP_AUDIO_OUT_IT_PRIORITY, 0);
HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ);
}
/* Audio In Msp initialization */
if (hsai->Instance == AUDIO_IN_SAIx)
{
/* Enable SAI clock */
AUDIO_IN_SAIx_CLK_ENABLE();
/* Enable SD GPIO clock */
AUDIO_IN_SAIx_SD_ENABLE();
/* CODEC_SAI pin configuration: SD pin */
gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN;
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init_structure.Alternate = AUDIO_IN_SAIx_AF;
HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure);
/* Enable the DMA clock */
AUDIO_IN_SAIx_DMAx_CLK_ENABLE();
/* Configure the hdma_sai_rx handle parameters */
hdma_sai_rx.Init.Request = AUDIO_IN_SAIx_DMAx_REQUEST;
hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE;
if (Audio_In_Ctx[0].BitsPerSample == AUDIO_RESOLUTION_16B)
{
hdma_sai_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_sai_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
}
else /* AUDIO_RESOLUTION_24B */
{
hdma_sai_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_sai_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
}
hdma_sai_rx.Init.Mode = DMA_CIRCULAR;
hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE;
hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM;
/* Associate the DMA handle */
__HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx);
/* Deinitialize the Stream for new transfer */
(void)HAL_DMA_DeInit(&hdma_sai_rx);
/* Configure the DMA Stream */
(void)HAL_DMA_Init(&hdma_sai_rx);
/* SAI DMA IRQ Channel configuration */
HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, BSP_AUDIO_IN_IT_PRIORITY, 0);
HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ);
}
}
/**
* @brief Initialize BSP_AUDIO_OUT MSP.
* @param hi2s I2S handle
* @retval None
*/
static void I2S_MspInit(I2S_HandleTypeDef *hi2s)
{
GPIO_InitTypeDef gpio_init_structure;
static DMA_HandleTypeDef hdma_i2s_tx;
static DMA_HandleTypeDef hdma_i2s_rx;
/* Enable I2S clock */
AUDIO_OUT_I2Sx_CLK_ENABLE();
/* Enable MCK, SCK, WS, SD and CODEC_INT GPIO clock */
AUDIO_OUT_I2Sx_MCK_GPIO_CLK_ENABLE();
AUDIO_OUT_I2Sx_SCK_GPIO_CLK_ENABLE();
AUDIO_OUT_I2Sx_SD_GPIO_CLK_ENABLE();
AUDIO_OUT_I2Sx_WS_GPIO_CLK_ENABLE();
/* CODEC_I2S pins configuration: MCK, SCK, WS and SD pins */
gpio_init_structure.Pin = AUDIO_OUT_I2Sx_MCK_PIN;
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_NOPULL;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init_structure.Alternate = AUDIO_OUT_I2Sx_MCK_AF;
HAL_GPIO_Init(AUDIO_OUT_I2Sx_MCK_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = AUDIO_OUT_I2Sx_SCK_PIN;
gpio_init_structure.Alternate = AUDIO_OUT_I2Sx_SCK_AF;
HAL_GPIO_Init(AUDIO_OUT_I2Sx_SCK_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = AUDIO_OUT_I2Sx_WS_PIN;
gpio_init_structure.Alternate = AUDIO_OUT_I2Sx_WS_AF;
HAL_GPIO_Init(AUDIO_OUT_I2Sx_WS_GPIO_PORT, &gpio_init_structure);
gpio_init_structure.Pin = AUDIO_OUT_I2Sx_SD_PIN;
gpio_init_structure.Alternate = AUDIO_OUT_I2Sx_SD_AF;
HAL_GPIO_Init(AUDIO_OUT_I2Sx_SD_GPIO_PORT, &gpio_init_structure);
if (hi2s == &haudio_out_i2s)
{
/* Enable the DMA clock */
AUDIO_OUT_I2Sx_DMAx_CLK_ENABLE();
/* Configure the hdma_i2s_tx handle parameters */
hdma_i2s_tx.Init.Request = AUDIO_OUT_I2Sx_DMAx_REQUEST;
hdma_i2s_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2s_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2s_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2s_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_i2s_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_i2s_tx.Init.Mode = DMA_CIRCULAR;
hdma_i2s_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2s_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_i2s_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_i2s_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_i2s_tx.Init.PeriphBurst = DMA_MBURST_SINGLE;
hdma_i2s_tx.Instance = AUDIO_OUT_I2Sx_DMAx_STREAM;
/* Associate the DMA handle */
__HAL_LINKDMA(hi2s, hdmatx, hdma_i2s_tx);
/* Deinitialize the Stream for new transfer */
(void)HAL_DMA_DeInit(&hdma_i2s_tx);
/* Configure the DMA Stream */
(void)HAL_DMA_Init(&hdma_i2s_tx);
/* I2S DMA IRQ Channel configuration */
HAL_NVIC_SetPriority(AUDIO_OUT_I2Sx_DMAx_IRQ, BSP_AUDIO_OUT_IT_PRIORITY, 0);
HAL_NVIC_EnableIRQ(AUDIO_OUT_I2Sx_DMAx_IRQ);
}
if (hi2s == &haudio_in_i2s)
{
AUDIO_IN_I2Sx_SD_GPIO_CLK_ENABLE();
gpio_init_structure.Pin = AUDIO_IN_I2Sx_SD_PIN;
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_PULLDOWN;
gpio_init_structure.Alternate = AUDIO_IN_I2Sx_SD_AF;
HAL_GPIO_Init(AUDIO_IN_I2Sx_SD_GPIO_PORT, &gpio_init_structure);
/* Enable the DMA clock */
AUDIO_IN_I2Sx_DMAx_CLK_ENABLE();
/* Configure the hdma_i2s_rx handle parameters */
hdma_i2s_rx.Init.Request = AUDIO_IN_I2Sx_DMAx_REQUEST;
hdma_i2s_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2s_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2s_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2s_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_i2s_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_i2s_rx.Init.Mode = DMA_CIRCULAR;
hdma_i2s_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2s_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_i2s_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_i2s_rx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_i2s_rx.Init.PeriphBurst = DMA_MBURST_SINGLE;
hdma_i2s_rx.Instance = AUDIO_IN_I2Sx_DMAx_STREAM;
/* Associate the DMA handle */
__HAL_LINKDMA(hi2s, hdmarx, hdma_i2s_rx);
/* Deinitialize the Stream for new transfer */
(void)HAL_DMA_DeInit(&hdma_i2s_rx);
/* Configure the DMA Stream */
(void)HAL_DMA_Init(&hdma_i2s_rx);
/* I2S DMA IRQ Channel configuration */
HAL_NVIC_SetPriority(AUDIO_IN_I2Sx_DMAx_IRQ, BSP_AUDIO_IN_IT_PRIORITY, 0);
HAL_NVIC_EnableIRQ(AUDIO_IN_I2Sx_DMAx_IRQ);
}
}
/**
* @brief Deinitializes SAI MSP.
* @param hsai SAI handle
* @retval HAL status
*/
static void SAI_MspDeInit(SAI_HandleTypeDef *hsai)
{
if (hsai->Instance == AUDIO_OUT_SAIx)
{
/* SAI DMA IRQ Channel deactivation */
HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ);
/* Deinitialize the DMA stream */
(void)HAL_DMA_DeInit(hsai->hdmatx);
/* De-initialize FS, SCK, MCK and SD pins */
HAL_GPIO_DeInit(AUDIO_OUT_SAIx_FS_GPIO_PORT, AUDIO_OUT_SAIx_FS_PIN);
HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SCK_GPIO_PORT, AUDIO_OUT_SAIx_SCK_PIN);
HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SD_GPIO_PORT, AUDIO_OUT_SAIx_SD_PIN);
HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, AUDIO_OUT_SAIx_MCLK_PIN);
}
if (hsai->Instance == AUDIO_IN_SAIx)
{
/* SAI DMA IRQ Channel deactivation */
HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ);
/* Deinitialize the DMA stream */
(void)HAL_DMA_DeInit(hsai->hdmarx);
/* De-initialize SD pin */
HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, AUDIO_IN_SAIx_SD_PIN);
/* Disable SAI clock */
AUDIO_IN_SAIx_CLK_DISABLE();
}
}
/**
* @brief Deinitializes I2S MSP.
* @param hi2s I2S handle
* @retval HAL status
*/
static void I2S_MspDeInit(I2S_HandleTypeDef *hi2s)
{
/* I2S DMA IRQ Channel deactivation */
HAL_NVIC_DisableIRQ(AUDIO_OUT_I2Sx_DMAx_IRQ);
HAL_NVIC_DisableIRQ(AUDIO_IN_I2Sx_DMAx_IRQ);
/* Deinitialize the DMA stream */
(void)HAL_DMA_DeInit(hi2s->hdmatx);
(void)HAL_DMA_DeInit(hi2s->hdmarx);
/* Disable I2S peripheral */
__HAL_I2S_DISABLE(hi2s);
/* Deactivates CODEC_I2S pins WS, SCK, MCK and SD by putting them in input mode */
HAL_GPIO_DeInit(AUDIO_OUT_I2Sx_MCK_GPIO_PORT, AUDIO_OUT_I2Sx_MCK_PIN);
HAL_GPIO_DeInit(AUDIO_OUT_I2Sx_SCK_GPIO_PORT, AUDIO_OUT_I2Sx_SCK_PIN);
HAL_GPIO_DeInit(AUDIO_OUT_I2Sx_WS_GPIO_PORT, AUDIO_OUT_I2Sx_WS_PIN);
HAL_GPIO_DeInit(AUDIO_OUT_I2Sx_SD_GPIO_PORT, AUDIO_OUT_I2Sx_SD_PIN);
HAL_GPIO_DeInit(AUDIO_IN_I2Sx_SD_GPIO_PORT, AUDIO_IN_I2Sx_SD_PIN);
/* Disable I2S clock */
AUDIO_OUT_I2Sx_CLK_DISABLE();
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/**
* @brief Tx Transfer completed callbacks.
* @param hsai SAI handle
* @retval None
*/
static void SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_TransferComplete_CallBack(0);
}
/**
* @brief Tx Half Transfer completed callbacks.
* @param hsai SAI handle
* @retval None
*/
static void SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_HalfTransfer_CallBack(0);
}
/**
* @brief SAI error callbacks.
* @param hsai SAI handle
* @retval None
*/
static void SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
{
if (hsai->Instance == AUDIO_OUT_SAIx)
{
BSP_AUDIO_OUT_Error_CallBack(0);
}
else
{
BSP_AUDIO_IN_Error_CallBack(0);
}
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/**
* @brief Tx Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
static void I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_TransferComplete_CallBack(1);
}
/**
* @brief Tx Half Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
static void I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_OUT_HalfTransfer_CallBack(1);
}
/**
* @brief Rx Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
static void I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_IN_TransferComplete_CallBack(1);
}
/**
* @brief Rx Half Transfer completed callbacks.
* @param hi2s I2S handle
* @retval None
*/
static void I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hi2s);
/* Manage the remaining file size and new address offset: This function
should be coded by user (its prototype is already declared in stm32h7b3i_eval_audio.h) */
BSP_AUDIO_IN_HalfTransfer_CallBack(1);
}
/**
* @brief I2S error callbacks.
* @param hi2s I2S handle
* @retval None
*/
static void I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
{
if (hi2s->Instance == AUDIO_OUT_I2Sx)
{
BSP_AUDIO_OUT_Error_CallBack(1);
}
else
{
BSP_AUDIO_IN_Error_CallBack(1);
}
}
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_IN_Exported_Functions STM32H7B3I_EVAL_AUDIO_IN Exported Functions
* @{
*/
/**
* @brief Initialize wave recording.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param AudioInit Init structure
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_Init(uint32_t Instance, BSP_AUDIO_Init_t *AudioInit)
{
uint32_t i;
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Store the audio record context */
Audio_In_Ctx[Instance].Device = AudioInit->Device;
Audio_In_Ctx[Instance].ChannelsNbr = AudioInit->ChannelsNbr;
Audio_In_Ctx[Instance].SampleRate = AudioInit->SampleRate;
Audio_In_Ctx[Instance].BitsPerSample = AudioInit->BitsPerSample;
Audio_In_Ctx[Instance].Volume = AudioInit->Volume;
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RESET;
if (Instance != 2U)
{
/* Un-reset audio codec if not currently used by audio out instances */
if ((Audio_Out_Ctx[0].State == AUDIO_OUT_STATE_RESET) && (Audio_Out_Ctx[1].State == AUDIO_OUT_STATE_RESET))
{
if (CS42L51_PowerUp() != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Initialize the codec internal registers */
if (CS42L51_Probe() != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
}
}
if (ret == BSP_ERROR_NONE)
{
if (Instance == 0U)
{
/* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
if (MX_SAI1_ClockConfig(&haudio_in_sai, AudioInit->SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
else
{
haudio_in_sai.Instance = AUDIO_IN_SAIx;
haudio_out_sai.Instance = AUDIO_OUT_SAIx;
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 0)
SAI_MspInit(&haudio_in_sai);
#else
/* Register the default SAI MSP callbacks */
if (Audio_In_Ctx[Instance].IsMspCallbacksValid == 0U)
{
if (BSP_AUDIO_IN_RegisterDefaultMspCallbacks(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 0) */
MX_SAI_Config mx_config;
/* Prepare haudio_in_sai handle */
mx_config.AudioFrequency = Audio_In_Ctx[Instance].SampleRate;
mx_config.AudioMode = SAI_MODESLAVE_RX;
mx_config.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
mx_config.MonoStereoMode = (AudioInit->ChannelsNbr == 1U) ? SAI_MONOMODE : SAI_STEREOMODE;
mx_config.DataSize = SAI_DATASIZE_16;
mx_config.FrameLength = 32;
mx_config.ActiveFrameLength = 16;
mx_config.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
mx_config.Synchro = SAI_SYNCHRONOUS;
mx_config.SynchroExt = SAI_SYNCEXT_DISABLE;
if (Audio_In_Ctx[Instance].Device == AUDIO_IN_DEVICE_ANALOG_MIC)
{
mx_config.SlotActive = SAI_SLOTACTIVE_0;
}
else
{
mx_config.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
}
if (MX_SAI1_Block_B_Init(&haudio_in_sai, &mx_config) != HAL_OK)
{
/* Return BSP_ERROR_PERIPH_FAILURE when operations are not correctly done */
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
/* Prepare haudio_out_sai handle */
mx_config.AudioMode = SAI_MODEMASTER_TX;
mx_config.Synchro = SAI_ASYNCHRONOUS;
mx_config.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
if (MX_SAI1_Block_A_Init(&haudio_out_sai, &mx_config) != HAL_OK)
{
/* Return BSP_ERROR_PERIPH_FAILURE when operations are not correctly done */
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
if (ret == BSP_ERROR_NONE)
{
/* Register SAI TC, HT and Error callbacks */
if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_RX_COMPLETE_CB_ID, SAI_RxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_RX_HALFCOMPLETE_CB_ID, SAI_RxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_ERROR_CB_ID, SAI_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
#if (USE_AUDIO_CODEC_CS42L51 == 1)
if (ret == BSP_ERROR_NONE)
{
CS42L51_Init_t codec_init;
/* Fill codec_init structure */
codec_init.OutputDevice = ((Audio_Out_Ctx[0].State == AUDIO_OUT_STATE_RESET) && (Audio_Out_Ctx[1].State == AUDIO_OUT_STATE_RESET)) ? \
CS42L51_OUT_NONE : CS42L51_OUT_HEADPHONE;
codec_init.Frequency = AudioInit->SampleRate;
codec_init.Resolution = CS42L51_RESOLUTION_16b; /* Not used */
codec_init.Volume = AudioInit->Volume;
codec_init.InputDevice = (AudioInit->Device == AUDIO_IN_DEVICE_ANALOG_LINE1) ? CS42L51_IN_LINE1 : CS42L51_IN_MIC1;
/* Initialize the codec internal registers */
if (Audio_Drv->Init(Audio_CompObj, &codec_init) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Update audio in context state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_STOP;
}
}
#endif /*USE_AUDIO_CODEC_CS42L51 == 1)*/
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
}
#endif
}
}
else if (Instance == 1U)
{
/* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
if (MX_I2S6_ClockConfig(&haudio_in_i2s, AudioInit->SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
else
{
/* I2S data transfer preparation:
Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
haudio_in_i2s.Instance = AUDIO_OUT_I2Sx;
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 0)
I2S_MspInit(&haudio_in_i2s);
#else
/* Register the default SAI MSP callbacks */
if (Audio_In_Ctx[Instance].IsMspCallbacksValid == 0U)
{
if (BSP_AUDIO_IN_RegisterDefaultMspCallbacks(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
MX_I2S_Config mx_i2s_config;
mx_i2s_config.AudioMode = I2S_MODE_MASTER_RX;
mx_i2s_config.SampleRate = AudioInit->SampleRate;
/* I2S peripheral initialization: this __weak function can be redefined by the application */
if (MX_I2S6_Init(&haudio_in_i2s, &mx_i2s_config) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_TX_COMPLETE_CB_ID, I2S_TxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_TX_HALF_COMPLETE_CB_ID, I2S_TxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_ERROR_CB_ID, I2S_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
#if (USE_AUDIO_CODEC_CS42L51 == 1)
/* Initialize the codec internal registers */
CS42L51_Init_t codec_init;
/* Fill codec_init structure */
codec_init.OutputDevice = ((Audio_Out_Ctx[0].State == AUDIO_OUT_STATE_RESET) && (Audio_Out_Ctx[1].State == AUDIO_OUT_STATE_RESET)) ? \
CS42L51_OUT_NONE : CS42L51_OUT_HEADPHONE;
codec_init.Frequency = AudioInit->SampleRate;
codec_init.Resolution = CS42L51_RESOLUTION_16b; /* Not used */
codec_init.Volume = AudioInit->Volume;
codec_init.InputDevice = (AudioInit->Device == AUDIO_IN_DEVICE_ANALOG_LINE1) ? CS42L51_IN_LINE1 : CS42L51_IN_MIC1;
/* Receive fake I2S data in order to generate MCLK needed by CS42L51 to set its registers */
if (HAL_I2S_Receive_DMA(&haudio_in_i2s, ((uint16_t *)0x38000000), 16) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}/* Initialize the codec internal registers */
else if (Audio_Drv->Init(Audio_CompObj, &codec_init) != 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Stop receiving fake I2S data */
if (HAL_I2S_DMAStop(&haudio_in_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
}
#endif
#endif /*USE_AUDIO_CODEC_CS42L51 == 1)*/
}
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
}
#endif
}
}
else /* (Instance == 2U) */
{
DFSDM_Filter_TypeDef *FilterInstnace[DFSDM_MIC_NUMBER] = {AUDIO_DFSDMx_MIC1_FILTER, AUDIO_DFSDMx_MIC2_FILTER, AUDIO_DFSDMx_MIC3_FILTER, AUDIO_DFSDMx_MIC4_FILTER, AUDIO_DFSDMx_MIC5_FILTER};
DFSDM_Channel_TypeDef *ChannelInstance[DFSDM_MIC_NUMBER] = {AUDIO_DFSDMx_MIC1_CHANNEL, AUDIO_DFSDMx_MIC2_CHANNEL, AUDIO_DFSDMx_MIC3_CHANNEL, AUDIO_DFSDMx_MIC4_CHANNEL, AUDIO_DFSDMx_MIC5_CHANNEL};
uint32_t DigitalMicPins[DFSDM_MIC_NUMBER] = {DFSDM_CHANNEL_SAME_CHANNEL_PINS, DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS, DFSDM_CHANNEL_SAME_CHANNEL_PINS, DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS, DFSDM_CHANNEL_SAME_CHANNEL_PINS};
uint32_t DigitalMicType[DFSDM_MIC_NUMBER] = {DFSDM_CHANNEL_SPI_RISING, DFSDM_CHANNEL_SPI_FALLING, DFSDM_CHANNEL_SPI_RISING, DFSDM_CHANNEL_SPI_FALLING, DFSDM_CHANNEL_SPI_RISING};
uint32_t Channel4Filter[DFSDM_MIC_NUMBER] = {AUDIO_DFSDMx_MIC1_CHANNEL_FOR_FILTER, AUDIO_DFSDMx_MIC2_CHANNEL_FOR_FILTER, AUDIO_DFSDMx_MIC3_CHANNEL_FOR_FILTER, AUDIO_DFSDMx_MIC4_CHANNEL_FOR_FILTER, AUDIO_DFSDMx_MIC5_CHANNEL_FOR_FILTER};
MX_DFSDM_Config dfsdm_config;
/* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */
if (Audio_In_Ctx[Instance].Device == AUDIO_IN_DEVICE_DIGITAL_MIC5)
{
if (MX_DFSDM2_ClockConfig(&haudio_in_dfsdm_channel[0], AudioInit->SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
}
else
{
if (MX_DFSDM1_ClockConfig(&haudio_in_dfsdm_channel[0], AudioInit->SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0)
DFSDM_FilterMspInit(&haudio_in_dfsdm_filter[1]);
DFSDM_ChannelMspInit(&haudio_in_dfsdm_channel[1]);
#else
/* Register the default DFSDM MSP callbacks */
if (Audio_In_Ctx[Instance].IsMspCallbacksValid == 0U)
{
if (BSP_AUDIO_IN_RegisterDefaultMspCallbacks(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) */
for (i = 0; i < DFSDM_MIC_NUMBER; i ++)
{
dfsdm_config.FilterInstance = FilterInstnace[i];
dfsdm_config.ChannelInstance = ChannelInstance[i];
dfsdm_config.DigitalMicPins = DigitalMicPins[i];
dfsdm_config.DigitalMicType = DigitalMicType[i];
dfsdm_config.Channel4Filter = Channel4Filter[i];
dfsdm_config.RegularTrigger = DFSDM_FILTER_SW_TRIGGER;
/* MIC2, MIC3 and MIC4 should be synchronized to MIC1 if it's used */
if ((i >= 1U) && (i < 4U)
&& ((Audio_In_Ctx[Instance].Device & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1))
{
dfsdm_config.RegularTrigger = DFSDM_FILTER_SYNC_TRIGGER;
}
dfsdm_config.SincOrder = DFSDM_FILTER_ORDER(Audio_In_Ctx[Instance].SampleRate);
dfsdm_config.Oversampling = DFSDM_OVER_SAMPLING(Audio_In_Ctx[Instance].SampleRate);
dfsdm_config.ClockDivider = DFSDM_CLOCK_DIVIDER(Audio_In_Ctx[Instance].SampleRate);
dfsdm_config.RightBitShift = DFSDM_MIC_BIT_SHIFT(Audio_In_Ctx[Instance].SampleRate);
if (((AudioInit->Device >> i) & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1)
{
/* Default configuration of DFSDM filters and channels */
if (Audio_In_Ctx[Instance].Device == AUDIO_IN_DEVICE_DIGITAL_MIC5)
{
if (MX_DFSDM2_Init(&haudio_in_dfsdm_filter[i], &haudio_in_dfsdm_channel[i], &dfsdm_config) != HAL_OK)
{
/* Return BSP_ERROR_PERIPH_FAILURE when operations are not correctly done */
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (MX_DFSDM1_Init(&haudio_in_dfsdm_filter[i], &haudio_in_dfsdm_channel[i], &dfsdm_config) != HAL_OK)
{
/* Return BSP_ERROR_PERIPH_FAILURE when operations are not correctly done */
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1)
/* Register filter regular conversion callbacks */
if (HAL_DFSDM_Filter_RegisterCallback(&haudio_in_dfsdm_filter[i], HAL_DFSDM_FILTER_REGCONV_COMPLETE_CB_ID,
DFSDM_FilterRegConvCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_DFSDM_Filter_RegisterCallback(&haudio_in_dfsdm_filter[i], HAL_DFSDM_FILTER_REGCONV_HALFCOMPLETE_CB_ID,
DFSDM_FilterRegConvHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) */
}
if (ret != BSP_ERROR_NONE)
{
break;
}
}
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1)
}
#endif
}
}
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_STOP;
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Deinit the audio IN peripherals.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_DeInit(uint32_t Instance)
{
uint32_t i;
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
if ((Instance == 0U) || (Instance == 1U))
{
/* Reset audio codec if not currently used by audio out instance 0 or 1 */
if ((Audio_Out_Ctx[0].State == AUDIO_OUT_STATE_RESET) && (Audio_Out_Ctx[1].State == AUDIO_OUT_STATE_RESET))
{
if (CS42L51_PowerDown() != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
if (Instance == 0U)
{
/* SAI peripheral de-initialization */
if (HAL_SAI_DeInit(&haudio_in_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
/* De-initialize audio codec if not currently used by audio out instance 0 or 1 */
else
{
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 0)
SAI_MspDeInit(&haudio_in_sai);
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 0) */
}
}
else
{
/* I2S peripheral de-initialization */
if (HAL_I2S_DeInit(&haudio_in_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
/* De-initialize audio codec if not currently used by audio out instance 0 or 1 */
else
{
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 0)
I2S_MspDeInit(&haudio_in_i2s);
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 0) */
}
}
if ((Audio_Out_Ctx[0].State == AUDIO_OUT_STATE_RESET) && (Audio_Out_Ctx[1].State == AUDIO_OUT_STATE_RESET))
{
if (Audio_Drv->DeInit(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
/* Update audio in context */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RESET;
}
}
}
else /* (Instance == 2U) */
{
for (i = 0U; i < DFSDM_MIC_NUMBER; i++)
{
/* De-initializes DFSDM Filter handle */
if (haudio_in_dfsdm_filter[i].Instance != NULL)
{
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0)
DFSDM_FilterMspDeInit(&haudio_in_dfsdm_filter[i]);
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0) */
if (HAL_OK != HAL_DFSDM_FilterDeInit(&haudio_in_dfsdm_filter[i]))
{
return BSP_ERROR_PERIPH_FAILURE;
}
haudio_in_dfsdm_filter[i].Instance = NULL;
}
/* De-initializes DFSDM Channel handle */
if (haudio_in_dfsdm_channel[i].Instance != NULL)
{
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0)
DFSDM_ChannelMspDeInit(&haudio_in_dfsdm_channel[i]);
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0) */
if (HAL_OK != HAL_DFSDM_ChannelDeInit(&haudio_in_dfsdm_channel[i]))
{
return BSP_ERROR_PERIPH_FAILURE;
}
haudio_in_dfsdm_channel[i].Instance = NULL;
}
}
/* Reset Audio_In_Ctx[2].IsMultiBuff if any */
Audio_In_Ctx[2].IsMultiBuff = 0;
}
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RESET;
}
/* Return BSP status */
return ret;
}
/**
* @brief Clock Config.
* @param hDfsdmChannel DFSDM Channel Handle
* @param SampleRate Audio frequency to be configured for the DFSDM Channel.
* @note This API is called by BSP_AUDIO_IN_Init()
* Being __weak it can be overwritten by the application
* @retval HAL_status
*/
__weak HAL_StatusTypeDef MX_DFSDM1_ClockConfig(DFSDM_Channel_HandleTypeDef *hDfsdmChannel, uint32_t SampleRate)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hDfsdmChannel);
HAL_StatusTypeDef ret = HAL_OK;
RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
/* Configure the PLL2 according to the requested audio frequency if not already done by other instances */
if ((Audio_Out_Ctx[0].State == AUDIO_OUT_STATE_RESET) && (Audio_In_Ctx[0].State == AUDIO_IN_STATE_RESET))
{
ret = MX_SAI1_ClockConfig(&haudio_in_sai, SampleRate);
}
return ret;
}
/**
* @brief Clock Config.
* @param hDfsdmChannel DFSDM Channel Handle
* @param SampleRate Audio frequency to be configured for the DFSDM Channel.
* @note This API is called by BSP_AUDIO_IN_Init()
* Being __weak it can be overwritten by the application
* @retval HAL_status
*/
__weak HAL_StatusTypeDef MX_DFSDM2_ClockConfig(DFSDM_Channel_HandleTypeDef *hDfsdmChannel, uint32_t SampleRate)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hDfsdmChannel);
HAL_StatusTypeDef ret = HAL_OK;
RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
/* Configure the PLL2 according to the requested audio frequency if not already done by other instances */
if (Audio_Out_Ctx[1].State == AUDIO_OUT_STATE_RESET)
{
ret = MX_I2S6_ClockConfig(&haudio_out_i2s, SampleRate);
}
return ret;
}
/**
* @brief Initializes the Audio instance (DFSDM).
* @param hDfsdmFilter DFSDM Filter Handle
* @param hDfsdmChannel DFSDM Channel Handle
* @param MXConfig DFSDM configuration structure
* @note Being __weak it can be overwritten by the application
* @note Channel output Clock Divider and Filter Oversampling are calculated as follow:
* - Clock_Divider = CLK(input DFSDM)/CLK(micro) with
* 1MHZ < CLK(micro) < 3.2MHZ (TYP 2.4MHZ for MP34DT01TR)
* - Oversampling = CLK(input DFSDM)/(Clock_Divider * AudioFreq)
* @retval HAL_status
*/
__weak HAL_StatusTypeDef MX_DFSDM1_Init(DFSDM_Filter_HandleTypeDef *hDfsdmFilter,
DFSDM_Channel_HandleTypeDef *hDfsdmChannel, MX_DFSDM_Config *MXConfig)
{
/* MIC filters initialization */
hDfsdmFilter->Instance = MXConfig->FilterInstance;
hDfsdmFilter->Init.RegularParam.Trigger = MXConfig->RegularTrigger;
hDfsdmFilter->Init.RegularParam.FastMode = ENABLE;
hDfsdmFilter->Init.RegularParam.DmaMode = ENABLE;
hDfsdmFilter->Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
hDfsdmFilter->Init.InjectedParam.ScanMode = DISABLE;
hDfsdmFilter->Init.InjectedParam.DmaMode = DISABLE;
hDfsdmFilter->Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
hDfsdmFilter->Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
hDfsdmFilter->Init.FilterParam.SincOrder = MXConfig->SincOrder;
hDfsdmFilter->Init.FilterParam.Oversampling = MXConfig->Oversampling;
hDfsdmFilter->Init.FilterParam.IntOversampling = 1;
if (HAL_DFSDM_FilterInit(hDfsdmFilter) != HAL_OK)
{
return HAL_ERROR;
}
/* MIC channels initialization */
hDfsdmChannel->Instance = MXConfig->ChannelInstance;
hDfsdmChannel->Init.OutputClock.Activation = ENABLE;
hDfsdmChannel->Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
hDfsdmChannel->Init.OutputClock.Divider = MXConfig->ClockDivider;
hDfsdmChannel->Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
hDfsdmChannel->Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
hDfsdmChannel->Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
hDfsdmChannel->Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
hDfsdmChannel->Init.Awd.Oversampling = 10;
hDfsdmChannel->Init.Offset = 0;
hDfsdmChannel->Init.RightBitShift = MXConfig->RightBitShift;
hDfsdmChannel->Init.Input.Pins = MXConfig->DigitalMicPins;
hDfsdmChannel->Init.SerialInterface.Type = MXConfig->DigitalMicType;
if (HAL_OK != HAL_DFSDM_ChannelInit(hDfsdmChannel))
{
return HAL_ERROR;
}
/* Configure injected channel */
if (HAL_DFSDM_FilterConfigRegChannel(hDfsdmFilter, MXConfig->Channel4Filter, DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Initializes the Audio instance (DFSDM).
* @param hDfsdmFilter DFSDM Filter Handle
* @param hDfsdmChannel DFSDM Channel Handle
* @param MXConfig DFSDM configuration structure.
* @note Being __weak it can be overwritten by the application
* @note Channel output Clock Divider and Filter Oversampling are calculated as follow:
* - Clock_Divider = CLK(input DFSDM)/CLK(micro) with
* 1MHZ < CLK(micro) < 3.2MHZ (TYP 2.4MHZ for MP34DT01TR)
* - Oversampling = CLK(input DFSDM)/(Clock_Divider * AudioFreq)
* @retval HAL_status
*/
__weak HAL_StatusTypeDef MX_DFSDM2_Init(DFSDM_Filter_HandleTypeDef *hDfsdmFilter,
DFSDM_Channel_HandleTypeDef *hDfsdmChannel, MX_DFSDM_Config *MXConfig)
{
/* MIC filters initialization */
__HAL_DFSDM_FILTER_RESET_HANDLE_STATE(hDfsdmFilter);
hDfsdmFilter->Instance = MXConfig->FilterInstance;
hDfsdmFilter->Init.RegularParam.Trigger = MXConfig->RegularTrigger;
hDfsdmFilter->Init.RegularParam.FastMode = ENABLE;
hDfsdmFilter->Init.RegularParam.DmaMode = ENABLE;
hDfsdmFilter->Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
hDfsdmFilter->Init.InjectedParam.ScanMode = DISABLE;
hDfsdmFilter->Init.InjectedParam.DmaMode = DISABLE;
hDfsdmFilter->Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
hDfsdmFilter->Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
hDfsdmFilter->Init.FilterParam.SincOrder = MXConfig->SincOrder;
hDfsdmFilter->Init.FilterParam.Oversampling = MXConfig->Oversampling;
hDfsdmFilter->Init.FilterParam.IntOversampling = 1;
if (HAL_DFSDM_FilterInit(hDfsdmFilter) != HAL_OK)
{
return HAL_ERROR;
}
/* MIC channels initialization */
__HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(hDfsdmChannel);
hDfsdmChannel->Instance = MXConfig->ChannelInstance;
hDfsdmChannel->Init.OutputClock.Activation = ENABLE;
hDfsdmChannel->Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
hDfsdmChannel->Init.OutputClock.Divider = MXConfig->ClockDivider;
hDfsdmChannel->Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
hDfsdmChannel->Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
hDfsdmChannel->Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
hDfsdmChannel->Init.Awd.FilterOrder = DFSDM_CHANNEL_SINC1_ORDER;
hDfsdmChannel->Init.Awd.Oversampling = 10;
hDfsdmChannel->Init.Offset = 0;
hDfsdmChannel->Init.RightBitShift = MXConfig->RightBitShift;
hDfsdmChannel->Init.Input.Pins = MXConfig->DigitalMicPins;
hDfsdmChannel->Init.SerialInterface.Type = MXConfig->DigitalMicType;
if (HAL_OK != HAL_DFSDM_ChannelInit(hDfsdmChannel))
{
return HAL_ERROR;
}
/* Configure injected channel */
if (HAL_DFSDM_FilterConfigRegChannel(hDfsdmFilter, MXConfig->Channel4Filter, DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Initializes the Audio Codec audio in instance (SAI).
* @param hsai SAI handle
* @param MXConfig SAI configuration structure
* @note Being __weak it can be overwritten by the application
* @retval HAL status
*/
__weak HAL_StatusTypeDef MX_SAI1_Block_B_Init(SAI_HandleTypeDef *hsai, MX_SAI_Config *MXConfig)
{
HAL_StatusTypeDef ret = HAL_OK;
/* Disable SAI peripheral to allow access to SAI internal registers */
__HAL_SAI_DISABLE(hsai);
/* Configure SAI1_Block_B */
hsai->Init.AudioFrequency = MXConfig->AudioFrequency;
hsai->Init.MonoStereoMode = MXConfig->MonoStereoMode;
hsai->Init.AudioMode = MXConfig->AudioMode;
hsai->Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hsai->Init.Protocol = SAI_FREE_PROTOCOL;
hsai->Init.DataSize = MXConfig->DataSize;
hsai->Init.FirstBit = SAI_FIRSTBIT_MSB;
hsai->Init.ClockStrobing = MXConfig->ClockStrobing;
hsai->Init.Synchro = MXConfig->Synchro;
hsai->Init.OutputDrive = MXConfig->OutputDrive;
hsai->Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
hsai->Init.SynchroExt = MXConfig->SynchroExt;
hsai->Init.CompandingMode = SAI_NOCOMPANDING;
hsai->Init.TriState = SAI_OUTPUT_RELEASED;
hsai->Init.Mckdiv = 0;
hsai->Init.MckOutput = SAI_MCK_OUTPUT_ENABLE;
hsai->Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE;
hsai->Init.PdmInit.Activation = DISABLE;
/* Configure SAI_Block_x Frame */
hsai->FrameInit.FrameLength = MXConfig->FrameLength;
hsai->FrameInit.ActiveFrameLength = MXConfig->ActiveFrameLength;
hsai->FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
hsai->FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
hsai->FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
/* Configure SAI Block_x Slot */
hsai->SlotInit.FirstBitOffset = 0;
if ((MXConfig->DataSize == AUDIO_RESOLUTION_24B) || (MXConfig->DataSize == AUDIO_RESOLUTION_32B))
{
hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
}
else
{
hsai->SlotInit.SlotSize = SAI_SLOTSIZE_16B;
}
hsai->SlotInit.SlotNumber = 2;
hsai->SlotInit.SlotActive = MXConfig->SlotActive;
if (HAL_SAI_Init(hsai) != HAL_OK)
{
ret = HAL_ERROR;
}
return ret;
}
#if ((USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) || (USE_HAL_SAI_REGISTER_CALLBACKS == 1) || (USE_HAL_I2S_REGISTER_CALLBACKS == 1))
/**
* @brief Default BSP AUDIO IN Msp Callbacks
* @param Instance BSP AUDIO IN Instance
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_RegisterDefaultMspCallbacks(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Instance == 0U)
{
__HAL_SAI_RESET_HANDLE_STATE(&haudio_in_sai);
__HAL_SAI_RESET_HANDLE_STATE(&haudio_out_sai);
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_MSPINIT_CB_ID, SAI_MspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_out_sai, HAL_SAI_MSPINIT_CB_ID, SAI_MspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_MSPDEINIT_CB_ID, SAI_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_MSPDEINIT_CB_ID, SAI_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
}
else if (Instance == 1U)
{
__HAL_I2S_RESET_HANDLE_STATE(&haudio_in_i2s);
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_MSPDEINIT_CB_ID, I2S_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_MSPDEINIT_CB_ID, I2S_MspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
}
else
{
uint32_t i;
for (i = 0; i < DFSDM_MIC_NUMBER; i ++)
{
if (((Audio_In_Ctx[Instance].Device >> i) & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1)
{
__HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&haudio_in_dfsdm_channel[i]);
__HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&haudio_in_dfsdm_filter[i]);
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1)
/* Register MspInit/MspDeInit Callbacks */
if (HAL_DFSDM_Channel_RegisterCallback(&haudio_in_dfsdm_channel[i], HAL_DFSDM_CHANNEL_MSPINIT_CB_ID,
DFSDM_ChannelMspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_DFSDM_Filter_RegisterCallback(&haudio_in_dfsdm_filter[i], HAL_DFSDM_FILTER_MSPINIT_CB_ID,
DFSDM_FilterMspInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_DFSDM_Channel_RegisterCallback(&haudio_in_dfsdm_channel[i], HAL_DFSDM_CHANNEL_MSPDEINIT_CB_ID,
DFSDM_ChannelMspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_DFSDM_Filter_RegisterCallback(&haudio_in_dfsdm_filter[i], HAL_DFSDM_FILTER_MSPDEINIT_CB_ID,
DFSDM_FilterMspDeInit) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) */
}
}
}
if (ret == BSP_ERROR_NONE)
{
Audio_In_Ctx[Instance].IsMspCallbacksValid = 1;
}
/* Return BSP status */
return ret;
}
/**
* @brief BSP AUDIO In Filter Msp Callback registering
* @param Instance AUDIO IN Instance
* @param CallBacks pointer to filter MspInit/MspDeInit functions
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_RegisterMspCallbacks(uint32_t Instance, BSP_AUDIO_IN_Cb_t *CallBacks)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Instance == 0U)
{
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_MSPINIT_CB_ID, CallBacks->pMspSaiInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_MSPDEINIT_CB_ID, CallBacks->pMspSaiDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
}
else if (Instance == 1U)
{
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_MSPINIT_CB_ID, CallBacks->pMspI2sInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_MSPDEINIT_CB_ID, CallBacks->pMspI2sDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
}
else
{
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1)
uint32_t i;
for (i = 0U; i < DFSDM_MIC_NUMBER; i ++)
{
__HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&haudio_in_dfsdm_filter[i]);
/* Register MspInit/MspDeInit Callback */
if (HAL_DFSDM_Filter_RegisterCallback(&haudio_in_dfsdm_filter[i], HAL_DFSDM_FILTER_MSPINIT_CB_ID,
CallBacks->pMspFltrInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_DFSDM_Filter_RegisterCallback(&haudio_in_dfsdm_filter[i], HAL_DFSDM_FILTER_MSPDEINIT_CB_ID,
CallBacks->pMspFltrDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_DFSDM_Channel_RegisterCallback(&haudio_in_dfsdm_channel[i], HAL_DFSDM_CHANNEL_MSPINIT_CB_ID,
CallBacks->pMspChInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_DFSDM_Channel_RegisterCallback(&haudio_in_dfsdm_channel[i], HAL_DFSDM_CHANNEL_MSPDEINIT_CB_ID,
CallBacks->pMspChDeInitCb) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) */
}
if (ret == BSP_ERROR_NONE)
{
Audio_In_Ctx[Instance].IsMspCallbacksValid = 1;
}
/* Return BSP status */
return ret;
}
#endif /* ((USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) || (USE_HAL_SAI_REGISTER_CALLBACKS == 1) || (USE_HAL_I2S_REGISTER_CALLBACKS == 1)) */
/**
* @brief Start audio recording.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param pBuf Main buffer pointer for the recorded data storing
* @param NbrOfBytes Size of the record buffer in bytes
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_Record(uint32_t Instance, uint8_t *pBuf, uint32_t NbrOfBytes)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
if (Instance == 0U)
{
/* If no playback is on going, just transmit some bytes on audio out stream to generate SAI clock and synchro signals */
if ((Audio_Out_Ctx[0].State != AUDIO_OUT_STATE_PLAYING) && (Audio_Out_Ctx[0].State != AUDIO_OUT_STATE_PAUSE))
{
uint8_t TxData[2] = {0x00U, 0x00U};
if (HAL_SAI_Transmit(&haudio_out_sai, TxData, 2, 1000) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
if (ret == BSP_ERROR_NONE)
{
/* Call the audio Codec Play function */
if (Audio_Drv->Play(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Start the process receive DMA */
if (HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t *)pBuf,
(uint16_t)(NbrOfBytes / (Audio_In_Ctx[Instance].BitsPerSample / 8U))) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
}
else if (Instance == 1U)
{
/* Call the audio Codec Play function */
if (Audio_Drv->Play(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else
{
/* Start the process receive DMA */
if (HAL_I2S_Receive_DMA(&haudio_in_i2s, (uint16_t *)pBuf,
(uint16_t)(NbrOfBytes / (Audio_In_Ctx[Instance].BitsPerSample / 8U))) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
else
{
Audio_In_Ctx[Instance].pBuff = (uint16_t *)pBuf;
Audio_In_Ctx[Instance].Size = NbrOfBytes;
/* Reset Buffer Trigger */
RecBuffTrigger = 0;
RecBuffHalf = 0;
/* Call the Media layer start function for MIC2 channel */
if (HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)], \
(int32_t *)MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)], DEFAULT_AUDIO_IN_BUFFER_SIZE) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)], \
(int32_t *)MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)], DEFAULT_AUDIO_IN_BUFFER_SIZE) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RECORDING;
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Stop audio recording.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_Stop(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio in state */
else if (Audio_In_Ctx[Instance].State == AUDIO_IN_STATE_STOP)
{
/* Nothing to do */
}
else if ((Audio_In_Ctx[Instance].State != AUDIO_IN_STATE_RECORDING) &&
(Audio_In_Ctx[Instance].State != AUDIO_IN_STATE_PAUSE))
{
ret = BSP_ERROR_BUSY;
}
else
{
if (Instance == 2U)
{
/* Call the Media layer stop function */
if (HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)]) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)]) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
else
{
/* Call the Media layer stop function */
if (Audio_Drv->Stop(Audio_CompObj, CODEC_PDWN_SW) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else if (Instance == 0U)
{
if (HAL_SAI_DMAStop(&haudio_in_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else /* (Instance == 1U) */
{
if (HAL_I2S_DMAStop(&haudio_in_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_STOP;
}
/* Return BSP status */
return ret;
}
/**
* @brief Pause the audio file stream.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_Pause(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
if ((Instance == 0U) || (Instance == 1U))
{
/* Call the audio codec pause function */
if (Audio_Drv->Pause(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else if (Instance == 0U)
{
/* Pause DMA transfer of audio samples from the serial audio interface */
if (HAL_SAI_DMAPause(&haudio_in_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (HAL_I2S_DMAPause(&haudio_in_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
/* Workaround */
haudio_in_i2s.Instance->IFCR = 0x800;
}
}
}
else
{
/* Call the Media layer stop function */
if (HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)]) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
if (HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)]) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_PAUSE;
}
/* Return BSP status */
return ret;
}
/**
* @brief Resume the audio file stream.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_Resume(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
if ((Instance == 0U) || (Instance == 1U))
{
/* Call the audio codec pause function */
if (Audio_Drv->Resume(Audio_CompObj) < 0)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
else if (Instance == 0U)
{
/* Call Audio Codec Pause function */
if (HAL_SAI_DMAResume(&haudio_in_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
else
{
if (HAL_I2S_DMAResume(&haudio_in_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
else
{
/* Call the Media layer start function for MIC2/MIC1 channel */
if (HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)],
(int32_t *)MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)], DEFAULT_AUDIO_IN_BUFFER_SIZE) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)],
(int32_t *)MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)], DEFAULT_AUDIO_IN_BUFFER_SIZE) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
ret = BSP_ERROR_NONE;
}
}
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RECORDING;
}
/* Return BSP status */
return ret;
}
/**
* @brief Starts audio recording.
* @param Instance AUDIO IN Instance. It can be 2(DFSDM used)
* @param pBuf Main buffer pointer for the recorded data storing
* @param NbrOfBytes Size of the recorded buffer in bytes
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_RecordChannels(uint32_t Instance, uint8_t **pBuf, uint32_t NbrOfBytes)
{
uint16_t i;
int32_t ret = BSP_ERROR_NONE;
uint32_t mic_init[DFSDM_MIC_NUMBER] = {0};
uint32_t audio_in_digital_mic = AUDIO_IN_DEVICE_DIGITAL_MIC1, pbuf_index = 0;
uint32_t enabled_mic = 0;
if (Instance != 2U)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Get the number of activated microphones */
for (i = 0U; i < DFSDM_MIC_NUMBER; i++)
{
if ((Audio_In_Ctx[Instance].Device & audio_in_digital_mic) == audio_in_digital_mic)
{
enabled_mic++;
}
audio_in_digital_mic = audio_in_digital_mic << 1;
}
Audio_In_Ctx[Instance].pMultiBuff = pBuf;
Audio_In_Ctx[Instance].Size = NbrOfBytes;
Audio_In_Ctx[Instance].IsMultiBuff = 1;
audio_in_digital_mic = AUDIO_IN_DEVICE_DIGITAL_MIC_LAST;
for (i = 0U; i < DFSDM_MIC_NUMBER; i++)
{
if ((mic_init[POS_VAL(audio_in_digital_mic)] != 1U)
&& ((Audio_In_Ctx[Instance].Device & audio_in_digital_mic) == audio_in_digital_mic))
{
/* Call the Media layer start function for MICx channel */
if (HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_filter[POS_VAL(audio_in_digital_mic)],
(int32_t *)pBuf[enabled_mic - 1U - pbuf_index], NbrOfBytes) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else
{
mic_init[POS_VAL(audio_in_digital_mic)] = 1;
pbuf_index++;
}
}
audio_in_digital_mic = audio_in_digital_mic >> 1;
}
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RECORDING;
}
/* Return BSP status */
return ret;
}
/**
* @brief Stop audio recording.
* @param Instance AUDIO IN Instance. It can be 1(DFSDM used)
* @param Device Digital input device to be stopped
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_StopChannels(uint32_t Instance, uint32_t Device)
{
int32_t ret;
/* Stop selected devices */
ret = BSP_AUDIO_IN_PauseChannels(Instance, Device);
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_STOP;
}
/* Return BSP status */
return ret;
}
/**
* @brief Pause the audio file stream.
* @param Instance AUDIO IN Instance. It can be 1(DFSDM used)
* @param Device Digital mic to be paused
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_PauseChannels(uint32_t Instance, uint32_t Device)
{
uint32_t audio_in_digital_mic = AUDIO_IN_DEVICE_DIGITAL_MIC1;
uint32_t i;
int32_t ret = BSP_ERROR_NONE;
if ((Instance != 2U) || ((Device < AUDIO_IN_DEVICE_DIGITAL_MIC1) && (Device > AUDIO_IN_DEVICE_DIGITAL_MIC_LAST)))
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
for (i = 0; i < DFSDM_MIC_NUMBER; i++)
{
if ((Device & audio_in_digital_mic) == audio_in_digital_mic)
{
/* Call the Media layer stop function */
if (HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_filter[POS_VAL(audio_in_digital_mic)]) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
audio_in_digital_mic = audio_in_digital_mic << 1;
}
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_PAUSE;
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Resume the audio file stream
* @param Instance AUDIO IN Instance. It can be 1(DFSDM used)
* @param Device Digital mic to be resumed
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_ResumeChannels(uint32_t Instance, uint32_t Device)
{
int32_t ret = BSP_ERROR_NONE;
uint32_t audio_in_digital_mic = AUDIO_IN_DEVICE_DIGITAL_MIC_LAST;
uint32_t i;
if ((Instance != 2U) || ((Device < AUDIO_IN_DEVICE_DIGITAL_MIC1) && (Device > AUDIO_IN_DEVICE_DIGITAL_MIC_LAST)))
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
for (i = 0; i < DFSDM_MIC_NUMBER; i++)
{
if ((Device & audio_in_digital_mic) == audio_in_digital_mic)
{
/* Start selected device channel */
if (HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_filter[POS_VAL(audio_in_digital_mic)], \
(int32_t *)Audio_In_Ctx[Instance].pMultiBuff[POS_VAL(audio_in_digital_mic)], Audio_In_Ctx[Instance].Size) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
audio_in_digital_mic = audio_in_digital_mic >> 1;
}
if (ret == BSP_ERROR_NONE)
{
/* Update BSP AUDIO IN state */
Audio_In_Ctx[Instance].State = AUDIO_IN_STATE_RECORDING;
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Set Audio In device
* @param Instance AUDIO IN Instance. It can be 0 when SAI is used 1 when I2S is used or 2 if DFSDM is used
* @param Device The audio input device to be used
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_SetDevice(uint32_t Instance, uint32_t Device)
{
int32_t ret = BSP_ERROR_NONE;
uint32_t i;
BSP_AUDIO_Init_t audio_init;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_In_Ctx[Instance].State == AUDIO_IN_STATE_STOP)
{
if (Instance == 2U)
{
for (i = 0; i < DFSDM_MIC_NUMBER; i ++)
{
if (((Device >> i) & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1)
{
if (HAL_DFSDM_ChannelDeInit(&haudio_in_dfsdm_channel[i]) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
}
}
}
audio_init.Device = Device;
audio_init.ChannelsNbr = Audio_In_Ctx[Instance].ChannelsNbr;
audio_init.SampleRate = Audio_In_Ctx[Instance].SampleRate;
audio_init.BitsPerSample = Audio_In_Ctx[Instance].BitsPerSample;
audio_init.Volume = Audio_In_Ctx[Instance].Volume;
if (BSP_AUDIO_IN_Init(Instance, &audio_init) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_NO_INIT;
}
}
else
{
ret = BSP_ERROR_BUSY;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get Audio In device
* @param Instance AUDIO IN Instance. It can be 0 when SAI is used 1 when I2S is used or 2 if DFSDM is used
* @param Device The audio input device used
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_GetDevice(uint32_t Instance, uint32_t *Device)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Return audio Input Device */
*Device = Audio_In_Ctx[Instance].Device;
}
return ret;
}
/**
* @brief Set Audio In frequency
* @param Instance Audio IN instance
* @param SampleRate Input frequency to be set
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_SetSampleRate(uint32_t Instance, uint32_t SampleRate)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
/* Check audio in state */
else if (Audio_In_Ctx[Instance].State != AUDIO_IN_STATE_STOP)
{
ret = BSP_ERROR_BUSY;
}
/* Check if playback on instance 0 or 1 is on going and corresponding sample rate */
else if ((Audio_Out_Ctx[0].State != AUDIO_OUT_STATE_RESET) &&
(Audio_Out_Ctx[0].SampleRate != SampleRate) &&
(Audio_Out_Ctx[1].State != AUDIO_OUT_STATE_RESET) &&
(Audio_Out_Ctx[1].SampleRate != SampleRate))
{
ret = BSP_ERROR_FEATURE_NOT_SUPPORTED;
}
/* Check if sample rate is modified */
else if (Audio_In_Ctx[Instance].SampleRate == SampleRate)
{
/* Nothing to do */
}
else if (Instance == 0U)
{
/* Update SAI1 clock config */
haudio_in_sai.Init.AudioFrequency = SampleRate;
haudio_out_sai.Init.AudioFrequency = SampleRate;
if (MX_SAI1_ClockConfig(&haudio_in_sai, SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
/* Re-initialize SAI1 with new sample rate */
else if (HAL_SAI_Init(&haudio_in_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_Init(&haudio_out_sai) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Register SAI TC, HT and Error callbacks */
else if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_RX_COMPLETE_CB_ID, SAI_RxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_RX_HALFCOMPLETE_CB_ID, SAI_RxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_SAI_RegisterCallback(&haudio_in_sai, HAL_SAI_ERROR_CB_ID, SAI_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
/* Store new sample rate on audio in context */
else
{
Audio_In_Ctx[Instance].SampleRate = SampleRate;
}
}
else if (Instance == 1U)
{
/* Update I2S clock config */
haudio_in_i2s.Init.AudioFreq = SampleRate;
if (MX_I2S6_ClockConfig(&haudio_in_i2s, SampleRate) != HAL_OK)
{
ret = BSP_ERROR_CLOCK_FAILURE;
}
/* Re-initialize I2S with new sample rate */
else if (HAL_I2S_Init(&haudio_in_i2s) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#if (USE_HAL_I2S_REGISTER_CALLBACKS == 1)
/* Register I2S TC, HT and Error callbacks */
else if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_RX_COMPLETE_CB_ID, I2S_RxCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_RX_HALF_COMPLETE_CB_ID, I2S_RxHalfCpltCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
else if (HAL_I2S_RegisterCallback(&haudio_in_i2s, HAL_I2S_ERROR_CB_ID, I2S_ErrorCallback) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
#endif /* (USE_HAL_I2S_REGISTER_CALLBACKS == 1) */
/* Store new sample rate on audio in context */
else
{
Audio_In_Ctx[Instance].SampleRate = SampleRate;
}
}
else /* Instance = 2 */
{
uint32_t i;
BSP_AUDIO_Init_t audio_init;
for (i = 0; i < DFSDM_MIC_NUMBER; i ++)
{
if (((Audio_In_Ctx[Instance].Device >> i) & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1)
{
if (HAL_DFSDM_ChannelDeInit(&haudio_in_dfsdm_channel[i]) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
if (HAL_DFSDM_FilterDeInit(&haudio_in_dfsdm_filter[i]) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
}
}
audio_init.Device = Audio_In_Ctx[Instance].Device;
audio_init.ChannelsNbr = Audio_In_Ctx[Instance].ChannelsNbr;
audio_init.SampleRate = SampleRate;
audio_init.BitsPerSample = Audio_In_Ctx[Instance].BitsPerSample;
audio_init.Volume = Audio_In_Ctx[Instance].Volume;
if (BSP_AUDIO_IN_Init(Instance, &audio_init) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_NO_INIT;
}
}
/* Return BSP status */
return ret;
}
/**
* @brief Get Audio In frequency
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param SampleRate Audio Input frequency to be returned
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_GetSampleRate(uint32_t Instance, uint32_t *SampleRate)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Return audio in frequency */
*SampleRate = Audio_In_Ctx[Instance].SampleRate;
}
/* Return BSP status */
return ret;
}
/**
* @brief Set Audio In Resolution
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param BitsPerSample Input resolution to be set
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_SetBitsPerSample(uint32_t Instance, uint32_t BitsPerSample)
{
uint32_t i;
int32_t ret = BSP_ERROR_NONE;
BSP_AUDIO_Init_t audio_init;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else if (Audio_In_Ctx[Instance].State == AUDIO_IN_STATE_STOP)
{
if (Instance == 2U)
{
for (i = 0; i < DFSDM_MIC_NUMBER; i ++)
{
if (((Audio_In_Ctx[Instance].Device >> i) & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1)
{
if (HAL_DFSDM_ChannelDeInit(&haudio_in_dfsdm_channel[i]) != HAL_OK)
{
return BSP_ERROR_PERIPH_FAILURE;
}
}
}
}
audio_init.Device = Audio_In_Ctx[Instance].Device;
audio_init.ChannelsNbr = Audio_In_Ctx[Instance].ChannelsNbr;
audio_init.SampleRate = Audio_In_Ctx[Instance].SampleRate;
audio_init.BitsPerSample = BitsPerSample;
audio_init.Volume = Audio_In_Ctx[Instance].Volume;
if (BSP_AUDIO_IN_Init(Instance, &audio_init) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_NO_INIT;
}
}
else
{
ret = BSP_ERROR_BUSY;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get Audio In Resolution
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param BitsPerSample Input resolution to be returned
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_GetBitsPerSample(uint32_t Instance, uint32_t *BitsPerSample)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Return audio in resolution */
*BitsPerSample = Audio_In_Ctx[Instance].BitsPerSample;
}
return ret;
}
/**
* @brief Set Audio In Channel number
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param ChannelNbr Channel number to be used
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_SetChannelsNbr(uint32_t Instance, uint32_t ChannelNbr)
{
int32_t ret = BSP_ERROR_NONE;
if ((Instance >= AUDIO_IN_INSTANCES_NBR) || (ChannelNbr > 2U))
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Update AudioIn Context */
Audio_In_Ctx[Instance].ChannelsNbr = ChannelNbr;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get Audio In Channel number
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param ChannelNbr Channel number to be used
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_GetChannelsNbr(uint32_t Instance, uint32_t *ChannelNbr)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Channel number to be returned */
*ChannelNbr = Audio_In_Ctx[Instance].ChannelsNbr;
}
return ret;
}
/**
* @brief Set the current audio in volume level.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param Volume Volume level to be returned
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_SetVolume(uint32_t Instance, uint32_t Volume)
{
int32_t ret;
if ((Instance >= AUDIO_IN_INSTANCES_NBR) || (Volume > 100U))
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Feature not supported */
ret = BSP_ERROR_FEATURE_NOT_SUPPORTED;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get the current audio in volume level.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param Volume Volume level to be returned
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_GetVolume(uint32_t Instance, uint32_t *Volume)
{
int32_t ret;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Input Volume to be returned */
*Volume = 0U;
/* Feature not supported */
ret = BSP_ERROR_FEATURE_NOT_SUPPORTED;
}
/* Return BSP status */
return ret;
}
/**
* @brief Get Audio In device
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param State Audio Out state
* @retval BSP status
*/
int32_t BSP_AUDIO_IN_GetState(uint32_t Instance, uint32_t *State)
{
int32_t ret = BSP_ERROR_NONE;
if (Instance >= AUDIO_IN_INSTANCES_NBR)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Input State to be returned */
*State = Audio_In_Ctx[Instance].State;
}
return ret;
}
/**
* @brief This function handles Audio Out DMA interrupt requests.
* @param Instance Audio IN instance: 0 for SAI, 1 for I2S and 2 for DFSDM
* @param InputDevice Can be:
* - AUDIO_IN_DEVICE_ANALOG_MIC
* - AUDIO_IN_DEVICE_ANALOG_LINE1
* - AUDIO_IN_DEVICE_DIGITAL_MIC1
* - AUDIO_IN_DEVICE_DIGITAL_MIC2
* - AUDIO_IN_DEVICE_DIGITAL_MIC3
* - AUDIO_IN_DEVICE_DIGITAL_MIC4
* - AUDIO_IN_DEVICE_DIGITAL_MIC5
* @retval None
*/
void BSP_AUDIO_IN_IRQHandler(uint32_t Instance, uint32_t InputDevice)
{
if ((Instance == 0U) && ((InputDevice == AUDIO_IN_DEVICE_ANALOG_MIC)
|| (InputDevice == AUDIO_IN_DEVICE_ANALOG_LINE1))) /* SAI */
{
HAL_DMA_IRQHandler(haudio_in_sai.hdmarx);
}
else if ((Instance == 1U) && ((InputDevice == AUDIO_IN_DEVICE_ANALOG_MIC)
|| (InputDevice == AUDIO_IN_DEVICE_ANALOG_LINE1))) /* I2S */
{
HAL_DMA_IRQHandler(haudio_in_i2s.hdmarx);
}
else
{
HAL_DMA_IRQHandler(haudio_in_dfsdm_filter[POS_VAL(InputDevice)].hdmaReg);
}
}
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0) || !defined (USE_HAL_DFSDM_REGISTER_CALLBACKS)
/**
* @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;
static uint32_t DmaRecBuffCplt[DFSDM_MIC_NUMBER] = {0};
int32_t tmp;
if (Audio_In_Ctx[2].IsMultiBuff == 1U)
{
/* Call the record update function to get the second half */
BSP_AUDIO_IN_TransferComplete_CallBack(2);
}
else
{
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)])
{
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 1;
}
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)])
{
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 1;
}
if (DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] == 1U)
{
if (DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] == 1U)
{
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)][DEFAULT_AUDIO_IN_BUFFER_SIZE
/ 2U], ((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)][DEFAULT_AUDIO_IN_BUFFER_SIZE
/ 2U], ((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
for (index = (DEFAULT_AUDIO_IN_BUFFER_SIZE / 2U) ; index < DEFAULT_AUDIO_IN_BUFFER_SIZE; index++)
{
if (Audio_In_Ctx[2].ChannelsNbr == 2U)
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
tmp = MicRecBuff[1][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
else
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
RecBuffTrigger += 2U;
}
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_CleanDCache_by_Addr((uint32_t *)Audio_In_Ctx[2].pBuff, (int32_t)Audio_In_Ctx[2].Size * 2);
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 0;
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 0;
}
}
/* Call Half Transfer Complete callback */
if (RecBuffTrigger == (Audio_In_Ctx[2].Size / 4U))
{
if (RecBuffHalf == 0U)
{
RecBuffHalf = 1;
BSP_AUDIO_IN_HalfTransfer_CallBack(2);
}
}
/* Call Transfer Complete callback */
if (RecBuffTrigger == (Audio_In_Ctx[2].Size / 2U))
{
/* Reset Application Buffer Trigger */
RecBuffTrigger = 0;
RecBuffHalf = 0;
/* Call the record update function to get the next buffer to fill and its size (size is ignored) */
BSP_AUDIO_IN_TransferComplete_CallBack(2);
}
}
}
/**
* @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;
static uint32_t DmaRecHalfBuffCplt[DFSDM_MIC_NUMBER] = {0};
int32_t tmp;
if (Audio_In_Ctx[2].IsMultiBuff == 1U)
{
/* Call the record update function to get the first half */
BSP_AUDIO_IN_HalfTransfer_CallBack(2);
}
else
{
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)])
{
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 1;
}
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)])
{
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 1;
}
if (DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] == 1U)
{
if (DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] == 1U)
{
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)][0],
((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)][0],
((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
for (index = 0 ; index < (DEFAULT_AUDIO_IN_BUFFER_SIZE / 2U); index++)
{
if (Audio_In_Ctx[2].ChannelsNbr == 2U)
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
tmp = MicRecBuff[1][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
else
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
RecBuffTrigger += 2U;
}
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_CleanDCache_by_Addr((uint32_t *)Audio_In_Ctx[2].pBuff, ((int32_t)Audio_In_Ctx[2].Size * 2));
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 0;
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 0;
}
}
/* Call Half Transfer Complete callback */
if (RecBuffTrigger == (Audio_In_Ctx[2].Size / 4U))
{
if (RecBuffHalf == 0U)
{
RecBuffHalf = 1;
BSP_AUDIO_IN_HalfTransfer_CallBack(2);
}
}
/* Call Transfer Complete callback */
if (RecBuffTrigger == (Audio_In_Ctx[2].Size / 2U))
{
/* Reset Application Buffer Trigger */
RecBuffTrigger = 0;
RecBuffHalf = 0;
/* Call the record update function to get the next buffer to fill and its size (size is ignored) */
BSP_AUDIO_IN_TransferComplete_CallBack(2);
}
}
}
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 0) || !defined (USE_HAL_DFSDM_REGISTER_CALLBACKS) */
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 0) || !defined (USE_HAL_SAI_REGISTER_CALLBACKS)
/**
* @brief Half reception complete callback.
* @param hsai SAI handle.
* @retval None
*/
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Call the record update function to get the first half */
BSP_AUDIO_IN_HalfTransfer_CallBack(0);
}
/**
* @brief Reception complete callback.
* @param hsai SAI handle.
* @retval None
*/
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Call the record update function to get the second half */
BSP_AUDIO_IN_TransferComplete_CallBack(0);
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 0) || !defined (USE_HAL_SAI_REGISTER_CALLBACKS) */
/**
* @brief User callback when record buffer is filled.
* @retval None
*/
__weak void BSP_AUDIO_IN_TransferComplete_CallBack(uint32_t Instance)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(Instance);
/* This function should be implemented by the user application.
It is called into this driver when the current buffer is filled
to prepare the next buffer pointer and its size. */
}
/**
* @brief Manages the DMA Half Transfer complete event.
* @retval None
*/
__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(uint32_t Instance)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(Instance);
/* This function should be implemented by the user application.
It is called into this driver when the current buffer is filled
to prepare the next buffer pointer and its size. */
}
/**
* @brief Audio IN Error callback function.
* @retval None
*/
__weak void BSP_AUDIO_IN_Error_CallBack(uint32_t Instance)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(Instance);
/* This function is called when an Interrupt due to transfer error on or peripheral
error occurs. */
}
/**
* @}
*/
/** @defgroup STM32H7B3I_EVAL_AUDIO_IN_Private_Functions AUDIO IN Private Functions
* @{
*/
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/**
* @brief Half reception complete callback.
* @param hsai SAI handle.
* @retval None
*/
static void SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Call the record update function to get the first half */
BSP_AUDIO_IN_HalfTransfer_CallBack(0);
}
/**
* @brief Reception complete callback.
* @param hsai SAI handle.
* @retval None
*/
static void SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hsai);
/* Call the record update function to get the second half */
BSP_AUDIO_IN_TransferComplete_CallBack(0);
}
#endif /* (USE_HAL_SAI_REGISTER_CALLBACKS == 1) */
#if (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1)
/**
* @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
*/
static void DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
uint32_t index;
static uint32_t DmaRecBuffCplt[DFSDM_MIC_NUMBER] = {0};
int32_t tmp;
if (Audio_In_Ctx[2].IsMultiBuff == 1U)
{
/* Call the record update function to get the second half */
BSP_AUDIO_IN_TransferComplete_CallBack(2);
}
else
{
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)])
{
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 1;
}
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)])
{
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 1;
}
if (DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] == 1U)
{
if (DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] == 1U)
{
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)][DEFAULT_AUDIO_IN_BUFFER_SIZE
/ 2U], (int32_t)((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)][DEFAULT_AUDIO_IN_BUFFER_SIZE
/ 2U], (int32_t)((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
for (index = (DEFAULT_AUDIO_IN_BUFFER_SIZE / 2U) ; index < DEFAULT_AUDIO_IN_BUFFER_SIZE; index++)
{
if (Audio_In_Ctx[2].ChannelsNbr == 2U)
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
tmp = MicRecBuff[1][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
else
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
RecBuffTrigger += 2U;
}
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_CleanDCache_by_Addr((uint32_t *)Audio_In_Ctx[2].pBuff, (int32_t)Audio_In_Ctx[2].Size * 2);
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 0;
DmaRecBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 0;
}
}
/* Call Half Transfer Complete callback */
if (RecBuffTrigger == (Audio_In_Ctx[2].Size / 4U))
{
if (RecBuffHalf == 0U)
{
RecBuffHalf = 1;
BSP_AUDIO_IN_HalfTransfer_CallBack(2);
}
}
/* Call Transfer Complete callback */
if (RecBuffTrigger == Audio_In_Ctx[2].Size / 2U)
{
/* Reset Application Buffer Trigger */
RecBuffTrigger = 0;
RecBuffHalf = 0;
/* Call the record update function to get the next buffer to fill and its size (size is ignored) */
BSP_AUDIO_IN_TransferComplete_CallBack(2);
}
}
}
/**
* @brief Half regular conversion complete callback.
* @param hdfsdm_filter DFSDM filter handle.
* @retval None
*/
static void DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
{
uint32_t index;
static uint32_t DmaRecHalfBuffCplt[DFSDM_MIC_NUMBER] = {0};
int32_t tmp;
if (Audio_In_Ctx[2].IsMultiBuff == 1U)
{
/* Call the record update function to get the first half */
BSP_AUDIO_IN_HalfTransfer_CallBack(2);
}
else
{
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)])
{
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 1;
}
if (hdfsdm_filter == &haudio_in_dfsdm_filter[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)])
{
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 1;
}
if (DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] == 1U)
{
if (DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] == 1U)
{
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)][0],
(int32_t)((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
SCB_InvalidateDCache_by_Addr((uint32_t *)&MicRecBuff[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)][0],
(int32_t)((int32_t)DEFAULT_AUDIO_IN_BUFFER_SIZE / 2) * 4);
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
for (index = 0 ; index < (DEFAULT_AUDIO_IN_BUFFER_SIZE / 2U); index++)
{
if (Audio_In_Ctx[2].ChannelsNbr == 2U)
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
tmp = MicRecBuff[1][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
else
{
tmp = MicRecBuff[0][index] / 256;
tmp = SaturaLH(tmp, -32768, 32767);
Audio_In_Ctx[2].pBuff[RecBuffTrigger] = (uint16_t)(tmp);
Audio_In_Ctx[2].pBuff[RecBuffTrigger + 1U] = (uint16_t)(tmp);
}
RecBuffTrigger += 2U;
}
#if (USE_BSP_CPU_CACHE_MAINTENANCE == 1)
SCB_CleanDCache_by_Addr((uint32_t *)Audio_In_Ctx[2].pBuff, (int32_t)Audio_In_Ctx[2].Size * 2);
#endif /* USE_BSP_CPU_CACHE_MAINTENANCE */
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] = 0;
DmaRecHalfBuffCplt[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] = 0;
}
}
/* Call Half Transfer Complete callback */
if (RecBuffTrigger == (Audio_In_Ctx[2].Size / 4U))
{
if (RecBuffHalf == 0U)
{
RecBuffHalf = 1;
BSP_AUDIO_IN_HalfTransfer_CallBack(2);
}
}
/* Call Transfer Complete callback */
if (RecBuffTrigger == Audio_In_Ctx[2].Size / 2U)
{
/* Reset Application Buffer Trigger */
RecBuffTrigger = 0;
RecBuffHalf = 0;
/* Call the record update function to get the next buffer to fill and its size (size is ignored) */
BSP_AUDIO_IN_TransferComplete_CallBack(2);
}
}
}
#endif /* (USE_HAL_DFSDM_REGISTER_CALLBACKS == 1) */
/**
* @brief Un-reset CS42L51.
* @retval BSP status.
*/
static int32_t CS42L51_PowerUp(void)
{
int32_t ret = BSP_ERROR_NONE;
#if (USE_BSP_IO_CLASS > 0)
BSP_IO_Init_t IO_Init;
/* Initialize the BSP IO driver and configure the CS42L51 reset pin */
IO_Init.Pin = IO_PIN_3;
IO_Init.Mode = IO_MODE_OUTPUT_PP;
IO_Init.Pull = IO_PULLDOWN;
if (BSP_IO_Init(0, &IO_Init) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_BUS_FAILURE;
}
else if (BSP_IO_WritePin(0, IO_PIN_3, IO_PIN_SET) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_BUS_FAILURE;
}
else
{
/* Wait 1ms according CS42L51 datasheet */
HAL_Delay(1);
}
#endif /* USE_BSP_IO_CLASS > 0 */
return ret;
}
/**
* @brief Reset CS42L51.
* @retval BSP status.
*/
static int32_t CS42L51_PowerDown(void)
{
int32_t ret;
#if (USE_BSP_IO_CLASS > 0)
/* Reset the CS42L51 */
ret = BSP_IO_WritePin(0, IO_PIN_15, IO_PIN_RESET);
#else /* USE_BSP_IO_CLASS == 1 */
ret = BSP_ERROR_NONE;
#endif /* USE_BSP_IO_CLASS > 0 */
return ret;
}
/**
* @brief Initialize the DFSDM channel MSP.
* @param hDfsdmChannel DFSDM Channel handle
* @retval None
*/
static void DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hDfsdmChannel)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* Prevent unused argument(s) compilation warning */
UNUSED(hDfsdmChannel);
/* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN pins ------------------*/
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
if (Audio_In_Ctx[2].Device == AUDIO_IN_DEVICE_DIGITAL_MIC5)
{
AUDIO_DFSDM2_CLK_ENABLE();
AUDIO_DFSDM2_CKOUT_GPIO_CLK_ENABLE();
AUDIO_DFSDMx_DATIN_MIC5_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = AUDIO_DFSDM2_CKOUT_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDM2_CKOUT_AF;
HAL_GPIO_Init(AUDIO_DFSDM2_CKOUT_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC5_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DATIN_MIC5_AF;
HAL_GPIO_Init(AUDIO_DFSDMx_DATIN_MIC5_GPIO_PORT, &GPIO_InitStruct);
}
else
{
/* Enable DFSDM clock */
AUDIO_DFSDM1_CLK_ENABLE();
/* Enable GPIO clock */
AUDIO_DFSDM1_CKOUT_GPIO_CLK_ENABLE();
AUDIO_DFSDMx_DATIN_MIC1_GPIO_CLK_ENABLE();
AUDIO_DFSDMx_DATIN_MIC2_GPIO_CLK_ENABLE();
AUDIO_DFSDMx_DATIN_MIC3_GPIO_CLK_ENABLE();
AUDIO_DFSDMx_DATIN_MIC4_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = AUDIO_DFSDM1_CKOUT_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDM1_CKOUT_AF;
HAL_GPIO_Init(AUDIO_DFSDM1_CKOUT_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC1_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DATIN_MIC1_AF;
HAL_GPIO_Init(AUDIO_DFSDMx_DATIN_MIC1_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC2_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DATIN_MIC2_AF;
HAL_GPIO_Init(AUDIO_DFSDMx_DATIN_MIC2_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC3_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DATIN_MIC3_AF;
HAL_GPIO_Init(AUDIO_DFSDMx_DATIN_MIC3_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC4_PIN;
GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DATIN_MIC4_AF;
HAL_GPIO_Init(AUDIO_DFSDMx_DATIN_MIC4_GPIO_PORT, &GPIO_InitStruct);
}
}
/**
* @brief DeInitialize the DFSDM channel MSP.
* @param hDfsdmChannel DFSDM Channel handle
* @retval None
*/
static void DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hDfsdmChannel)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* Prevent unused argument(s) compilation warning */
UNUSED(hDfsdmChannel);
/* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN pins ------------------*/
if (Audio_In_Ctx[2].Device == AUDIO_IN_DEVICE_DIGITAL_MIC5)
{
GPIO_InitStruct.Pin = AUDIO_DFSDM2_CKOUT_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDM2_CKOUT_GPIO_PORT, GPIO_InitStruct.Pin);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC5_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDMx_DATIN_MIC5_GPIO_PORT, GPIO_InitStruct.Pin);
}
else
{
GPIO_InitStruct.Pin = AUDIO_DFSDM1_CKOUT_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDM1_CKOUT_GPIO_PORT, GPIO_InitStruct.Pin);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC1_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDMx_DATIN_MIC1_GPIO_PORT, GPIO_InitStruct.Pin);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC2_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDMx_DATIN_MIC2_GPIO_PORT, GPIO_InitStruct.Pin);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC3_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDMx_DATIN_MIC3_GPIO_PORT, GPIO_InitStruct.Pin);
GPIO_InitStruct.Pin = AUDIO_DFSDMx_DATIN_MIC4_PIN;
HAL_GPIO_DeInit(AUDIO_DFSDMx_DATIN_MIC4_GPIO_PORT, GPIO_InitStruct.Pin);
}
}
/**
* @brief Initialize the DFSDM filter MSP.
* @param hDfsdmFilter DFSDM Filter handle
* @retval None
*/
static void DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hDfsdmFilter)
{
uint32_t i, mic_num, mic_init[DFSDM_MIC_NUMBER] = {0};
IRQn_Type AUDIO_DFSDM_DMAx_MIC_IRQHandler[DFSDM_MIC_NUMBER] = {AUDIO_DFSDMx_DMAx_MIC1_IRQ, AUDIO_DFSDMx_DMAx_MIC2_IRQ, AUDIO_DFSDMx_DMAx_MIC3_IRQ, AUDIO_DFSDMx_DMAx_MIC4_IRQ, AUDIO_DFSDMx_DMAx_MIC5_IRQ};
DMA_Stream_TypeDef *AUDIO_DFSDMx_DMAx_MIC_STREAM[DFSDM_MIC_NUMBER] = {AUDIO_DFSDMx_DMAx_MIC1_STREAM, AUDIO_DFSDMx_DMAx_MIC2_STREAM, AUDIO_DFSDMx_DMAx_MIC3_STREAM, AUDIO_DFSDMx_DMAx_MIC4_STREAM, NULL};
uint32_t AUDIO_DFSDMx_DMAx_MIC_REQUEST[DFSDM_MIC_NUMBER] = {AUDIO_DFSDMx_DMAx_MIC1_REQUEST, AUDIO_DFSDMx_DMAx_MIC2_REQUEST, AUDIO_DFSDMx_DMAx_MIC3_REQUEST, AUDIO_DFSDMx_DMAx_MIC4_REQUEST, AUDIO_DFSDMx_DMAx_MIC5_REQUEST};
/* Prevent unused argument(s) compilation warning */
UNUSED(hDfsdmFilter);
/* Enable DFSDM clock */
AUDIO_DFSDM1_CLK_ENABLE();
AUDIO_DFSDM2_CLK_ENABLE();
/* Enable the DMA clock */
AUDIO_DFSDM1_DMAx_CLK_ENABLE();
AUDIO_DFSDM2_DMAx_CLK_ENABLE();
for (i = 0; i < DFSDM_MIC_NUMBER; i++)
{
if ((mic_init[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC1)] != 1U)
&& ((Audio_In_Ctx[2].Device & AUDIO_IN_DEVICE_DIGITAL_MIC1) == AUDIO_IN_DEVICE_DIGITAL_MIC1))
{
mic_num = 0U;
mic_init[mic_num] = 1;
}
else if ((mic_init[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC2)] != 1U)
&& ((Audio_In_Ctx[2].Device & AUDIO_IN_DEVICE_DIGITAL_MIC2) == AUDIO_IN_DEVICE_DIGITAL_MIC2))
{
mic_num = 1U;
mic_init[mic_num] = 1;
}
else if ((mic_init[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC3)] != 1U)
&& ((Audio_In_Ctx[2].Device & AUDIO_IN_DEVICE_DIGITAL_MIC3) == AUDIO_IN_DEVICE_DIGITAL_MIC3))
{
mic_num = 2U;
mic_init[mic_num] = 1;
}
else if ((mic_init[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC4)] != 1U)
&& ((Audio_In_Ctx[2].Device & AUDIO_IN_DEVICE_DIGITAL_MIC4) == AUDIO_IN_DEVICE_DIGITAL_MIC4))
{
mic_num = 3U;
mic_init[mic_num] = 1;
}
else if ((mic_init[POS_VAL(AUDIO_IN_DEVICE_DIGITAL_MIC5)] != 1U)
&& ((Audio_In_Ctx[2].Device & AUDIO_IN_DEVICE_DIGITAL_MIC5) == AUDIO_IN_DEVICE_DIGITAL_MIC5))
{
mic_num = 4U;
mic_init[mic_num] = 1;
}
else
{
break;
}
/* Configure the hDmaDfsdm[i] handle parameters */
hDmaDfsdm[mic_num].Init.Request = AUDIO_DFSDMx_DMAx_MIC_REQUEST[mic_num];
hDmaDfsdm[mic_num].Instance = AUDIO_DFSDMx_DMAx_MIC_STREAM[mic_num];
if (mic_num == 4U)
{
hDmaDfsdm[mic_num].Instance = AUDIO_DFSDMx_DMAx_MIC5_STREAM;
}
hDmaDfsdm[mic_num].Init.Direction = DMA_PERIPH_TO_MEMORY;
hDmaDfsdm[mic_num].Init.PeriphInc = DMA_PINC_DISABLE;
hDmaDfsdm[mic_num].Init.MemInc = DMA_MINC_ENABLE;
hDmaDfsdm[mic_num].Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hDmaDfsdm[mic_num].Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hDmaDfsdm[mic_num].Init.Mode = DMA_CIRCULAR;
hDmaDfsdm[mic_num].Init.Priority = DMA_PRIORITY_HIGH;
hDmaDfsdm[mic_num].Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hDmaDfsdm[mic_num].Init.MemBurst = DMA_MBURST_SINGLE;
hDmaDfsdm[mic_num].Init.PeriphBurst = DMA_PBURST_SINGLE;
hDmaDfsdm[mic_num].State = HAL_DMA_STATE_RESET;
/* Associate the DMA handle */
__HAL_LINKDMA(&haudio_in_dfsdm_filter[mic_num], hdmaReg, hDmaDfsdm[mic_num]);
/* Reset DMA handle state */
__HAL_DMA_RESET_HANDLE_STATE(&hDmaDfsdm[mic_num]);
/* Configure the DMA Channel */
(void)HAL_DMA_Init(&hDmaDfsdm[mic_num]);
/* DMA IRQ Channel configuration */
HAL_NVIC_SetPriority(AUDIO_DFSDM_DMAx_MIC_IRQHandler[mic_num], BSP_AUDIO_IN_IT_PRIORITY, 0);
HAL_NVIC_EnableIRQ(AUDIO_DFSDM_DMAx_MIC_IRQHandler[mic_num]);
}
}
/**
* @brief DeInitialize the DFSDM filter MSP.
* @param hDfsdmFilter DFSDM Filter handle
* @retval None
*/
static void DFSDM_FilterMspDeInit(DFSDM_Filter_HandleTypeDef *hDfsdmFilter)
{
uint32_t i;
/* Prevent unused argument(s) compilation warning */
UNUSED(hDfsdmFilter);
/* Configure the DMA Channel */
for (i = 0; i < DFSDM_MIC_NUMBER; i++)
{
if (hDmaDfsdm[i].Instance != NULL)
{
(void)HAL_DMA_DeInit(&hDmaDfsdm[i]);
}
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/