STM32L476G-Discovery BSP User Manual: stm32l476g_discovery_audio.c Source File

STM32L476G-Discovery BSP

stm32l476g_discovery_audio.c
Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    stm32l476g_discovery_audio.c
00004   * @author  MCD Application Team
00005   * @version $VERSION$
00006   * @date    $DATE$
00007   * @brief   This file provides a set of functions needed to manage the 
00008   *          Audio driver for the STM32L476G-Discovery board.
00009   ******************************************************************************
00010   * @attention
00011   *
00012   * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
00013   *
00014   * Redistribution and use in source and binary forms, with or without modification,
00015   * are permitted provided that the following conditions are met:
00016   *   1. Redistributions of source code must retain the above copyright notice,
00017   *      this list of conditions and the following disclaimer.
00018   *   2. Redistributions in binary form must reproduce the above copyright notice,
00019   *      this list of conditions and the following disclaimer in the documentation
00020   *      and/or other materials provided with the distribution.
00021   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00022   *      may be used to endorse or promote products derived from this software
00023   *      without specific prior written permission.
00024   *
00025   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00026   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00028   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00029   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00030   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00031   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00032   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00033   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035   *
00036   ******************************************************************************
00037   */
00038 
00039 /*==============================================================================
00040                                  User NOTES
00041                                  
00042 1. How To use this driver:
00043 --------------------------
00044    + This driver supports STM32L4xx devices on STM32L476G-Discovery (MB1184) Discovery boards.
00045         a) to play an audio file (all functions names start by BSP_AUDIO_OUT_xxx)
00046         b) to record an audio file through MP34DT01TR, ST MEMS (all functions names start by BSP_AUDIO_IN_xxx)
00047 
00048 a) PLAY A FILE:
00049 ==============
00050    + Call the function BSP_AUDIO_OUT_Init(
00051                                     OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, 
00052                                                   OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH)
00053                                     Volume      : Initial volume to be set (0 is min (mute), 100 is max (100%)
00054                                     AudioFreq   : Audio frequency in Hz (8000, 16000, 22500, 32000...)
00055                                                   this parameter is relative to the audio file/stream type.
00056                                    )
00057       This function configures all the hardware required for the audio application (codec, I2C, SAI, 
00058       GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK.
00059       If the returned value is different from AUDIO_OK or the function is stuck then the communication with
00060       the audio codec has failed.
00061       - OUTPUT_DEVICE_SPEAKER  : only speaker will be set as output for the audio stream.
00062       - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream.
00063       - OUTPUT_DEVICE_BOTH     : both Speaker and Headphone are used as outputs for the audio stream
00064                                  at the same time.
00065 
00066    + Call the function BSP_AUDIO_OUT_RegisterCallbacks to register user callbacks
00067      required to manage audio data streaming towards the audio codec (ErrorCallback(),
00068      HalfTransfer_CallBack() and TransferComplete_CallBack()).
00069 
00070    + Call the function BSP_AUDIO_OUT_Play() to start audio playback (for the first time).
00071    + Call the function BSP_AUDIO_OUT_Pause() to pause audio playabck   
00072    + Call the function BSP_AUDIO_OUT_Resume() to resume audio playback.
00073        Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called
00074           for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case).
00075        Note. This function should be called only when the audio file is played or paused (not stopped).
00076    + Call the function BSP_AUDIO_OUT_Stop() to stop audio playback.
00077    + To modify the volume level, the sampling frequency, the device output mode, 
00078       the mute status or the audio configuration or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), 
00079       AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetOutputMode(), BSP_AUDIO_OUT_SetMute()and 
00080       BSP_AUDIO_OUT_ChangeAudioConfig().
00081  
00082 Driver architecture:
00083 --------------------
00084    + This driver provides the audio layer high level API: it consists in functions
00085      exported in the stm32l476g_discovery_audio.h file (e.g. BSP_AUDIO_OUT_Init(),
00086      BSP_AUDIO_OUT_Play(), ...).
00087    + This driver also includes the Media Access Layer (MAL): it consists in 
00088      functions allowing to access setup the audio devices. These functions 
00089      are  included as local functions into the stm32l476g_discovery_audio.c file
00090      (e.g. AUDIO_SAIx_Init()).
00091 
00092 Known Limitations:
00093 ------------------
00094    1- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some
00095       user interrupt routines (in this case, interrupts could be disabled just before the start of 
00096       communication then re-enabled when it is over). Note that this communication is only done at
00097       the configuration phase (BSP_AUDIO_OUT_Init() or BSP_AUDIO_OUT_Stop()) and when Volume control modification is 
00098       performed (BSP_AUDIO_OUT_SetVolume() or BSP_AUDIO_OUT_SetMute()or BSP_AUDIO_OUT_SetOutputMode()). 
00099       When the audio data is played, no communication is required with the audio codec.
00100    2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, 
00101       File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.
00102    3- Supports only 16-bits audio data size.
00103 
00104 b) RECORD A FILE:
00105 ================
00106    + Call the function BSP_AUDIO_IN_Init(
00107                                     AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...)
00108                                     )
00109       This function configures all the hardware required for the audio application (DFSDM, 
00110       GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if the 
00111       configuration completes successfully.
00112 
00113    + Call the function BSP_AUDIO_IN_RegisterCallbacks to register user callbacks
00114      used to stream audio data toward the record buffer (ErrorCallback(),
00115      HalfTransfer_CallBack() and TransferComplete_CallBack()).
00116 
00117    + Call the function BSP_AUDIO_IN_Record(
00118                             pbuf Main buffer pointer for the recorded data storing  
00119                             size Current size of the recorded buffer
00120                             )
00121       to start recording from the microphone.
00122 
00123    + Call the function AUDIO_IN_STOP() to stop recording 
00124 ==============================================================================*/
00125 
00126 /* Includes ------------------------------------------------------------------*/
00127 #include <string.h>
00128 #include "stm32l476g_discovery_audio.h"
00129 
00130 /** @addtogroup BSP
00131   * @{
00132   */
00133 
00134 /** @addtogroup STM32L476G_DISCOVERY
00135   * @{
00136   */
00137 
00138 /** @defgroup STM32L476G_DISCOVERY_AUDIO STM32L476G-DISCOVERY AUDIO
00139   * @brief This file includes the low layer driver for cs43l22 Audio Codec
00140   *        available on STM32L476G-Discovery board(MB1184).
00141   * @{
00142   */ 
00143 
00144 /* Private typedef -----------------------------------------------------------*/
00145 /** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Types Private Types
00146   * @{
00147   */
00148 typedef struct
00149 {
00150   AUDIO_DrvTypeDef *    AudioDrv;            /* Audio codec driver */
00151   Audio_CallbackTypeDef CbError;            /* pointer to the callback function invoked when ... */
00152   Audio_CallbackTypeDef CbHalfTransfer;     /* pointer to the callback function invoked when ... */
00153   Audio_CallbackTypeDef CbTransferComplete; /* pointer to the callback function invoked when ... */
00154 } AUDIO_OUT_TypeDef;
00155 
00156 typedef struct
00157 {
00158   DFSDM_Channel_HandleTypeDef hDfsdmLeftChannel;  /* DFSDM channel handle used for left channel */
00159   DMA_HandleTypeDef           hDmaDfsdmLeft;      /* DMA handle used for DFSDM regular conversions on left channel */
00160   int32_t *                   LeftRecBuff;        /* Buffers for left samples */
00161   uint32_t                Frequency;        /* Record Frequency */
00162   uint32_t                BitResolution;    /* Record bit resolution */
00163   uint32_t                ChannelNbr;       /* Record Channel Number */
00164   uint16_t *              pRecBuf;          /* Pointer to record user buffer */
00165   uint32_t                RecSize;          /* Size to record in mono, double size to record in stereo */
00166   Audio_CallbackTypeDef       CbError;            /* pointer to the callback function invoked when a DMA transfer fails */
00167   Audio_CallbackTypeDef       CbHalfTransfer;     /* pointer to the callback function invoked when half of the DMA transfer is completed */
00168   Audio_CallbackTypeDef       CbTransferComplete; /* pointer to the callback function invoked when the DMA transfer is completed */
00169 } AUDIO_IN_TypeDef;
00170 
00171 /**
00172   * @}
00173   */
00174 
00175 /* Private defines ------------------------------------------------------------*/
00176 /** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Constants Private Constants
00177   * @{
00178   */
00179 /**
00180   * @}
00181   */
00182 
00183 /* Private macros ------------------------------------------------------------*/
00184 /** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Macros Private Macros
00185   * @{
00186   */
00187 /*### PLAY ###*/
00188 /* SCK(kHz) = SAI_CK_x/(SAIClockDivider*2*256) */
00189 #define SAIClockDivider(__FREQUENCY__) \
00190         (__FREQUENCY__ == AUDIO_FREQUENCY_8K)  ? 12 \
00191       : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 2 \
00192       : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 6 \
00193       : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 1 \
00194       : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 3 \
00195       : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \
00196       : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 2 : 1  \
00197 
00198 /*### RECORD ###*/
00199 #define DFSDMOverSampling(__FREQUENCY__) \
00200         (__FREQUENCY__ == AUDIO_FREQUENCY_8K)  ? 256 \
00201       : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 256 \
00202       : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 128 \
00203       : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 128 \
00204       : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 64 \
00205       : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 64  \
00206       : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 32 : 16  \
00207 
00208 #define DFSDMClockDivider(__FREQUENCY__) \
00209         (__FREQUENCY__ == AUDIO_FREQUENCY_8K)  ? 24 \
00210       : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 4 \
00211       : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 24 \
00212       : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \
00213       : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 24 \
00214       : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 4  \
00215       : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 32 : 32  \
00216 
00217 #define DFSDMFilterOrder(__FREQUENCY__) \
00218         (__FREQUENCY__ == AUDIO_FREQUENCY_8K)  ? DFSDM_FILTER_SINC3_ORDER \
00219       : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? DFSDM_FILTER_SINC3_ORDER \
00220       : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? DFSDM_FILTER_SINC3_ORDER \
00221       : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? DFSDM_FILTER_SINC3_ORDER \
00222       : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? DFSDM_FILTER_SINC4_ORDER \
00223       : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? DFSDM_FILTER_SINC4_ORDER  \
00224       : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC4_ORDER : DFSDM_FILTER_SINC5_ORDER  \
00225 
00226 #define DFSDMRightBitShift(__FREQUENCY__) \
00227         (__FREQUENCY__ == AUDIO_FREQUENCY_8K)  ? 2 \
00228       : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 3 \
00229       : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 2 \
00230       : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 0 \
00231       : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 3 \
00232       : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 3  \
00233       : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 7 : 0  \
00234 
00235 /* Saturate the record PCM sample */
00236 #define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
00237 
00238 /**
00239   * @}
00240   */ 
00241   
00242 /* Private variables ---------------------------------------------------------*/
00243 /** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Variables Private Variables
00244   * @{
00245   */
00246 /* Audio output context information */
00247 static AUDIO_OUT_TypeDef hAudioOut;
00248 
00249 /* Audio input context information */
00250 static AUDIO_IN_TypeDef hAudioIn;
00251 
00252 /* SAI DMA handle */
00253 static DMA_HandleTypeDef hDmaSai;
00254 /**
00255   * @}
00256   */
00257 
00258 /* Exported variables ---------------------------------------------------------*/
00259 /** @defgroup STM32L476G_DISCOVERY_AUDIO_Exported_Variables Exported Variables
00260   * @{
00261   */
00262 /* SAIx handle */
00263 SAI_HandleTypeDef               BSP_AUDIO_hSai;
00264     
00265 /* DFSDM filter handle */
00266 DFSDM_Filter_HandleTypeDef      BSP_AUDIO_hDfsdmLeftFilter;
00267 /**
00268   * @}
00269   */
00270 
00271 /* Private function prototypes -----------------------------------------------*/
00272 /** @defgroup STM32L476G_DISCOVERY_AUDIO_Private_Functions Private Functions
00273   * @{
00274   */
00275 static void    AUDIO_CODEC_Reset(void);
00276 static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq);
00277 static uint8_t AUDIO_SAIx_DeInit(void);
00278 static uint8_t AUDIO_DFSDMx_Init(uint32_t AudioFreq);
00279 static uint8_t AUDIO_DFSDMx_DeInit(void);
00280 static uint8_t AUDIO_SAIPLLConfig(uint32_t AudioFreq);
00281 /**
00282   * @}
00283   */
00284 
00285 /* Exported functions --------------------------------------------------------*/
00286 /** @addtogroup STM32L476G_DISCOVERY_AUDIO_Exported_Functions
00287   * @{
00288   */ 
00289 
00290 /**
00291   * @brief  Configures the audio codec related peripherals.
00292   * @param  OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
00293   *                       or OUTPUT_DEVICE_BOTH.
00294   * @param  Volume: Initial volume level (from 0 (Mute) to 100 (Max))
00295   * @param  AudioFreq: Audio frequency used to play the audio stream.ion.  
00296   * @retval BSP AUDIO status
00297   * @note   The SAI PLL input clock must be configure in the user application.
00298   *         The SAI PLL configuration done within this function assumes that
00299   *         the SAI PLL input clock runs at 8 MHz.
00300   */
00301 uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, 
00302                            uint8_t Volume,
00303                            uint32_t AudioFreq)
00304 { 
00305   /* Initialize the audio output context */
00306   hAudioOut.AudioDrv           = &cs43l22_drv; 
00307   hAudioOut.CbError            = (Audio_CallbackTypeDef)NULL; 
00308   hAudioOut.CbHalfTransfer     = (Audio_CallbackTypeDef)NULL; 
00309   hAudioOut.CbTransferComplete = (Audio_CallbackTypeDef)NULL;
00310   
00311   /* Configure the SAI PLL according to the requested audio frequency */
00312   if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
00313   {
00314     return AUDIO_ERROR;
00315   }
00316         
00317   /* SAI data transfer preparation: prepare the Media to be used for the audio
00318      transfer from memory to SAI peripheral. */
00319   if (AUDIO_SAIx_Init(AudioFreq) != AUDIO_OK)
00320   {
00321     return AUDIO_ERROR;
00322   }
00323 
00324   /* Retieve audio codec identifier */
00325   if (cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS) != CS43L22_ID)
00326   {
00327     return AUDIO_ERROR;
00328   }
00329   
00330   /* Reset the audio codec Registers */
00331   AUDIO_CODEC_Reset();
00332   
00333   /* Initialize the audio codec internal registers */
00334   if (hAudioOut.AudioDrv->Init(AUDIO_I2C_ADDRESS, 
00335                                OutputDevice, 
00336                                Volume, 
00337                                AudioFreq) != 0)
00338   {
00339     return AUDIO_ERROR;
00340   }
00341   
00342   /* Set the requested volume */
00343   BSP_AUDIO_OUT_SetVolume(Volume);
00344 
00345   return AUDIO_OK;
00346 }
00347   
00348 /**
00349   * @brief  De-Initializes audio codec related peripherals
00350   * @retval BSP AUDIO status
00351   
00352   */
00353 uint8_t BSP_AUDIO_OUT_DeInit(void)
00354 {
00355   /* De-initializes the Audio Codec audio interface */
00356   if (AUDIO_SAIx_DeInit() != AUDIO_OK)
00357   {  
00358     return AUDIO_ERROR;
00359   }
00360 
00361   /* DeInit Audio component interface */
00362   hAudioOut.AudioDrv->DeInit();
00363   
00364   /* Reset the audio output context */
00365   memset(&hAudioOut, 0, sizeof(hAudioOut));
00366   
00367   return AUDIO_OK;
00368 }
00369 
00370 /**
00371   * @brief  Starts playing audio stream from a data buffer for a determined size. 
00372   * @param  pData: pointer on PCM samples buffer 
00373   * @param  Size: Number of audio data BYTES.
00374   * @retval BSP AUDIO status
00375   */
00376 uint8_t BSP_AUDIO_OUT_Play(uint16_t* pData, uint32_t Size)
00377 {
00378   /* Call the audio Codec Play function */
00379   if (hAudioOut.AudioDrv->Play(AUDIO_I2C_ADDRESS, pData, Size) != 0)
00380   {  
00381     return AUDIO_ERROR;
00382   }
00383   
00384   /* Initiate a DMA transfer of PCM samples towards the serial audio interface */  
00385   if (HAL_SAI_Transmit_DMA(&BSP_AUDIO_hSai, (uint8_t *)pData, DMA_MAX(Size))!= HAL_OK)
00386   {
00387     return AUDIO_ERROR;
00388   }
00389         
00390     return AUDIO_OK;
00391   }
00392 
00393 /**
00394   * @brief  Sends n-Bytes on the SAI interface.
00395   * @param  pData: pointer on PCM samples buffer 
00396   * @param  Size: number of data to be written
00397   * @retval BSP AUDIO status
00398   */
00399 uint8_t BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
00400 {
00401   /* Initiate a DMA transfer of PCM samples towards the serial audio interface */  
00402   if (HAL_SAI_Transmit_DMA(&BSP_AUDIO_hSai, (uint8_t *)pData, Size)!= HAL_OK)
00403   {
00404     return AUDIO_ERROR;
00405   }
00406   
00407   return AUDIO_OK;
00408 }
00409 
00410 /**
00411   * @brief  This function Pauses the audio file stream. In case
00412   *         of using DMA, the DMA Pause feature is used.
00413   * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
00414   *       BSP_AUDIO_OUT_Resume() function should be called for resume
00415   *       (use of BSP_AUDIO_OUT_Play() function for resume could lead 
00416   *       to unexpected behavior).
00417   * @retval BSP AUDIO status
00418   */
00419 uint8_t BSP_AUDIO_OUT_Pause(void)
00420 {
00421   /* Call the Audio Codec Pause function */
00422   if (hAudioOut.AudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0)
00423   {
00424     return AUDIO_ERROR;
00425   }
00426   
00427   /* Pause DMA transfer of PCM samples towards the serial audio interface */  
00428   if (HAL_SAI_DMAPause(&BSP_AUDIO_hSai)!= HAL_OK)
00429   {
00430     return AUDIO_ERROR;
00431   }
00432   
00433   return AUDIO_OK;
00434 }
00435 
00436 /**
00437   * @brief  This function  Resumes the audio file stream.  
00438   * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
00439   *       BSP_AUDIO_OUT_Resume() function should be called for resume
00440   *       (use of BSP_AUDIO_OUT_Play() function for resume could lead to 
00441   *       unexpected behavior).
00442   * @retval BSP AUDIO status
00443   */
00444 uint8_t BSP_AUDIO_OUT_Resume(void)
00445 {    
00446   /* Call the Audio Codec Resume function */
00447   if (hAudioOut.AudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0)
00448   {
00449     return AUDIO_ERROR;
00450   }
00451 
00452   /* Resume DMA transfer of PCM samples towards the serial audio interface */  
00453   if (HAL_SAI_DMAResume(&BSP_AUDIO_hSai)!= HAL_OK)
00454   {
00455     return AUDIO_ERROR;
00456   }
00457   
00458   return AUDIO_OK;
00459 }
00460 
00461 /**
00462   * @brief  Stops audio playing and Power down the Audio Codec. 
00463   * @param  Option: could be one of the following parameters 
00464   *           - CODEC_PDWN_SW: for software power off (by writing registers). 
00465   *                            Then no need to reconfigure the Codec after power on.
00466   *           - CODEC_PDWN_HW: completely shut down the codec (physically). 
00467   *                            Then need to reconfigure the Codec after power on.  
00468   * @retval BSP AUDIO status
00469   */
00470 uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
00471 {
00472   /* Stop DMA transfer of PCM samples towards the serial audio interface */  
00473   if (HAL_SAI_DMAStop(&BSP_AUDIO_hSai)!= HAL_OK)
00474   {
00475     return AUDIO_ERROR;
00476   }
00477   
00478   /* Call Audio Codec Stop function */
00479   if (hAudioOut.AudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
00480   {
00481     return AUDIO_ERROR;
00482   }
00483   
00484   if(Option == CODEC_PDWN_HW)
00485   { 
00486     /* Wait at least 100us */
00487     HAL_Delay(1);
00488   }
00489   
00490   return AUDIO_OK;
00491 }
00492 
00493 /**
00494   * @brief  Controls the current audio volume level. 
00495   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for 
00496   *         Mute and 100 for Max volume level).
00497   * @retval BSP AUDIO status
00498   */
00499 uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
00500 {
00501   /* Call the codec volume control function with converted volume value */
00502   if (hAudioOut.AudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
00503   {
00504     return AUDIO_ERROR;
00505   }
00506   
00507   return AUDIO_OK;
00508 }
00509 
00510 /**
00511   * @brief  Enables or disables the MUTE mode by software 
00512   * @param  Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to 
00513   *         unmute the codec and restore previous volume level.
00514   * @retval BSP AUDIO status
00515   */
00516 uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
00517 { 
00518   /* Call the Codec Mute function */
00519   if (hAudioOut.AudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
00520   {
00521     return AUDIO_ERROR;
00522   }
00523   
00524   return AUDIO_OK;
00525 }
00526 
00527 /**
00528   * @brief  Switch dynamically (while audio file is being played) the output 
00529   *          target (speaker or headphone).
00530   * @param  Output: The audio output target: OUTPUT_DEVICE_SPEAKER,
00531   *         OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH
00532   * @retval BSP AUDIO status
00533   */
00534 uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
00535 {
00536   /* Call the Codec output device function */
00537   if (hAudioOut.AudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
00538   {
00539     return AUDIO_ERROR;
00540   }
00541   
00542   return AUDIO_OK;
00543 }
00544 
00545 /**
00546   * @brief  Updates the audio frequency.
00547   * @param  AudioFreq: Audio frequency used to play the audio stream.
00548   * @note   The SAI PLL input clock must be configure in the user application.
00549   *         The SAI PLL configuration done within this function assumes that
00550   *         the SAI PLL input clock runs at 8 MHz.
00551   * @retval BSP AUDIO status
00552   */
00553 uint8_t BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
00554 { 
00555   /* Configure the SAI PLL according to the requested audio frequency */
00556   if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
00557   {
00558     return AUDIO_ERROR;
00559   }
00560   
00561   /* Disable SAI peripheral to allow access to SAI internal registers */
00562   __HAL_SAI_DISABLE(&BSP_AUDIO_hSai);
00563   
00564   /* Update the SAI audio frequency configuration */
00565   BSP_AUDIO_hSai.Init.Mckdiv = SAIClockDivider(AudioFreq);
00566   HAL_SAI_Init(&BSP_AUDIO_hSai);
00567   
00568   /* Enable SAI peripheral to generate MCLK */
00569   __HAL_SAI_ENABLE(&BSP_AUDIO_hSai);
00570 
00571   return AUDIO_OK;
00572 }
00573 
00574 /**
00575   * @brief  Changes the Audio Out Configuration.
00576   * @param  AudioOutOption: specifies the audio out new configuration
00577   *         This parameter can be any value of @ref BSP_Audio_Out_Option
00578   * @note   This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
00579   *         audio out configuration.
00580   * @retval None
00581   */
00582 void BSP_AUDIO_OUT_ChangeAudioConfig(uint32_t AudioOutOption)
00583 { 
00584   /********** Playback Buffer circular/normal mode **********/
00585   if(AudioOutOption & BSP_AUDIO_OUT_CIRCULARMODE)
00586   {
00587     /* Deinitialize the Stream to update DMA mode */
00588     HAL_DMA_DeInit(BSP_AUDIO_hSai.hdmatx);
00589     
00590     /* Update the SAI audio Transfer DMA mode */
00591     BSP_AUDIO_hSai.hdmatx->Init.Mode = DMA_CIRCULAR;
00592     
00593     /* Configure the DMA Stream with new Transfer DMA mode */
00594     HAL_DMA_Init(BSP_AUDIO_hSai.hdmatx);      
00595   }
00596   else /* BSP_AUDIO_OUT_NORMALMODE */
00597   {
00598     /* Deinitialize the Stream to update DMA mode */
00599     HAL_DMA_DeInit(BSP_AUDIO_hSai.hdmatx);
00600     
00601     /* Update the SAI audio Transfer DMA mode */
00602     BSP_AUDIO_hSai.hdmatx->Init.Mode = DMA_NORMAL;
00603     
00604     /* Configure the DMA Stream with new Transfer DMA mode */
00605     HAL_DMA_Init(BSP_AUDIO_hSai.hdmatx);      
00606   }
00607   
00608   /********** Playback Buffer stereo/mono mode **********/
00609   if(AudioOutOption & BSP_AUDIO_OUT_STEREOMODE)
00610   {
00611     /* Disable SAI peripheral to allow access to SAI internal registers */
00612     __HAL_SAI_DISABLE(&BSP_AUDIO_hSai);
00613     
00614     /* Update the SAI audio frame slot configuration */
00615     BSP_AUDIO_hSai.Init.MonoStereoMode = SAI_STEREOMODE;
00616     HAL_SAI_Init(&BSP_AUDIO_hSai);
00617     
00618     /* Enable SAI peripheral to generate MCLK */
00619     __HAL_SAI_ENABLE(&BSP_AUDIO_hSai);
00620   }
00621   else /* BSP_AUDIO_OUT_MONOMODE */
00622   {
00623     /* Disable SAI peripheral to allow access to SAI internal registers */
00624     __HAL_SAI_DISABLE(&BSP_AUDIO_hSai);
00625     
00626     /* Update the SAI audio frame slot configuration */
00627     BSP_AUDIO_hSai.Init.MonoStereoMode = SAI_MONOMODE;
00628     HAL_SAI_Init(&BSP_AUDIO_hSai);
00629     
00630     /* Enable SAI peripheral to generate MCLK */
00631     __HAL_SAI_ENABLE(&BSP_AUDIO_hSai);
00632   }
00633 }
00634 
00635 /**
00636   * @brief  register user callback functions 
00637   * @param  ErrorCallback: pointer to the error callback function
00638   * @param  HalfTransferCallback: pointer to the half transfer callback function
00639   * @param  TransferCompleteCallback: pointer to the transfer complete callback function
00640   * @retval None
00641   */
00642 void BSP_AUDIO_OUT_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
00643                                      Audio_CallbackTypeDef HalfTransferCallback, 
00644                                      Audio_CallbackTypeDef TransferCompleteCallback)
00645 {
00646   hAudioOut.CbError            = ErrorCallback; 
00647   hAudioOut.CbHalfTransfer     = HalfTransferCallback; 
00648   hAudioOut.CbTransferComplete = TransferCompleteCallback;
00649 }
00650 
00651 /**
00652   * @brief  Tx Transfer completed callbacks.
00653   * @param  hsai: SAI handle
00654   * @retval None
00655   */
00656 void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
00657 {
00658   /* Invoke the registered 'TransferComplete' function (if any) */
00659   if (hAudioOut.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
00660   {
00661     hAudioOut.CbTransferComplete();
00662   }
00663 }
00664 
00665 /**
00666   * @brief  Tx Half Transfer completed callbacks.
00667   * @param  hsai: SAI handle
00668   * @retval None
00669   */
00670 void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
00671 {
00672   /* Invoke the registered 'HalfTransfer' callback function (if any) */
00673   if (hAudioOut.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
00674   {
00675     hAudioOut.CbHalfTransfer();
00676   }
00677 }
00678 
00679 /**
00680   * @brief  SAI error callbacks.
00681   * @param  hsai: SAI handle
00682   * @retval None
00683   */
00684 void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
00685 {
00686   /* Invoke the registered 'ErrorCallback' callback function (if any) */
00687   if (hAudioOut.CbError != (Audio_CallbackTypeDef)NULL)
00688   {
00689     hAudioOut.CbError();
00690   }
00691 }
00692 
00693 /**
00694   * @}
00695   */
00696 
00697 /** @addtogroup STM32L476G_EVAL_AUDIO_Exported_Functions
00698   * @{
00699   */
00700   
00701 /**
00702   * @brief  Initializes micropone related peripherals.
00703   * @note   This function assumes that the SAI input clock (through PLL_M)
00704   *         is already configured and ready to be used.  
00705   * @param  AudioFreq: Audio frequency to be configured for the SAI peripheral. 
00706   * @param  BitRes: Audio frequency to be configured for the SAI peripheral.
00707   * @param  ChnlNbr: Audio frequency to be configured for the SAI peripheral.
00708   * @retval BSP AUDIO status
00709   */
00710 uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
00711 {
00712   /* Update the audio input context */
00713   hAudioIn.Frequency          = AudioFreq;
00714   hAudioIn.BitResolution      = BitRes;
00715   hAudioIn.ChannelNbr         = ChnlNbr;
00716   hAudioIn.CbError            = (Audio_CallbackTypeDef)NULL; 
00717   hAudioIn.CbHalfTransfer     = (Audio_CallbackTypeDef)NULL; 
00718   hAudioIn.CbTransferComplete = (Audio_CallbackTypeDef)NULL;
00719 
00720   /* Configure the SAI PLL according to the requested audio frequency */
00721   if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
00722   {
00723     return AUDIO_ERROR;
00724   }
00725  
00726   /* Initializes the Digital Filter for Sigma-Delta Modulators interface */
00727   if(AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK)
00728   {
00729     return AUDIO_ERROR;
00730   }
00731   
00732   return AUDIO_OK;
00733   }
00734 
00735 /**
00736   * @brief  De-Initializes microphone related peripherals.
00737   * @retval BSP AUDIO status
00738 
00739   */
00740 uint8_t BSP_AUDIO_IN_DeInit(void)
00741 {
00742   /* De-initializes the Digital Filter for Sigma-Delta Modulators interface */
00743   if (AUDIO_DFSDMx_DeInit() != AUDIO_OK)
00744   {
00745     return AUDIO_ERROR;
00746   }
00747   
00748   /* Reset the audio input context */
00749   memset(&hAudioIn, 0, sizeof(hAudioIn));
00750 
00751   return AUDIO_OK;
00752 }
00753 
00754 /**
00755   * @brief  Starts audio recording.
00756   * @param  pbuf: Main buffer pointer for the recorded data storing  
00757   * @param  size: Current size of the recorded buffer
00758   * @note   The Right channel is start at first with synchro on start of Left channel
00759   * @retval BSP AUDIO status
00760   */
00761 uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size)
00762 {
00763   hAudioIn.pRecBuf = pbuf;
00764   hAudioIn.RecSize = size;
00765 
00766   /* Allocate hAudioIn.LeftRecBuff buffer */
00767 #if defined(BSP_AUDIO_USE_RTOS)
00768   hAudioIn.LeftRecBuff  = (int32_t *)k_malloc(size * sizeof(int32_t));
00769 #else
00770   hAudioIn.LeftRecBuff  = (int32_t *)malloc(size * sizeof(int32_t));
00771 #endif
00772   if(hAudioIn.LeftRecBuff == NULL)
00773   {
00774     return AUDIO_ERROR;
00775   }
00776 
00777   /* Call the Media layer start function for left channel */
00778   if(HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter, 
00779                                       (int32_t*)hAudioIn.LeftRecBuff, 
00780                                       (hAudioIn.RecSize/DEFAULT_AUDIO_IN_CHANNEL_NBR)) != HAL_OK)
00781   {
00782     return AUDIO_ERROR;
00783   }
00784 
00785   return AUDIO_OK;
00786 }
00787 
00788 /**
00789   * @brief  Updates the audio frequency.
00790   * @param  AudioFreq: Audio frequency used to record the audio stream.
00791   * @note   This API should be called after the BSP_AUDIO_IN_Init() to adjust the
00792   *         audio frequency.
00793   * @retval BSP AUDIO status
00794   */
00795 uint8_t BSP_AUDIO_IN_SetFrequency(uint32_t AudioFreq)
00796 { 
00797   /* Configure the SAI PLL according to the requested audio frequency */
00798   if (AUDIO_SAIPLLConfig(AudioFreq) != AUDIO_OK)
00799   {
00800     return AUDIO_ERROR;
00801   }
00802 
00803   /* De-initializes the Digital Filter for Sigma-Delta Modulators interface */
00804   if(AUDIO_DFSDMx_DeInit() != AUDIO_OK)
00805   {
00806     return AUDIO_ERROR;
00807   }
00808   
00809   /* Initializes the Digital Filter for Sigma-Delta Modulators interface */
00810   if(AUDIO_DFSDMx_Init(AudioFreq) != AUDIO_OK)
00811   {
00812     return AUDIO_ERROR;
00813   }
00814   
00815   return AUDIO_OK;
00816 }
00817 
00818 /**
00819   * @brief  Regular conversion complete callback. 
00820   * @note   In interrupt mode, user has to read conversion value in this function
00821             using HAL_DFSDM_FilterGetRegularValue.
00822   * @param  hdfsdm_filter : DFSDM filter handle.
00823   * @retval None
00824   */
00825 void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
00826 {
00827   uint32_t index;
00828   uint32_t recbufsize = (hAudioIn.RecSize/DEFAULT_AUDIO_IN_CHANNEL_NBR);
00829   
00830   for(index = (recbufsize/2); index < recbufsize; index++)
00831   {
00832     hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32760, 32760));
00833   }
00834   
00835   /* Invoke the registered 'TransferComplete' function (if any) */
00836   if (hAudioIn.CbTransferComplete != (Audio_CallbackTypeDef)NULL)
00837   {
00838     hAudioIn.CbTransferComplete();
00839   }
00840 }
00841 
00842 /**
00843   * @brief  Half regular conversion complete callback. 
00844   * @param  hdfsdm_filter : DFSDM filter handle.
00845   * @retval None
00846   */
00847 void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
00848 {
00849   uint32_t index;
00850   uint32_t recbufsize = (hAudioIn.RecSize/DEFAULT_AUDIO_IN_CHANNEL_NBR);
00851   
00852   
00853   for(index = 0; index < (recbufsize/2); index++)
00854   {
00855     hAudioIn.pRecBuf[index] = (uint16_t)(SaturaLH((hAudioIn.LeftRecBuff[index] >> 8), -32760, 32760));
00856   }
00857   
00858   /* Invoke the registered 'HalfTransfer' callback function (if any) */
00859   if (hAudioIn.CbHalfTransfer != (Audio_CallbackTypeDef)NULL)
00860   {
00861     hAudioIn.CbHalfTransfer();
00862   }
00863 }
00864 
00865 /**
00866   * @brief  Error callback. 
00867   * @param  hdfsdm_filter : DFSDM filter handle.
00868   * @retval None
00869   */
00870 void HAL_DFSDM_FilterErrorCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
00871 {
00872   /* Invoke the registered 'ErrorCallback' callback function (if any) */
00873   if (hAudioIn.CbError != (Audio_CallbackTypeDef)NULL)
00874   {
00875     hAudioIn.CbError();
00876   }
00877 }
00878 
00879 /**
00880   * @brief  Stops audio recording.
00881   * @retval BSP AUDIO status
00882   */
00883 uint8_t BSP_AUDIO_IN_Stop(void)
00884 {
00885   /* Call the Media layer stop function for left channel */
00886   if(HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK )
00887   {
00888     return AUDIO_ERROR;
00889   }
00890 
00891   /* Free hAudioIn.LeftRecBuff buffer */
00892 #if defined(BSP_AUDIO_USE_RTOS)
00893   k_free((void *)hAudioIn.LeftRecBuff);
00894 #else
00895   free((void *)hAudioIn.LeftRecBuff);
00896 #endif
00897   
00898   return AUDIO_OK;
00899 }
00900 
00901 /**
00902   * @brief  Pauses the audio file stream.
00903   * @retval BSP AUDIO status
00904   */
00905 uint8_t BSP_AUDIO_IN_Pause(void)
00906 {    
00907   /* Call the Media layer stop function */
00908   if(HAL_DFSDM_FilterRegularStop_DMA(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
00909   {
00910     return AUDIO_ERROR;
00911   }
00912   
00913   return AUDIO_OK;
00914 }
00915 
00916 /**
00917   * @brief  Resumes the audio file stream.
00918   * @retval BSP AUDIO status
00919   */
00920 uint8_t BSP_AUDIO_IN_Resume(void)
00921 {    
00922   /* Call the Media layer start function for left channel */
00923   if(HAL_DFSDM_FilterRegularStart_DMA(&BSP_AUDIO_hDfsdmLeftFilter,
00924                                       (int32_t*)hAudioIn.LeftRecBuff,
00925                                       (hAudioIn.RecSize/DEFAULT_AUDIO_IN_CHANNEL_NBR)) != HAL_OK)
00926   {
00927     return AUDIO_ERROR;
00928   }
00929   
00930   return AUDIO_OK;
00931 }
00932 
00933 /**
00934   * @brief  register user callback functions 
00935   * @param  ErrorCallback: pointer to the error callback function
00936   * @param  HalfTransferCallback: pointer to the half transfer callback function
00937   * @param  TransferCompleteCallback: pointer to the transfer complete callback function
00938   * @retval None
00939   */
00940 void BSP_AUDIO_IN_RegisterCallbacks(Audio_CallbackTypeDef ErrorCallback,
00941                                     Audio_CallbackTypeDef HalfTransferCallback, 
00942                                     Audio_CallbackTypeDef TransferCompleteCallback)
00943 {
00944   hAudioIn.CbError            = ErrorCallback; 
00945   hAudioIn.CbHalfTransfer     = HalfTransferCallback; 
00946   hAudioIn.CbTransferComplete = TransferCompleteCallback;
00947 }
00948 /**
00949   * @}
00950   */
00951 
00952 /* private functions --------------------------------------------------------*/
00953 /** @addtogroup STM32L476G_DISCOVERY_AUDIO_Private_Functions
00954   * @{
00955   */
00956 /**
00957   * @brief  Initializes the Audio Codec audio interface (SAI).
00958   * @param  AudioFreq: Audio frequency to be configured for the SAI peripheral.
00959   * @note   The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 
00960   *         and user can update this configuration using 
00961   * @retval BSP AUDIO status
00962   */
00963 static uint8_t AUDIO_SAIx_Init(uint32_t AudioFreq)
00964 {
00965   /* Disable SAI peripheral to allow access to SAI internal registers */
00966   __HAL_SAI_DISABLE(&BSP_AUDIO_hSai);
00967   
00968   /* Initialize the BSP_AUDIO_hSai Instance parameter */
00969   BSP_AUDIO_hSai.Instance = AUDIO_SAIx;
00970   
00971   /* Configure SAI_Block_x 
00972   LSBFirst: Disabled 
00973   DataSize: 16 */
00974   BSP_AUDIO_hSai.Init.AudioMode      = SAI_MODEMASTER_TX;
00975   BSP_AUDIO_hSai.Init.Synchro        = SAI_ASYNCHRONOUS;
00976   BSP_AUDIO_hSai.Init.SynchroExt     = SAI_SYNCEXT_DISABLE;
00977   BSP_AUDIO_hSai.Init.OutputDrive    = SAI_OUTPUTDRIVE_ENABLE;
00978   BSP_AUDIO_hSai.Init.NoDivider      = SAI_MASTERDIVIDER_ENABLE;
00979   BSP_AUDIO_hSai.Init.FIFOThreshold  = SAI_FIFOTHRESHOLD_1QF;
00980   BSP_AUDIO_hSai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;
00981   BSP_AUDIO_hSai.Init.Mckdiv         = SAIClockDivider(AudioFreq);
00982   BSP_AUDIO_hSai.Init.MonoStereoMode = SAI_STEREOMODE;
00983   BSP_AUDIO_hSai.Init.CompandingMode = SAI_NOCOMPANDING;
00984   BSP_AUDIO_hSai.Init.TriState       = SAI_OUTPUT_NOTRELEASED;
00985   BSP_AUDIO_hSai.Init.Protocol       = SAI_FREE_PROTOCOL;
00986   BSP_AUDIO_hSai.Init.DataSize       = SAI_DATASIZE_16;
00987   BSP_AUDIO_hSai.Init.FirstBit       = SAI_FIRSTBIT_MSB;
00988   BSP_AUDIO_hSai.Init.ClockStrobing  = SAI_CLOCKSTROBING_RISINGEDGE;
00989   
00990   /* Configure SAI_Block_x Frame 
00991   Frame Length: 32
00992   Frame active Length: 16
00993   FS Definition: Start frame + Channel Side identification
00994   FS Polarity: FS active Low
00995   FS Offset: FS asserted one bit before the first bit of slot 0 */ 
00996   BSP_AUDIO_hSai.FrameInit.FrameLength = 32;
00997   BSP_AUDIO_hSai.FrameInit.ActiveFrameLength = 16;
00998   BSP_AUDIO_hSai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
00999   BSP_AUDIO_hSai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
01000   BSP_AUDIO_hSai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
01001   
01002   /* Configure SAI Block_x Slot 
01003   Slot First Bit Offset: 0
01004   Slot Size  : 16
01005   Slot Number: 2
01006   Slot Active: Slots 0 and 1 actives */
01007   BSP_AUDIO_hSai.SlotInit.FirstBitOffset = 0;
01008   BSP_AUDIO_hSai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
01009   BSP_AUDIO_hSai.SlotInit.SlotNumber = 2; 
01010   BSP_AUDIO_hSai.SlotInit.SlotActive = SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1;
01011 
01012   /* Initializes the SAI peripheral*/
01013   if (HAL_SAI_Init(&BSP_AUDIO_hSai) != HAL_OK)
01014   {
01015     return AUDIO_ERROR;
01016   }
01017   
01018   /* Enable SAI peripheral to generate MCLK */
01019   __HAL_SAI_ENABLE(&BSP_AUDIO_hSai);
01020   
01021   return AUDIO_OK;
01022   
01023 }
01024 
01025 /**
01026   * @brief  De-initializes the Audio Codec audio interface (SAI).
01027   * @retval BSP AUDIO status
01028   */
01029 static uint8_t AUDIO_SAIx_DeInit(void)
01030 {
01031   /* Disable the SAI audio block */
01032   __HAL_SAI_DISABLE(&BSP_AUDIO_hSai);
01033 
01034   /* De-initializes the SAI peripheral */
01035   if (HAL_SAI_DeInit(&BSP_AUDIO_hSai) != HAL_OK)
01036   {
01037     return AUDIO_ERROR;
01038   }
01039   
01040   /* Disable SAIx PLL */
01041   if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK)
01042   {
01043     return AUDIO_ERROR;
01044   }  
01045   
01046   return AUDIO_OK;
01047 }
01048 
01049 /**
01050   * @brief  SAI MSP Init
01051   * @param  hsai : pointer to a SAI_HandleTypeDef structure
01052   * @retval None
01053   */
01054 void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
01055 { 
01056   GPIO_InitTypeDef  GPIO_InitStruct;  
01057 
01058   /* Enable SAI clock */
01059   AUDIO_SAIx_CLK_ENABLE();
01060   
01061   /* Enable GPIO clock */
01062   AUDIO_SAIx_MCK_SCK_SD_FS_ENABLE();
01063   
01064   /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/
01065   GPIO_InitStruct.Pin = AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SCK_PIN | AUDIO_SAIx_SD_PIN | AUDIO_SAIx_MCK_PIN;
01066   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
01067   GPIO_InitStruct.Pull = GPIO_NOPULL;
01068   GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
01069   GPIO_InitStruct.Alternate = AUDIO_SAIx_MCK_SCK_SD_FS_AF;
01070   HAL_GPIO_Init(AUDIO_SAIx_MCK_SCK_SD_FS_GPIO_PORT, &GPIO_InitStruct);
01071 
01072   /* Enable the DMA clock */
01073   AUDIO_SAIx_DMAx_CLK_ENABLE();
01074     
01075   if(hsai->Instance == AUDIO_SAIx)
01076   {
01077     /* Configure the hDmaSai handle parameters */   
01078     hDmaSai.Init.Request             = DMA_REQUEST_1;
01079     hDmaSai.Init.Direction           = DMA_MEMORY_TO_PERIPH;
01080     hDmaSai.Init.PeriphInc           = DMA_PINC_DISABLE;
01081     hDmaSai.Init.MemInc              = DMA_MINC_ENABLE;
01082     hDmaSai.Init.PeriphDataAlignment = AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE;
01083     hDmaSai.Init.MemDataAlignment    = AUDIO_SAIx_DMAx_MEM_DATA_SIZE;
01084     hDmaSai.Init.Mode                = DMA_NORMAL;
01085     hDmaSai.Init.Priority            = DMA_PRIORITY_HIGH;
01086     
01087     hDmaSai.Instance = AUDIO_SAIx_DMAx_CHANNEL;
01088     
01089     /* Associate the DMA handle */
01090     __HAL_LINKDMA(hsai, hdmatx, hDmaSai);
01091     
01092     /* Deinitialize the Stream for new transfer */
01093     HAL_DMA_DeInit(&hDmaSai);
01094     
01095     /* Configure the DMA Stream */
01096     HAL_DMA_Init(&hDmaSai);      
01097   }
01098   
01099   /* SAI DMA IRQ Channel configuration */
01100   HAL_NVIC_SetPriority(AUDIO_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
01101   HAL_NVIC_EnableIRQ(AUDIO_SAIx_DMAx_IRQ); 
01102 }
01103 
01104 /**
01105   * @brief  SAI MSP De-init
01106   * @param  hsai : pointer to a SAI_HandleTypeDef structure
01107   * @retval None
01108   */
01109 void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai)
01110 {
01111   /* Disable SAI DMA Channel IRQ  */
01112   HAL_NVIC_DisableIRQ(AUDIO_SAIx_DMAx_IRQ); 
01113 
01114   /* Reset the DMA Stream configuration*/
01115   HAL_DMA_DeInit(&hDmaSai);
01116   
01117   /* Disable the DMA clock */
01118   AUDIO_SAIx_DMAx_CLK_DISABLE();
01119     
01120   /* De-initialize FS, SCK, MCK and SD pins*/
01121   HAL_GPIO_DeInit(AUDIO_SAIx_MCK_SCK_SD_FS_GPIO_PORT, 
01122                   AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SCK_PIN | AUDIO_SAIx_SD_PIN | AUDIO_SAIx_MCK_PIN);
01123   
01124   /* Disable GPIO clock */
01125   AUDIO_SAIx_MCK_SCK_SD_FS_DISABLE();
01126   
01127   /* Disable SAI clock */
01128   AUDIO_SAIx_CLK_DISABLE();
01129 }
01130 
01131 /**
01132   * @brief  Resets the audio codec. It restores the default configuration of the 
01133   *         codec (this function shall be called before initializing the codec).
01134   * @retval None
01135   */
01136 static void AUDIO_CODEC_Reset(void)
01137 {
01138   /* Initialize the audio driver structure */
01139   hAudioOut.AudioDrv = &cs43l22_drv; 
01140   
01141   hAudioOut.AudioDrv->Reset(AUDIO_I2C_ADDRESS);
01142 }
01143 
01144 /**
01145   * @}
01146   */
01147 
01148 /** @addtogroup STM32L476G_DISCOVERY_AUDIO_Private_Functions
01149   * @{
01150   */ 
01151 
01152 /**
01153   * @brief  Initializes the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
01154   * @param  AudioFreq: Audio frequency to be used to set correctly the DFSDM peripheral.
01155   * @retval BSP AUDIO status
01156   */
01157 static uint8_t AUDIO_DFSDMx_Init(uint32_t AudioFreq)
01158 {
01159   /*####CHANNEL 2####*/
01160   hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Activation   = ENABLE;
01161   hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Selection    = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
01162   /* Set the DFSDM clock OUT audio frequency configuration */
01163   hAudioIn.hDfsdmLeftChannel.Init.OutputClock.Divider      = DFSDMClockDivider(AudioFreq);
01164   hAudioIn.hDfsdmLeftChannel.Init.Input.Multiplexer        = DFSDM_CHANNEL_EXTERNAL_INPUTS;
01165   hAudioIn.hDfsdmLeftChannel.Init.Input.DataPacking        = DFSDM_CHANNEL_STANDARD_MODE;
01166   hAudioIn.hDfsdmLeftChannel.Init.Input.Pins               = DFSDM_CHANNEL_SAME_CHANNEL_PINS;
01167   /* Request to sample stable data for LEFT micro on Rising edge */
01168   hAudioIn.hDfsdmLeftChannel.Init.SerialInterface.Type     = DFSDM_CHANNEL_SPI_RISING;
01169   hAudioIn.hDfsdmLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
01170   hAudioIn.hDfsdmLeftChannel.Init.Awd.FilterOrder          = DFSDM_CHANNEL_SINC1_ORDER;
01171   hAudioIn.hDfsdmLeftChannel.Init.Awd.Oversampling         = 10;
01172   hAudioIn.hDfsdmLeftChannel.Init.Offset                   = 0;
01173   hAudioIn.hDfsdmLeftChannel.Init.RightBitShift            = DFSDMRightBitShift(AudioFreq);
01174 
01175   hAudioIn.hDfsdmLeftChannel.Instance                      = DFSDM_Channel2;
01176 
01177     /* Init the DFSDM Channel */
01178   if (HAL_DFSDM_ChannelInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK)
01179   {
01180     return AUDIO_ERROR;
01181   }
01182 
01183   /*####FILTER 0####*/
01184   BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.Trigger         = DFSDM_FILTER_SW_TRIGGER;
01185   BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.FastMode        = ENABLE;
01186   BSP_AUDIO_hDfsdmLeftFilter.Init.RegularParam.DmaMode         = ENABLE;
01187   BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.Trigger        = DFSDM_FILTER_SW_TRIGGER;
01188   BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ScanMode       = DISABLE;
01189   BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.DmaMode        = DISABLE;
01190   BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ExtTrigger     = DFSDM_FILTER_EXT_TRIG_TIM8_TRGO;
01191   BSP_AUDIO_hDfsdmLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_BOTH_EDGES;
01192   BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.SincOrder        = DFSDMFilterOrder(AudioFreq);
01193   /* Set the DFSDM Filters Oversampling to have correct sample rate */
01194   BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.Oversampling     = DFSDMOverSampling(AudioFreq);
01195   BSP_AUDIO_hDfsdmLeftFilter.Init.FilterParam.IntOversampling  = 1;
01196   
01197   BSP_AUDIO_hDfsdmLeftFilter.Instance                          = AUDIO_DFSDMx_LEFT_FILTER;
01198 
01199     /* Init the DFSDM Filter */
01200   if (HAL_DFSDM_FilterInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
01201   {
01202     return AUDIO_ERROR;
01203   }
01204   
01205   /* Configure regular channel */
01206   if (HAL_DFSDM_FilterConfigRegChannel(&BSP_AUDIO_hDfsdmLeftFilter, 
01207                                       DFSDM_CHANNEL_2, 
01208                                       DFSDM_CONTINUOUS_CONV_ON) != HAL_OK)
01209   {
01210     return AUDIO_ERROR;
01211   }
01212 
01213   return AUDIO_OK;
01214 }
01215 
01216 /**
01217   * @brief  De-initializes the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
01218   * @retval BSP AUDIO status
01219   */
01220 static uint8_t AUDIO_DFSDMx_DeInit(void)
01221 {
01222   /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */
01223   if (HAL_DFSDM_FilterDeInit(&BSP_AUDIO_hDfsdmLeftFilter) != HAL_OK)
01224   {
01225     return AUDIO_ERROR;
01226   }
01227 
01228   /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */
01229   if (HAL_DFSDM_ChannelDeInit(&hAudioIn.hDfsdmLeftChannel) != HAL_OK)
01230   {
01231     return AUDIO_ERROR;
01232   }
01233 
01234   /* Disable DFSDM clock */
01235   AUDIO_DFSDMx_CLK_DISABLE();
01236 
01237   /* Disable SAIx PLL */
01238   if (AUDIO_SAIx_PLL_DISABLE() != AUDIO_OK)
01239   {
01240     return AUDIO_ERROR;
01241   }  
01242 
01243   /* DFSDM reset */
01244   __HAL_RCC_DFSDM_FORCE_RESET();
01245   __HAL_RCC_DFSDM_RELEASE_RESET();
01246 
01247   return AUDIO_OK;
01248 }
01249 
01250 /**
01251   * @brief  Initializes the DFSDM channel MSP.
01252   * @param  hdfsdm_channel : DFSDM channel handle.
01253   * @retval None
01254   */
01255 void HAL_DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel)
01256 {
01257   GPIO_InitTypeDef  GPIO_InitStruct;  
01258 
01259   /* Enable DFSDM clock */
01260   AUDIO_DFSDMx_CLK_ENABLE();
01261   
01262   /* Enable GPIO clock */
01263   AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE();
01264   
01265   /* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN pins ------------------*/
01266   GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN | AUDIO_DFSDMx_DMIC_DATIN_PIN;
01267   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
01268   GPIO_InitStruct.Pull = GPIO_NOPULL;
01269   GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
01270   GPIO_InitStruct.Alternate = AUDIO_DFSDMx_CKOUT_DMIC_DATIN_AF;
01271   HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct);
01272 }
01273 
01274 /**
01275   * @brief  De-initializes the DFSDM channel MSP.
01276   * @param  hdfsdm_channel : DFSDM channel handle.
01277   * @retval None
01278   */
01279 void HAL_DFSDM_ChannelMspDeInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel)
01280 {
01281   GPIO_InitTypeDef  GPIO_InitStruct;
01282   
01283   /* Enable GPIO clock */
01284   AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE();
01285   
01286   /* DFSDM pins configuration: DFSDM_CKOUT */
01287   GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN;
01288   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
01289   GPIO_InitStruct.Pull = GPIO_NOPULL;
01290   GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
01291   HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct);
01292   HAL_GPIO_WritePin(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, AUDIO_DFSDMx_CKOUT_PIN, GPIO_PIN_RESET);
01293 
01294 
01295   /* De-initialize DMIC_DATIN pin */
01296   HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, AUDIO_DFSDMx_DMIC_DATIN_PIN);
01297 }
01298 
01299 /**
01300   * @brief  Initializes the DFSDM filter MSP.
01301   * @param  hdfsdm_filter : DFSDM filter handle.
01302   * @retval None
01303   */
01304 void HAL_DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
01305 {
01306   /* Enable DFSDM clock */
01307   AUDIO_DFSDMx_CLK_ENABLE();
01308   
01309   /* Enable the DMA clock */
01310   AUDIO_DFSDMx_DMAx_CLK_ENABLE();
01311     
01312   /* Configure the hAudioIn.hDmaDfsdmLeft handle parameters */   
01313   hAudioIn.hDmaDfsdmLeft.Init.Request             = DMA_REQUEST_0;
01314   hAudioIn.hDmaDfsdmLeft.Init.Direction           = DMA_PERIPH_TO_MEMORY;
01315   hAudioIn.hDmaDfsdmLeft.Init.PeriphInc           = DMA_PINC_DISABLE;
01316   hAudioIn.hDmaDfsdmLeft.Init.MemInc              = DMA_MINC_ENABLE;
01317   hAudioIn.hDmaDfsdmLeft.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE;
01318   hAudioIn.hDmaDfsdmLeft.Init.MemDataAlignment    = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE;
01319   hAudioIn.hDmaDfsdmLeft.Init.Mode                = DMA_CIRCULAR;
01320   hAudioIn.hDmaDfsdmLeft.Init.Priority            = DMA_PRIORITY_HIGH;
01321 
01322   hAudioIn.hDmaDfsdmLeft.Instance               = AUDIO_DFSDMx_DMAx_LEFT_CHANNEL;
01323   
01324   /* Associate the DMA handle */
01325   __HAL_LINKDMA(hdfsdm_filter, hdmaReg, hAudioIn.hDmaDfsdmLeft);
01326   
01327   /* Reset DMA handle state */
01328   __HAL_DMA_RESET_HANDLE_STATE(&hAudioIn.hDmaDfsdmLeft);
01329 
01330   /* Configure the DMA Channel */
01331   HAL_DMA_Init(&hAudioIn.hDmaDfsdmLeft);      
01332 
01333   /* DMA IRQ Channel configuration */
01334     HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
01335     HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_LEFT_IRQ);
01336   }
01337 
01338  /**
01339   * @brief  De-initializes the DFSDM filter MSP.
01340   * @param  hdfsdm_filter : DFSDM filter handle.
01341   * @retval None
01342   */
01343 void HAL_DFSDM_FilterMspDeInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
01344 {
01345   /* Disable DMA  Channel IRQ */
01346   HAL_NVIC_DisableIRQ(AUDIO_DFSDMx_DMAx_LEFT_IRQ);
01347 
01348   /* De-initialize the DMA Channel */
01349   HAL_DMA_DeInit(&hAudioIn.hDmaDfsdmLeft);      
01350 
01351   /* Disable the DMA clock */
01352   AUDIO_DFSDMx_DMAx_CLK_DISABLE();
01353 }
01354 
01355 /**
01356   * @brief  Configures the SAI PLL clock according to the required audio frequency.
01357   * @param  Frequency: Audio frequency.  
01358   * @retval BSP AUDIO status
01359   * @note   The SAI PLL input clock must be configured in the user application.
01360   *         The SAI PLL configuration done within this function assumes that
01361   *         the SAI PLL input clock runs at 8 MHz.
01362   */
01363 static uint8_t AUDIO_SAIPLLConfig(uint32_t Frequency)
01364 {
01365   RCC_PeriphCLKInitTypeDef RCC_ExCLKInitStruct;
01366 
01367   /* Retreive actual RCC configuration */
01368   HAL_RCCEx_GetPeriphCLKConfig(&RCC_ExCLKInitStruct);
01369   
01370     if (   (Frequency == AUDIO_FREQUENCY_11K) 
01371         || (Frequency == AUDIO_FREQUENCY_22K)
01372         || (Frequency == AUDIO_FREQUENCY_44K) )
01373   {
01374     /* Configure PLLSAI prescalers */
01375     /* SAI clock config 
01376     PLLSAI1_VCO= 8 Mhz * PLLSAI1N = 8 * 24 = VCO_192M 
01377     SAI_CK_x = PLLSAI1_VCO/PLLSAI1P = 192/17 = 11.294 Mhz */  
01378     RCC_ExCLKInitStruct.PeriphClockSelection    = RCC_PERIPHCLK_SAI1;
01379     RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1N        = 24; 
01380     RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1P        = 17; 
01381     RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK;
01382     RCC_ExCLKInitStruct.Sai1ClockSelection      = RCC_SAI1CLKSOURCE_PLLSAI1;
01383   }
01384   else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
01385   {
01386     /* SAI clock config 
01387     PLLSAI1_VCO= 8 Mhz * PLLSAI1N = 8 * 43 = VCO_344M 
01388     SAI_CK_x = PLLSAI1_VCO/PLLSAI1P = 344/7 = 49.142 Mhz */  
01389     RCC_ExCLKInitStruct.PeriphClockSelection    = RCC_PERIPHCLK_SAI1;
01390     RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1N        = 43;
01391     RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1P        = 7;
01392     RCC_ExCLKInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK;
01393     RCC_ExCLKInitStruct.Sai1ClockSelection      = RCC_SAI1CLKSOURCE_PLLSAI1;
01394   }
01395   
01396   if (HAL_RCCEx_PeriphCLKConfig(&RCC_ExCLKInitStruct) != HAL_OK)
01397   {
01398     return AUDIO_ERROR;
01399   }    
01400 
01401   return AUDIO_OK;
01402 }
01403 
01404 /**
01405   * @}
01406   */
01407 
01408 /**
01409   * @}
01410   */
01411 
01412 /**
01413   * @}
01414   */
01415 
01416 /**
01417   * @}
01418   */
01419 
01420 /**
01421   * @}
01422   */
01423 
01424 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
Generated on Tue Jun 23 2015 17:15:45 for STM32L476G-Discovery BSP User Manual by   doxygen 1.7.6.1