STM32446E_EVAL BSP User Manual: stm32446e_eval_audio.c Source File

STM32446E EVAL BSP Drivers

stm32446e_eval_audio.c
Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    stm32446e_eval_audio.c
00004   * @author  MCD Application Team
00005   * @version V1.1.1
00006   * @date    13-January-2016
00007   * @brief   This file provides the Audio driver for the STM32446E-EVAL evaluation board.
00008   ******************************************************************************
00009   * @attention
00010   *
00011   * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
00012   *
00013   * Redistribution and use in source and binary forms, with or without modification,
00014   * are permitted provided that the following conditions are met:
00015   *   1. Redistributions of source code must retain the above copyright notice,
00016   *      this list of conditions and the following disclaimer.
00017   *   2. Redistributions in binary form must reproduce the above copyright notice,
00018   *      this list of conditions and the following disclaimer in the documentation
00019   *      and/or other materials provided with the distribution.
00020   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00021   *      may be used to endorse or promote products derived from this software
00022   *      without specific prior written permission.
00023   *
00024   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00025   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00028   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00030   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00032   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034   *
00035   ******************************************************************************
00036   */
00037 
00038 /*==============================================================================
00039                                  User NOTES
00040                                  
00041 How To use this driver:
00042 -----------------------
00043    + This driver supports STM32F4xx devices on STM32446E-EVAL (MB1045) Evaluation boards.
00044    + Call the function BSP_AUDIO_OUT_Init(
00045                                     OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, 
00046                                                   OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH)
00047                                     Volume      : Initial volume to be set (0 is min (mute), 100 is max (100%)
00048                                     AudioFreq   : Audio frequency in Hz (8000, 16000, 22500, 32000...)
00049                                                   this parameter is relative to the audio file/stream type.
00050                                    )
00051       This function configures all the hardware required for the audio application (codec, I2C, SAI, 
00052       GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK.
00053       If the returned value is different from AUDIO_OK or the function is stuck then the communication with
00054       the codec or the MFX has failed (try to un-plug the power or reset device in this case).
00055       - OUTPUT_DEVICE_SPEAKER  : only speaker will be set as output for the audio stream.
00056       - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream.
00057       - OUTPUT_DEVICE_BOTH     : both Speaker and Headphone are used as outputs for the audio stream
00058                                  at the same time.
00059       Note. On STM32446E-EVAL SAI_DMA is configured in CIRCULAR mode. Due to this the application
00060         does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming.
00061    + Call the function BSP_EVAL_AUDIO_OUT_Play(
00062                                   pBuffer: pointer to the audio data file address
00063                                   Size   : size of the buffer to be sent in Bytes
00064                                  )
00065       to start playing (for the first time) from the audio file/stream.
00066    + Call the function BSP_AUDIO_OUT_Pause() to pause playing   
00067    + Call the function BSP_AUDIO_OUT_Resume() to resume playing.
00068        Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called
00069           for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case).
00070        Note. This function should be called only when the audio file is played or paused (not stopped).
00071    + For each mode, you may need to implement the relative callback functions into your code.
00072       The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in 
00073       the stm32446e_eval_audio.h file. (refer to the example for more details on the callbacks implementations)
00074    + To Stop playing, to modify the volume level, the frequency, the audio frame slot, 
00075       the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), 
00076       AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(),
00077       BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop().
00078    + The driver API and the callback functions are at the end of the stm32446e_eval_audio.h file.
00079  
00080 
00081 Driver architecture:
00082 --------------------
00083    + This driver provides the High Audio Layer: consists of the function API exported in the stm32446e_eval_audio.h file
00084      (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...)
00085    + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/
00086      providing the audio file/stream. These functions are also included as local functions into
00087      the stm32446e_eval_audio_codec.c file (I2Sx_Init(), I2Sx_DeInit(), SAIx_Init() and SAIx_DeInit())
00088 
00089 Known Limitations:
00090 ------------------
00091    1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second 
00092       Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams.
00093    2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, 
00094       File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.
00095    3- Supports only Stereo audio streaming.
00096    4- Supports only 16-bits audio data size.
00097 ==============================================================================*/
00098 
00099 /* Includes ------------------------------------------------------------------*/
00100 #include "stm32446e_eval_audio.h"
00101 
00102 /** @addtogroup BSP
00103   * @{
00104   */
00105 
00106 /** @addtogroup STM32446E_EVAL
00107   * @{
00108   */ 
00109   
00110 /** @defgroup STM32446E_EVAL_AUDIO STM32446E EVAL AUDIO
00111   * @brief This file includes the low layer driver for wm8994 Audio Codec
00112   *        available on STM32446E-EVAL evaluation board(MB1045).
00113   * @{
00114   */ 
00115 
00116 /** @defgroup STM32446E_EVAL_AUDIO_Private_Types STM32446E EVAL AUDIO Private Types
00117   * @{
00118   */ 
00119 /**
00120   * @}
00121   */ 
00122   
00123 /** @defgroup STM32446E_EVAL_AUDIO_Private_Defines STM32446E EVAL AUDIO Private Defines
00124   * @{
00125   */
00126 /**
00127   * @}
00128   */ 
00129 
00130 /** @defgroup STM32446E_EVAL_AUDIO_Private_Macros STM32446E EVAL AUDIO Private Macros 
00131   * @{
00132   */
00133 /**
00134   * @}
00135   */ 
00136   
00137 /** @defgroup STM32446E_EVAL_AUDIO_Private_Variables STM32446E EVAL AUDIO Private Variables
00138   * @{
00139   */
00140   
00141 /*
00142 Note: 
00143   these global variables are not compliant to naming rules (upper case without "_" ), 
00144   but we keep this naming for compatibility, in fact these variables (not static)
00145   could have been used by the application, example the stm32f4xx_it.c:
00146     void DMA2_Stream6_IRQHandler(void)
00147      {  HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);  }
00148 */
00149 AUDIO_DrvTypeDef          *audio_drv;
00150 SAI_HandleTypeDef         haudio_out_sai;
00151 I2S_HandleTypeDef         haudio_in_i2s;
00152 TIM_HandleTypeDef         haudio_tim;
00153 
00154 PDMFilter_InitStruct Filter[2];
00155 uint8_t Channel_Demux[128] = {
00156     0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
00157     0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
00158     0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
00159     0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
00160     0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
00161     0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03,
00162     0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
00163     0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07,
00164     0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
00165     0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
00166     0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
00167     0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
00168     0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
00169     0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b,
00170     0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f,
00171     0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f
00172 };
00173    
00174 uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME;
00175     
00176 /**
00177   * @}
00178   */ 
00179 
00180 /** @defgroup STM32446E_EVAL_AUDIO_Private_Function_Prototypes STM32446E EVAL AUDIO Private Function Prototypes
00181   * @{
00182   */
00183 static void SAIx_Init(uint32_t AudioFreq);
00184 static void SAIx_DeInit(void);
00185 static void I2Sx_Init(uint32_t AudioFreq);
00186 static void I2Sx_DeInit(void);
00187 static void TIMx_IC_MspInit(TIM_HandleTypeDef *htim);
00188 static void TIMx_IC_MspDeInit(TIM_HandleTypeDef *htim);
00189 static void TIMx_Init(void);
00190 static void TIMx_DeInit(void);
00191 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr);
00192 /**
00193   * @}
00194   */ 
00195 
00196 /** @defgroup STM32446E_EVAL_AUDIO_out_Private_Functions STM32446E EVAL AUDIO OUT Private Functions
00197   * @{
00198   */ 
00199 
00200 /**
00201   * @brief  Configures the audio peripherals.
00202   * @param  OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
00203   *                       or OUTPUT_DEVICE_BOTH.
00204   * @param  Volume: Initial volume level (from 0 (Mute) to 100 (Max))
00205   * @param  AudioFreq: Audio frequency used to play the audio stream.
00206   * @note   The I2S PLL input clock must be done in the user application.  
00207   * @retval AUDIO_OK if correct communication, else wrong communication
00208   */
00209 uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
00210 { 
00211   uint8_t ret = AUDIO_ERROR;
00212   uint32_t deviceid = 0x00;
00213 
00214   SAIx_DeInit();
00215 
00216   /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 
00217   BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL);
00218  
00219   /* SAI data transfer preparation:
00220   Prepare the Media to be used for the audio transfer from memory to SAI peripheral */
00221   haudio_out_sai.Instance = AUDIO_SAIx;
00222   if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET)
00223   {
00224     /* Init the SAI MSP: this __weak function can be redefined by the application*/
00225     BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL);
00226   }
00227   SAIx_Init(AudioFreq);
00228   
00229   /* wm8994 codec initialization */
00230   deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS);
00231   
00232   if((deviceid) == WM8994_ID)
00233   {  
00234     /* Initialize the audio driver structure */
00235     audio_drv = &wm8994_drv; 
00236     ret = AUDIO_OK;
00237   }
00238   else
00239   {
00240     ret = AUDIO_ERROR;
00241   }
00242 
00243   if(ret == AUDIO_OK)
00244   {
00245     /* Resets the audio codec. */
00246     audio_drv->Reset(AUDIO_I2C_ADDRESS);
00247     /* Initialize the codec internal registers */
00248     audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq);
00249   }
00250  
00251   return ret;
00252 }
00253 
00254 /**
00255   * @brief  Starts playing audio stream from a data buffer for a determined size. 
00256   * @param  pBuffer: Pointer to the buffer 
00257   * @param  Size: Number of audio data BYTES.
00258   * @retval AUDIO_OK if correct communication, else wrong communication
00259   */
00260 uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
00261 {
00262   /* Call the audio Codec Play function */
00263   if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0)
00264   {  
00265     return AUDIO_ERROR;
00266   }
00267   else
00268   {
00269     /* Update the Media layer and enable it for play */  
00270     HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE));
00271     
00272     return AUDIO_OK;
00273   }
00274 }
00275 
00276 /**
00277   * @brief  Sends n-Bytes on the SAI interface.
00278   * @param  pData: pointer on data address 
00279   * @param  Size: number of data to be written
00280   */
00281 void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
00282 {
00283    HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size);
00284 }
00285 
00286 /**
00287   * @brief  This function Pauses the audio file stream. In case
00288   *         of using DMA, the DMA Pause feature is used.
00289   * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only
00290   *          BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 
00291   *          function for resume could lead to unexpected behavior).
00292   * @retval AUDIO_OK if correct communication, else wrong communication
00293   */
00294 uint8_t BSP_AUDIO_OUT_Pause(void)
00295 {    
00296   /* Call the Audio Codec Pause/Resume function */
00297   if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0)
00298   {
00299     return AUDIO_ERROR;
00300   }
00301   else
00302   {
00303     /* Call the Media layer pause function */
00304     HAL_SAI_DMAPause(&haudio_out_sai);
00305     
00306     /* Return AUDIO_OK when all operations are correctly done */
00307     return AUDIO_OK;
00308   }
00309 }
00310 
00311 /**
00312   * @brief  This function  Resumes the audio file stream.  
00313   * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only
00314   *          BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 
00315   *          function for resume could lead to unexpected behavior).
00316   * @retval AUDIO_OK if correct communication, else wrong communication
00317   */
00318 uint8_t BSP_AUDIO_OUT_Resume(void)
00319 {    
00320   /* Call the Audio Codec Pause/Resume function */
00321   if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0)
00322   {
00323     return AUDIO_ERROR;
00324   }
00325   else
00326   {
00327     /* Call the Media layer pause/resume function */
00328     HAL_SAI_DMAResume(&haudio_out_sai);
00329     
00330     /* Return AUDIO_OK when all operations are correctly done */
00331     return AUDIO_OK;
00332   }
00333 }
00334 
00335 /**
00336   * @brief  Stops audio playing and Power down the Audio Codec. 
00337   * @param  Option: could be one of the following parameters 
00338   *           - CODEC_PDWN_SW: for software power off (by writing registers). 
00339   *                            Then no need to reconfigure the Codec after power on.
00340   *           - CODEC_PDWN_HW: completely shut down the codec (physically). 
00341   *                            Then need to reconfigure the Codec after power on.  
00342   * @retval AUDIO_OK if correct communication, else wrong communication
00343   */
00344 uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
00345 {
00346   /* Call the Media layer stop function */
00347   HAL_SAI_DMAStop(&haudio_out_sai);
00348 
00349   /* Call Audio Codec Stop function */
00350   if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
00351   {
00352     return AUDIO_ERROR;
00353   }
00354   else
00355   {
00356     if(Option == CODEC_PDWN_HW)
00357     { 
00358       /* Wait at least 100us */
00359       HAL_Delay(1);
00360     }
00361     /* Return AUDIO_OK when all operations are correctly done */
00362     return AUDIO_OK;
00363   }
00364 }
00365 
00366 /**
00367   * @brief  Controls the current audio volume level. 
00368   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for 
00369   *         Mute and 100 for Max volume level).
00370   * @retval AUDIO_OK if correct communication, else wrong communication
00371   */
00372 uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
00373 {
00374   /* Call the codec volume control function with converted volume value */
00375   if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
00376   {
00377     return AUDIO_ERROR;
00378   }
00379   else
00380   {
00381     /* Return AUDIO_OK when all operations are correctly done */
00382     return AUDIO_OK;
00383   }
00384 }
00385 
00386 /**
00387   * @brief  Enables or disables the MUTE mode by software 
00388   * @param  Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to 
00389   *         unmute the codec and restore previous volume level.
00390   * @retval AUDIO_OK if correct communication, else wrong communication
00391   */
00392 uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
00393 { 
00394   /* Call the Codec Mute function */
00395   if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
00396   {
00397     return AUDIO_ERROR;
00398   }
00399   else
00400   {
00401     /* Return AUDIO_OK when all operations are correctly done */
00402     return AUDIO_OK;
00403   }
00404 }
00405 
00406 /**
00407   * @brief  Switch dynamically (while audio file is played) the output target 
00408   *         (speaker or headphone).
00409   * @param  Output: The audio output target: OUTPUT_DEVICE_SPEAKER,
00410   *         OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH
00411   * @retval AUDIO_OK if correct communication, else wrong communication
00412   */
00413 uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
00414 {
00415   /* Call the Codec output device function */
00416   if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
00417   {
00418     return AUDIO_ERROR;
00419   }
00420   else
00421   {
00422     /* Return AUDIO_OK when all operations are correctly done */
00423     return AUDIO_OK;
00424   }
00425 }
00426 
00427 /**
00428   * @brief  Updates the audio frequency.
00429   * @param  AudioFreq: Audio frequency used to play the audio stream.
00430   * @note   This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
00431   *         audio frequency.
00432   */
00433 void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
00434 { 
00435   /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 
00436   BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL);
00437 
00438   /* Disable SAI peripheral to allow access to SAI internal registers */
00439   __HAL_SAI_DISABLE(&haudio_out_sai);
00440     
00441   /* Update the SAI audio frequency configuration */
00442   haudio_out_sai.Init.AudioFrequency = AudioFreq;
00443   HAL_SAI_Init(&haudio_out_sai);
00444   
00445   /* Enable SAI peripheral to generate MCLK */
00446   __HAL_SAI_ENABLE(&haudio_out_sai);
00447 }
00448 
00449 /**
00450   * @brief  Updates the Audio frame slot configuration.
00451   * @param  AudioFrameSlot: specifies the audio Frame slot
00452   *         This parameter can be any value of @ref CODEC_AudioFrame_SLOT_TDMMode
00453   * @note   This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
00454   *         audio frame slot.
00455   */
00456 void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot)
00457 { 
00458   /* Disable SAI peripheral to allow access to SAI internal registers */
00459   __HAL_SAI_DISABLE(&haudio_out_sai);
00460   
00461   /* Update the SAI audio frame slot configuration */
00462   haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot;
00463   HAL_SAI_Init(&haudio_out_sai);
00464   
00465   /* Enable SAI peripheral to generate MCLK */
00466   __HAL_SAI_ENABLE(&haudio_out_sai);
00467 }
00468 
00469 /**
00470   * @brief  Deinit the audio peripherals.
00471   */
00472 void BSP_AUDIO_OUT_DeInit(void)
00473 {
00474   SAIx_DeInit();
00475   /* DeInit the SAI MSP : this __weak function can be rewritten by the applic */
00476   BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL);
00477 }
00478 
00479 /**
00480   * @brief  Tx Transfer completed callbacks.
00481   * @param  hsai: SAI handle
00482   */
00483 void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
00484 {
00485   /* Manage the remaining file size and new address offset: This function 
00486      should be coded by user (its prototype is already declared in stm32446e_eval_audio.h) */
00487   BSP_AUDIO_OUT_TransferComplete_CallBack();
00488 }
00489 
00490 /**
00491   * @brief  Tx Half Transfer completed callbacks.
00492   * @param  hsai: SAI handle
00493   */
00494 void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
00495 {
00496   /* Manage the remaining file size and new address offset: This function 
00497      should be coded by user (its prototype is already declared in stm32446e_eval_audio.h) */
00498   BSP_AUDIO_OUT_HalfTransfer_CallBack();
00499 }
00500 
00501 /**
00502   * @brief  SAI error callbacks.
00503   * @param  hsai: SAI handle
00504   */
00505 void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
00506 {
00507   BSP_AUDIO_OUT_Error_CallBack();
00508 }
00509 
00510 /**
00511   * @brief  Manages the DMA full Transfer complete event.
00512   */
00513 __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
00514 {
00515 }
00516 
00517 /**
00518   * @brief  Manages the DMA Half Transfer complete event.
00519   */
00520 __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
00521 { 
00522 }
00523 
00524 /**
00525   * @brief  Manages the DMA FIFO error event.
00526   */
00527 __weak void BSP_AUDIO_OUT_Error_CallBack(void)
00528 {
00529 }
00530 
00531 /**
00532   * @brief  Initializes BSP_AUDIO_OUT MSP.
00533   * @param  hsai: SAI handle
00534   * @param  Params: pointer on additional configuration parameters, can be NULL.
00535   */
00536 __weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params)
00537 { 
00538   static DMA_HandleTypeDef hdma_sai_tx;
00539   GPIO_InitTypeDef  gpio_init_structure;  
00540 
00541   /* Enable SAI clock */
00542   AUDIO_SAIx_CLK_ENABLE();
00543   
00544   /* Enable GPIO clock */
00545   AUDIO_SAIx_MCLK_SCK_ENABLE();
00546   AUDIO_SAIx_SD_FS_ENABLE();
00547   
00548   /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/
00549   gpio_init_structure.Mode = GPIO_MODE_AF_PP;
00550   gpio_init_structure.Pull = GPIO_NOPULL;
00551   gpio_init_structure.Speed = GPIO_SPEED_HIGH;
00552 
00553   gpio_init_structure.Alternate = AUDIO_SAIx_MCLK_SD_FS_AF;
00554   gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SD_PIN;
00555   HAL_GPIO_Init(AUDIO_SAIx_SD_FS_GPIO_PORT, &gpio_init_structure);
00556 
00557   gpio_init_structure.Alternate = AUDIO_SAIx_MCLK_SD_FS_AF;
00558   gpio_init_structure.Pin = AUDIO_SAIx_MCK_PIN;
00559   HAL_GPIO_Init(AUDIO_SAIx_MCLK_SCK_GPIO_PORT, &gpio_init_structure);
00560 
00561   gpio_init_structure.Alternate = AUDIO_SAIx_SCK_AF;
00562   gpio_init_structure.Pin = AUDIO_SAIx_SCK_PIN ;
00563   HAL_GPIO_Init(AUDIO_SAIx_MCLK_SCK_GPIO_PORT, &gpio_init_structure);
00564  
00565   /* Enable the DMA clock */
00566   AUDIO_SAIx_DMAx_CLK_ENABLE();
00567     
00568   if(hsai->Instance == AUDIO_SAIx)
00569   {
00570     /* Configure the hdma_sai_tx handle parameters */   
00571     hdma_sai_tx.Init.Channel             = AUDIO_SAIx_DMAx_CHANNEL;
00572     hdma_sai_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
00573     hdma_sai_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
00574     hdma_sai_tx.Init.MemInc              = DMA_MINC_ENABLE;
00575     hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE;
00576     hdma_sai_tx.Init.MemDataAlignment    = AUDIO_SAIx_DMAx_MEM_DATA_SIZE;
00577     hdma_sai_tx.Init.Mode                = DMA_CIRCULAR;
00578     hdma_sai_tx.Init.Priority            = DMA_PRIORITY_HIGH;
00579     hdma_sai_tx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;         
00580     hdma_sai_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
00581     hdma_sai_tx.Init.MemBurst            = DMA_MBURST_SINGLE;
00582     hdma_sai_tx.Init.PeriphBurst         = DMA_PBURST_SINGLE; 
00583     
00584     hdma_sai_tx.Instance = AUDIO_SAIx_DMAx_STREAM;
00585     
00586     /* Associate the DMA handle */
00587     __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx);
00588     
00589     /* Deinitialize the Stream for new transfer */
00590     HAL_DMA_DeInit(&hdma_sai_tx);
00591     
00592     /* Configure the DMA Stream */
00593     HAL_DMA_Init(&hdma_sai_tx);      
00594   }
00595   
00596   /* SAI DMA IRQ Channel configuration */
00597   HAL_NVIC_SetPriority(AUDIO_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
00598   HAL_NVIC_EnableIRQ(AUDIO_SAIx_DMAx_IRQ); 
00599 }
00600 
00601 /**
00602   * @brief  Deinitializes SAI MSP.
00603   * @param  hsai: SAI handle
00604   * @param  Params: pointer on additional configuration parameters, can be NULL.
00605   */
00606 __weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params)
00607 {
00608     GPIO_InitTypeDef  gpio_init_structure;
00609 
00610     /* SAI DMA IRQ Channel deactivation */
00611     HAL_NVIC_DisableIRQ(AUDIO_SAIx_DMAx_IRQ);
00612 
00613     if(hsai->Instance == AUDIO_SAIx)
00614     {
00615       /* Deinitialize the DMA stream */
00616       HAL_DMA_DeInit(hsai->hdmatx);
00617     }
00618 
00619     /* Disable SAI peripheral */
00620     __HAL_SAI_DISABLE(hsai);  
00621 
00622     /* Deactives CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */
00623     gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SD_PIN;
00624     HAL_GPIO_DeInit(AUDIO_SAIx_SD_FS_GPIO_PORT, gpio_init_structure.Pin);
00625 
00626     gpio_init_structure.Pin = AUDIO_SAIx_MCK_PIN;
00627     HAL_GPIO_DeInit(AUDIO_SAIx_MCLK_SCK_GPIO_PORT, gpio_init_structure.Pin);
00628 
00629     gpio_init_structure.Pin = AUDIO_SAIx_SCK_PIN ;
00630     HAL_GPIO_DeInit(AUDIO_SAIx_MCLK_SCK_GPIO_PORT, gpio_init_structure.Pin);
00631   
00632     /* Disable SAI clock */
00633     AUDIO_SAIx_CLK_DISABLE();
00634 
00635     /* GPIO pins clock and DMA clock can be shut down in the application 
00636        by surcharging this __weak function */ 
00637 }
00638 
00639 /**
00640   * @brief  Clock Config.
00641   * @param  hsai: might be required to set audio peripheral predivider if any.
00642   * @param  AudioFreq: Audio frequency used to play the audio stream.
00643   * @param  Params: pointer on additional configuration parameters, can be NULL.
00644   * @note   This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency()
00645   *         Being __weak it can be overwritten by the application     
00646   */
00647 __weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params)
00648 { 
00649   RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
00650 
00651   HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
00652   
00653   /* Set the PLL configuration according to the audio frequency */
00654   if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K))
00655   {
00656     /* Configure PLLSAI prescalers */
00657     /* PLLSAI_VCO: VCO_429M 
00658     SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz
00659     SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ 
00660     rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
00661     rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI;
00662     rcc_ex_clk_init_struct.PLLSAI.PLLSAIM = 8; 
00663     rcc_ex_clk_init_struct.PLLSAI.PLLSAIN = 429; 
00664     rcc_ex_clk_init_struct.PLLSAI.PLLSAIQ = 2; 
00665     rcc_ex_clk_init_struct.PLLSAIDivQ = 19; 
00666     
00667     HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
00668     
00669   }
00670   else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */
00671   {
00672     /* SAI clock config 
00673     PLLSAI_VCO: VCO_344M 
00674     SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz 
00675     SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */  
00676     rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
00677     rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI;
00678     rcc_ex_clk_init_struct.PLLSAI.PLLSAIM = 8; 
00679     rcc_ex_clk_init_struct.PLLSAI.PLLSAIN = 344; 
00680     rcc_ex_clk_init_struct.PLLSAI.PLLSAIQ = 7; 
00681     rcc_ex_clk_init_struct.PLLSAIDivQ = 1;       
00682     
00683     HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
00684   }
00685 }
00686 
00687 /*******************************************************************************
00688                             Static Functions
00689 *******************************************************************************/
00690 
00691 /**
00692   * @brief  Initializes the Audio Codec audio interface (SAI).
00693   * @param  AudioFreq: Audio frequency to be configured for the SAI peripheral.
00694   * @note   The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 
00695   *         and user can update this configuration using 
00696   */
00697 static void SAIx_Init(uint32_t AudioFreq)
00698 {
00699   /* Initialize the hAudioOutSai Instance parameter */
00700   haudio_out_sai.Instance = AUDIO_SAIx;
00701   
00702   /* Disable SAI peripheral to allow access to SAI internal registers */
00703   __HAL_SAI_DISABLE(&haudio_out_sai);
00704   
00705   /* Configure SAI_Block_x 
00706   LSBFirst: Disabled 
00707   DataSize: 16 */
00708   haudio_out_sai.Init.AudioFrequency = AudioFreq;
00709   haudio_out_sai.Init.ClockSource = SAI_CLKSOURCE_PLLSAI;
00710   haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX;
00711   haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
00712   haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL;
00713   haudio_out_sai.Init.DataSize = SAI_DATASIZE_16;
00714   haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB;
00715   haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;
00716   haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS;
00717   haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
00718   haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
00719   
00720   /* Configure SAI_Block_x Frame 
00721   Frame Length: 64
00722   Frame active Length: 32
00723   FS Definition: Start frame + Channel Side identification
00724   FS Polarity: FS active Low
00725   FS Offset: FS asserted one bit before the first bit of slot 0 */ 
00726   haudio_out_sai.FrameInit.FrameLength = 64; 
00727   haudio_out_sai.FrameInit.ActiveFrameLength = 32;
00728   haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
00729   haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
00730   haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
00731   
00732   /* Configure SAI Block_x Slot 
00733   Slot First Bit Offset: 0
00734   Slot Size  : 16
00735   Slot Number: 4
00736   Slot Active: All slot actives */
00737   haudio_out_sai.SlotInit.FirstBitOffset = 0;
00738   haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
00739   haudio_out_sai.SlotInit.SlotNumber = 4; 
00740   haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123;
00741 
00742   HAL_SAI_Init(&haudio_out_sai);
00743   
00744   /* Enable SAI peripheral to generate MCLK */
00745   __HAL_SAI_ENABLE(&haudio_out_sai);
00746 }
00747 
00748 
00749 
00750 /**
00751   * @brief  Deinitializes the Audio Codec audio interface (SAI).
00752   */
00753 static void SAIx_DeInit(void)
00754 {
00755   /* Initialize the hAudioOutSai Instance parameter */
00756   haudio_out_sai.Instance = AUDIO_SAIx;
00757 
00758   /* Disable SAI peripheral */
00759   __HAL_SAI_DISABLE(&haudio_out_sai);
00760 
00761   HAL_SAI_DeInit(&haudio_out_sai);
00762 }
00763 
00764 
00765 /**
00766   * @}
00767   */
00768 
00769 /** @defgroup STM32446E_EVAL_AUDIO_in_Private_Functions STM32446E EVAL AUDIO IN Private Functions
00770   * @{
00771   */ 
00772   
00773 /**
00774   * @brief  Initializes wave recording.
00775   * @note   This function assumes that the I2S input clock (through PLL_R in 
00776   *         Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y)
00777   *         is already configured and ready to be used.  
00778   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral. 
00779   * @param  BitRes: Audio frequency to be configured for the I2S peripheral.
00780   * @param  ChnlNbr: Audio frequency to be configured for the I2S peripheral.
00781   * @retval AUDIO_OK if correct communication, else wrong communication
00782   */
00783 uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
00784 {
00785   RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
00786 
00787   I2Sx_DeInit();
00788   
00789   HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
00790   rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_I2S_APB1; /*SPI3 & TIM4 on APB1*/
00791   rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 384;
00792   rcc_ex_clk_init_struct.PLLI2S.PLLI2SR = 2;
00793   HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); 
00794   
00795   /* Configure the PDM library */
00796   PDMDecoder_Init(AudioFreq, ChnlNbr);
00797  
00798   /* Configure the I2S peripheral */
00799   haudio_in_i2s.Instance = AUDIO_I2Sx;
00800   if(HAL_I2S_GetState(&haudio_in_i2s) == HAL_I2S_STATE_RESET)
00801   { 
00802     /* Initialize the I2S Msp: this __weak function can be rewritten by the application */
00803     BSP_AUDIO_IN_MspInit(&haudio_in_i2s, NULL);
00804   }
00805   I2Sx_Init(AudioFreq);
00806 
00807   /* Return AUDIO_OK when all operations are correctly done */
00808   return AUDIO_OK;
00809 }
00810 
00811 /**
00812   * @brief  Starts audio recording.
00813   * @param  pbuf: Main buffer pointer for the recorded data storing  
00814   * @param  size: Current size of the recorded buffer
00815   * @retval AUDIO_OK if correct communication, else wrong communication
00816   */
00817 uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size)
00818 {
00819   uint32_t ret = AUDIO_ERROR;
00820   
00821   /* Start the process receive DMA */
00822   HAL_I2S_Receive_DMA(&haudio_in_i2s, pbuf, size);
00823   
00824   /* Return AUDIO_OK when all operations are correctly done */
00825   ret = AUDIO_OK;
00826   
00827   return ret;
00828 }
00829 
00830 /**
00831   * @brief  Stops audio recording.
00832   * @retval AUDIO_OK if correct communication, else wrong communication
00833   */
00834 uint8_t BSP_AUDIO_IN_Stop(void)
00835 {
00836   uint32_t ret = AUDIO_ERROR;
00837   
00838   /* Call the Media layer pause function */
00839   HAL_I2S_DMAPause(&haudio_in_i2s);  
00840   
00841   /* TIMx Peripheral clock disable */
00842   AUDIO_TIMx_CLK_DISABLE();
00843 
00844   /* Return AUDIO_OK when all operations are correctly done */
00845   ret = AUDIO_OK;
00846   
00847   return ret;
00848 }
00849 
00850 /**
00851   * @brief  Pauses the audio file stream.
00852   * @retval AUDIO_OK if correct communication, else wrong communication
00853   */
00854 uint8_t BSP_AUDIO_IN_Pause(void)
00855 {    
00856   /* Call the Media layer pause function */
00857   HAL_I2S_DMAPause(&haudio_in_i2s);
00858   
00859   /* Return AUDIO_OK when all operations are correctly done */
00860   return AUDIO_OK;
00861 }
00862 
00863 /**
00864   * @brief  Resumes the audio file stream.   
00865   * @retval AUDIO_OK if correct communication, else wrong communication
00866   */
00867 uint8_t BSP_AUDIO_IN_Resume(void)
00868 {    
00869   /* Call the Media layer pause/resume function */
00870   HAL_I2S_DMAResume(&haudio_in_i2s);
00871   
00872   /* Return AUDIO_OK when all operations are correctly done */
00873   return AUDIO_OK;
00874 }
00875 
00876 /**
00877   * @brief  Controls the audio in volume level. 
00878   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for 
00879   *         Mute and 100 for Max volume level).
00880   * @retval AUDIO_OK if correct communication, else wrong communication
00881   */
00882 uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume)
00883 {
00884   /* Set the Global variable AudioInVolume  */
00885   AudioInVolume = Volume; 
00886   
00887   /* Return AUDIO_OK when all operations are correctly done */
00888   return AUDIO_OK;
00889 }
00890 
00891 /**
00892   * @brief  Deinit the audio IN peripherals.
00893   */
00894 void BSP_AUDIO_IN_DeInit(void)
00895 {
00896   I2Sx_DeInit();
00897     /* DeInit the I2S MSP : this __weak function can be rewritten by the applic */
00898   BSP_AUDIO_IN_MspDeInit(&haudio_in_i2s, NULL);
00899   TIMx_DeInit();
00900 }
00901 
00902 /**
00903   * @brief  Converts audio format from PDM to PCM. 
00904   * @param  PDMBuf: Pointer to data PDM buffer
00905   * @param  PCMBuf: Pointer to data PCM buffer
00906   * @retval AUDIO_OK if correct communication, else wrong communication
00907   */
00908 uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t* PDMBuf, uint16_t* PCMBuf)
00909 {
00910   uint8_t app_pdm[INTERNAL_BUFF_SIZE*2];
00911   uint8_t byte1 = 0, byte2 = 0;
00912   uint32_t index = 0; 
00913   
00914   /* PDM Demux */
00915   for(index = 0; index<INTERNAL_BUFF_SIZE/2; index++)
00916   {
00917     byte2 = (PDMBuf[index] >> 8)& 0xFF;
00918     byte1 = (PDMBuf[index] & 0xFF);
00919     app_pdm[(index*2)+1] = Channel_Demux[byte1 & CHANNEL_DEMUX_MASK] | Channel_Demux[byte2 & CHANNEL_DEMUX_MASK] << 4;
00920     app_pdm[(index*2)] = Channel_Demux[(byte1 >> 1) & CHANNEL_DEMUX_MASK] | Channel_Demux[(byte2 >> 1) & CHANNEL_DEMUX_MASK] << 4;
00921   }
00922   
00923   for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++)
00924   {
00925     /* PDM to PCM filter */
00926     PDM_Filter_64_LSB((uint8_t*)&app_pdm[index], (uint16_t*)&(PCMBuf[index]), AudioInVolume , (PDMFilter_InitStruct *)&Filter[index]);
00927   }
00928     
00929   /* Return AUDIO_OK when all operations are correctly done */
00930   return AUDIO_OK; 
00931 }
00932 
00933  /**
00934   * @brief  Rx Transfer completed callbacks.
00935   * @param  hi2s: I2S handle
00936   */
00937 void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
00938 {
00939   /* Call the record update function to get the next buffer to fill and its size (size is ignored) */
00940   BSP_AUDIO_IN_TransferComplete_CallBack();
00941 }
00942 
00943 /**
00944   * @brief  Rx Half Transfer completed callbacks.
00945   * @param  hi2s: I2S handle
00946   */
00947 void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
00948 {
00949   /* Manage the remaining file size and new address offset: This function 
00950      should be coded by user (its prototype is already declared in stm32446e_eval_audio.h) */
00951   BSP_AUDIO_IN_HalfTransfer_CallBack();
00952 }
00953 
00954 /**
00955   * @brief  I2S error callbacks.
00956   * @param  hi2s: I2S handle
00957   */
00958 void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
00959 {
00960   /* Manage the error generated on DMA FIFO: This function 
00961      should be coded by user (its prototype is already declared in stm32446e_eval_audio.h) */
00962   BSP_AUDIO_IN_Error_Callback();
00963 }
00964 
00965 /**
00966   * @brief  User callback when record buffer is filled.
00967   */
00968 __weak void BSP_AUDIO_IN_TransferComplete_CallBack(void)
00969 {
00970   /* This function should be implemented by the user application.
00971      It is called into this driver when the current buffer is filled
00972      to prepare the next buffer pointer and its size. */
00973 }
00974 
00975 /**
00976   * @brief  Manages the DMA Half Transfer complete event.
00977   */
00978 __weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
00979 { 
00980   /* This function should be implemented by the user application.
00981      It is called into this driver when the current buffer is filled
00982      to prepare the next buffer pointer and its size. */
00983 }
00984 
00985 /**
00986   * @brief  Audio IN Error callback function.
00987   */
00988 __weak void BSP_AUDIO_IN_Error_Callback(void)
00989 {   
00990   /* This function is called when an Interrupt due to transfer error on or peripheral
00991      error occurs. */
00992 }
00993 
00994 /**
00995   * @brief  Initializes BSP_AUDIO_IN MSP.
00996   * @param  hi2s: I2S handle
00997   * @param  Params: pointer on additional configuration parameters, can be NULL.
00998   */
00999 __weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params)
01000 {
01001   static DMA_HandleTypeDef hdma_i2s_rx;
01002   GPIO_InitTypeDef  gpio_init_structure;  
01003 
01004   /* Configure the Timer which clocks the MEMS */
01005   /* Moved inside MSP to allow applic to redefine the TIMx_MspInit */
01006   TIMx_Init();
01007   
01008   /* Enable I2S clock */
01009   AUDIO_I2Sx_CLK_ENABLE();
01010   
01011   /* Enable SCK and SD GPIO clock */
01012   AUDIO_I2Sx_SD_GPIO_CLK_ENABLE();
01013   AUDIO_I2Sx_SCK_GPIO_CLK_ENABLE();
01014   /* CODEC_I2S pins configuration: SCK and SD pins */
01015   gpio_init_structure.Pin = AUDIO_I2Sx_SCK_PIN;
01016   gpio_init_structure.Mode = GPIO_MODE_AF_PP;
01017   gpio_init_structure.Pull = GPIO_NOPULL;
01018   gpio_init_structure.Speed = GPIO_SPEED_FAST;
01019   gpio_init_structure.Alternate = AUDIO_I2Sx_SCK_AF;
01020   HAL_GPIO_Init(AUDIO_I2Sx_SCK_GPIO_PORT, &gpio_init_structure);
01021   
01022   gpio_init_structure.Pin = AUDIO_I2Sx_SD_PIN;
01023   gpio_init_structure.Alternate = AUDIO_I2Sx_SD_AF;
01024   HAL_GPIO_Init(AUDIO_I2Sx_SD_GPIO_PORT, &gpio_init_structure); 
01025   
01026   /* Enable the DMA clock */
01027   AUDIO_I2Sx_DMAx_CLK_ENABLE();
01028     
01029   if(hi2s->Instance == AUDIO_I2Sx)
01030   {
01031     /* Configure the hdma_i2s_rx handle parameters */   
01032     hdma_i2s_rx.Init.Channel             = AUDIO_I2Sx_DMAx_CHANNEL;
01033     hdma_i2s_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
01034     hdma_i2s_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
01035     hdma_i2s_rx.Init.MemInc              = DMA_MINC_ENABLE;
01036     hdma_i2s_rx.Init.PeriphDataAlignment = AUDIO_I2Sx_DMAx_PERIPH_DATA_SIZE;
01037     hdma_i2s_rx.Init.MemDataAlignment    = AUDIO_I2Sx_DMAx_MEM_DATA_SIZE;
01038     hdma_i2s_rx.Init.Mode                = DMA_CIRCULAR;
01039     hdma_i2s_rx.Init.Priority            = DMA_PRIORITY_HIGH;
01040     hdma_i2s_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;         
01041     hdma_i2s_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
01042     hdma_i2s_rx.Init.MemBurst            = DMA_MBURST_SINGLE;
01043     hdma_i2s_rx.Init.PeriphBurst         = DMA_MBURST_SINGLE; 
01044     
01045     hdma_i2s_rx.Instance = AUDIO_I2Sx_DMAx_STREAM;
01046     
01047     /* Associate the DMA handle */
01048     __HAL_LINKDMA(hi2s, hdmarx, hdma_i2s_rx);
01049     
01050     /* Deinitialize the Stream for new transfer */
01051     HAL_DMA_DeInit(&hdma_i2s_rx);
01052     
01053     /* Configure the DMA Stream */
01054     HAL_DMA_Init(&hdma_i2s_rx);      
01055   }
01056   
01057   /* I2S DMA IRQ Channel configuration */
01058   HAL_NVIC_SetPriority(AUDIO_I2Sx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0);
01059   HAL_NVIC_EnableIRQ(AUDIO_I2Sx_DMAx_IRQ); 
01060 }
01061 
01062 /**
01063   * @brief  DeInitializes BSP_AUDIO_IN MSP.
01064   * @param  hi2s: I2S handle
01065   * @param  Params: pointer on additional configuration parameters, can be NULL.
01066   */
01067 __weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params)
01068 {
01069     GPIO_InitTypeDef  gpio_init_structure;  
01070 
01071     static DMA_HandleTypeDef hdma_i2s_rx;
01072 
01073     /* I2S DMA IRQ Channel deactivation */
01074     HAL_NVIC_DisableIRQ(AUDIO_I2Sx_DMAx_IRQ); 
01075     
01076     if(hi2s->Instance == AUDIO_I2Sx)
01077     {
01078       /* Deinitialize the Stream for new transfer */
01079       HAL_DMA_DeInit(&hdma_i2s_rx);
01080     }
01081 
01082    /* Disable I2S block */
01083     __HAL_I2S_DISABLE(hi2s);
01084 
01085     /* Disable pins: SCK and SD pins */
01086     gpio_init_structure.Pin = AUDIO_I2Sx_SCK_PIN;
01087     HAL_GPIO_DeInit(AUDIO_I2Sx_SCK_GPIO_PORT, gpio_init_structure.Pin);
01088     gpio_init_structure.Pin = AUDIO_I2Sx_SD_PIN;
01089     HAL_GPIO_DeInit(AUDIO_I2Sx_SD_GPIO_PORT, gpio_init_structure.Pin); 
01090 
01091     /* Disable I2S clock */
01092     AUDIO_I2Sx_CLK_DISABLE();
01093 
01094     /* GPIO pins clock and DMA clock can be shut down in the applic 
01095        by surcgarging this __weak function */ 
01096 }
01097 
01098 
01099 /*******************************************************************************
01100                             Static Functions
01101 *******************************************************************************/
01102 
01103 /**
01104   * @brief  Initializes the PDM library.
01105   * @param  AudioFreq: Audio sampling frequency
01106   * @param  ChnlNbr: Number of audio channels (1: mono; 2: stereo)
01107   */
01108 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr)
01109 { 
01110   uint32_t i = 0;
01111   
01112   /* Enable CRC peripheral to unlock the PDM library */
01113   __HAL_RCC_CRC_CLK_ENABLE();
01114   
01115   for(i = 0; i < ChnlNbr; i++)
01116   {
01117     /* Filter LP & HP Init */
01118     Filter[i].LP_HZ = AudioFreq/2;
01119     Filter[i].HP_HZ = 10;
01120     Filter[i].Fs = AudioFreq;
01121     Filter[i].Out_MicChannels = ChnlNbr;
01122     Filter[i].In_MicChannels = ChnlNbr; 
01123     PDM_Filter_Init((PDMFilter_InitStruct *)&Filter[i]);
01124   }  
01125 }
01126 
01127 /**
01128   * @brief  Initializes the Audio Codec audio interface (I2S)
01129   * @note   This function assumes that the I2S input clock (through PLL_R in 
01130   *         Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y)
01131   *         is already configured and ready to be used.    
01132   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral. 
01133   */
01134 static void I2Sx_Init(uint32_t AudioFreq)
01135 {
01136   /* Initialize the hAudioInI2s Instance parameter */
01137   haudio_in_i2s.Instance = AUDIO_I2Sx;
01138 
01139  /* Disable I2S block */
01140   __HAL_I2S_DISABLE(&haudio_in_i2s);
01141   
01142   /* I2S2 peripheral configuration */
01143   haudio_in_i2s.Init.AudioFreq = 4 * AudioFreq;
01144   haudio_in_i2s.Init.ClockSource = I2S_CLOCK_PLL;
01145   haudio_in_i2s.Init.CPOL = I2S_CPOL_HIGH;
01146   haudio_in_i2s.Init.DataFormat = I2S_DATAFORMAT_16B;
01147   haudio_in_i2s.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE;
01148   haudio_in_i2s.Init.Mode = I2S_MODE_MASTER_RX;
01149   haudio_in_i2s.Init.Standard = I2S_STANDARD_LSB;
01150   
01151   /* Init the I2S */
01152   HAL_I2S_Init(&haudio_in_i2s); 
01153 
01154  /* Disable I2S block */
01155   __HAL_I2S_ENABLE(&haudio_in_i2s);
01156 
01157 }
01158 
01159 /**
01160   * @brief  Deinitializes the Audio Codec audio interface (I2S).
01161   */
01162 static void I2Sx_DeInit(void)
01163 {
01164   /* Initialize the hAudioInI2s Instance parameter */
01165   haudio_in_i2s.Instance = AUDIO_I2Sx;
01166 
01167  /* Disable I2S block */
01168   __HAL_I2S_DISABLE(&haudio_in_i2s);
01169 
01170   /* DeInit the I2S */
01171   HAL_I2S_DeInit(&haudio_in_i2s); 
01172 }
01173 
01174 
01175 /**
01176   * @brief  Initializes the TIM INput Capture MSP.
01177   * @param  htim: TIM handle
01178   */
01179 static void TIMx_IC_MspInit(TIM_HandleTypeDef *htim)
01180 {
01181   GPIO_InitTypeDef   gpio_init_structure;
01182   
01183   /* Enable peripherals and GPIO Clocks --------------------------------------*/
01184   /* TIMx Peripheral clock enable */
01185   AUDIO_TIMx_CLK_ENABLE();
01186     
01187   /* Enable GPIO Channels Clock */
01188   AUDIO_TIMx_GPIO_CLK_ENABLE();
01189   
01190   /* Configure I/Os ----------------------------------------------------------*/
01191   /* Common configuration for all channels */
01192   gpio_init_structure.Mode = GPIO_MODE_AF_PP;
01193   gpio_init_structure.Pull = GPIO_NOPULL;
01194   gpio_init_structure.Speed = GPIO_SPEED_HIGH;
01195   gpio_init_structure.Alternate = AUDIO_TIMx_AF;
01196   
01197   /* Configure TIM input channel */
01198   gpio_init_structure.Pin = AUDIO_TIMx_IN_GPIO_PIN;
01199   HAL_GPIO_Init(AUDIO_TIMx_GPIO_PORT, &gpio_init_structure);
01200 
01201   /* Configure TIM output channel */
01202   gpio_init_structure.Pin = AUDIO_TIMx_OUT_GPIO_PIN;
01203   HAL_GPIO_Init(AUDIO_TIMx_GPIO_PORT, &gpio_init_structure);
01204 
01205 }
01206 
01207 /**
01208   * @brief  Initializes the TIM INput Capture MSP.
01209   * @param  htim: TIM handle
01210   */
01211 static void TIMx_IC_MspDeInit(TIM_HandleTypeDef *htim)
01212 {
01213     /* Disable TIMx Peripheral clock  */
01214     AUDIO_TIMx_CLK_DISABLE();
01215 
01216     /* GPIO pins clock and DMA clock can be shut down in the applic 
01217        by surcgarging this __weak function */ 
01218 }
01219 
01220 /**
01221   * @brief  Configure TIM as a clock divider by 2.
01222   *         I2S_SCK is externally connected to TIMx input channel
01223   */
01224 static void TIMx_Init(void)
01225 {
01226   TIM_IC_InitTypeDef     s_ic_config;
01227   TIM_OC_InitTypeDef     s_oc_config;
01228   TIM_ClockConfigTypeDef s_clk_source_config;
01229   TIM_SlaveConfigTypeDef s_slave_config;
01230   
01231   /* Configure the TIM peripheral --------------------------------------------*/
01232   /* Set TIMx instance */
01233   haudio_tim.Instance = AUDIO_TIMx;
01234   /* Timer Input Capture Configuration Structure declaration */
01235    /* Initialize TIMx peripheral as follow:
01236        + Period = 0xFFFF
01237        + Prescaler = 0
01238        + ClockDivision = 0
01239        + Counter direction = Up
01240   */
01241   haudio_tim.Init.Period        = 1;
01242   haudio_tim.Init.Prescaler     = 0;
01243   haudio_tim.Init.ClockDivision = 0;
01244   haudio_tim.Init.CounterMode   = TIM_COUNTERMODE_UP; 
01245   
01246   /* Initialize the TIMx peripheral with the structure above */
01247   TIMx_IC_MspInit(&haudio_tim);
01248   HAL_TIM_IC_Init(&haudio_tim);
01249   
01250   /* Configure the Input Capture channel -------------------------------------*/ 
01251   /* Configure the Input Capture of channel 2 */
01252   s_ic_config.ICPolarity  = TIM_ICPOLARITY_FALLING;
01253   s_ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI;
01254   s_ic_config.ICPrescaler = TIM_ICPSC_DIV1;
01255   s_ic_config.ICFilter    = 0;
01256   HAL_TIM_IC_ConfigChannel(&haudio_tim, &s_ic_config, AUDIO_TIMx_IN_CHANNEL);
01257   
01258   /* Select external clock mode 1 */
01259   s_clk_source_config.ClockSource = TIM_CLOCKSOURCE_ETRMODE1;
01260   s_clk_source_config.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;
01261   s_clk_source_config.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
01262   s_clk_source_config.ClockFilter = 0;   
01263   HAL_TIM_ConfigClockSource(&haudio_tim, &s_clk_source_config);
01264   
01265   /* Select Input Channel as input trigger */
01266   s_slave_config.InputTrigger = TIM_TS_TI1FP1;
01267   s_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
01268   s_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED;
01269   s_slave_config.TriggerPrescaler = TIM_CLOCKPRESCALER_DIV1;
01270   s_slave_config.TriggerFilter = 0;
01271   HAL_TIM_SlaveConfigSynchronization(&haudio_tim, &s_slave_config);
01272   
01273   /* Output Compare PWM Mode configuration: Channel2 */
01274   s_oc_config.OCMode = TIM_OCMODE_PWM1;
01275   s_oc_config.OCIdleState = TIM_OCIDLESTATE_SET;
01276   s_oc_config.Pulse = 1;
01277   s_oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
01278   s_oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
01279   s_oc_config.OCFastMode = TIM_OCFAST_DISABLE;
01280   s_oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET;
01281   
01282   /* Initialize the TIM4 Channel2 with the structure above */
01283   HAL_TIM_PWM_ConfigChannel(&haudio_tim, &s_oc_config, AUDIO_TIMx_OUT_CHANNEL);
01284   
01285   /* Start the TIM4 Channel2 */
01286   HAL_TIM_PWM_Start(&haudio_tim, AUDIO_TIMx_OUT_CHANNEL);
01287 
01288   /* Start the TIM4 Channel1 */
01289   HAL_TIM_IC_Start(&haudio_tim, AUDIO_TIMx_IN_CHANNEL);
01290 }
01291 
01292 /**
01293   * @brief  Configure TIM as a clock divider by 2.
01294   *         I2S_SCK is externally connected to TIMx input channel
01295   */
01296 static void TIMx_DeInit(void)
01297 {
01298   haudio_tim.Instance = AUDIO_TIMx;
01299   
01300   /* Stop the TIM4 Channel2 */
01301   HAL_TIM_PWM_Stop(&haudio_tim, AUDIO_TIMx_OUT_CHANNEL);
01302   /* Stop the TIM4 Channel1 */
01303   HAL_TIM_IC_Stop(&haudio_tim, AUDIO_TIMx_IN_CHANNEL);
01304 
01305   HAL_TIM_IC_DeInit(&haudio_tim);
01306   
01307   /* Initialize the TIMx peripheral with the structure above */
01308   TIMx_IC_MspDeInit(&haudio_tim);
01309 }
01310 
01311 /**
01312   * @}
01313   */ 
01314   
01315 /**
01316   * @}
01317   */
01318 
01319 /**
01320   * @}
01321   */
01322 
01323 /**
01324   * @}
01325   */ 
01326 
01327 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
Generated on Fri Jan 15 2016 10:06:21 for STM32446E_EVAL BSP User Manual by   doxygen 1.7.6.1