xref: /btstack/port/stm32-f4discovery-usb/bsp/stm32f4_discovery_audio.c (revision 98451c7b102094e15e0a72ca2f7098d91aed2017)
1 /**
2   ******************************************************************************
3   * @file    stm32f4_discovery_audio.c
4   * @author  MCD Application Team
5   * @version V2.1.2
6   * @date    27-January-2017
7   * @brief   This file provides the Audio driver for the STM32F4-Discovery
8   *          board.
9   ******************************************************************************
10   * @attention
11   *
12   * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
13   *
14   * Redistribution and use in source and binary forms, with or without modification,
15   * are permitted provided that the following conditions are met:
16   *   1. Redistributions of source code must retain the above copyright notice,
17   *      this list of conditions and the following disclaimer.
18   *   2. Redistributions in binary form must reproduce the above copyright notice,
19   *      this list of conditions and the following disclaimer in the documentation
20   *      and/or other materials provided with the distribution.
21   *   3. Neither the name of STMicroelectronics nor the names of its contributors
22   *      may be used to endorse or promote products derived from this software
23   *      without specific prior written permission.
24   *
25   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35   *
36   ******************************************************************************
37   */
38 
39 /*==============================================================================
40                                              User NOTES
41 1. How To use this driver:
42 --------------------------
43    - This driver supports STM32F4xx devices on STM32F4-Discovery Kit:
44         a) to play an audio file (all functions names start by BSP_AUDIO_OUT_xxx)
45         b) to record an audio file through MP45DT02, ST MEMS (all functions names start by AUDIO_IN_xxx)
46 
47 a) PLAY A FILE:
48 ==============
49    + Call the function BSP_AUDIO_OUT_Init(
50                                     OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER,
51                                                  OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_AUTO or
52                                                  OUTPUT_DEVICE_BOTH)
53                                     Volume: initial volume to be set (0 is min (mute), 100 is max (100%)
54                                     AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...)
55                                     this parameter is relative to the audio file/stream type.
56                                    )
57       This function configures all the hardware required for the audio application (codec, I2C, I2S,
58       GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK.
59       If the returned value is different from 0 or the function is stuck then the communication with
60       the codec (try to un-plug the power or reset device in this case).
61       - OUTPUT_DEVICE_SPEAKER: only speaker will be set as output for the audio stream.
62       - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream.
63       - OUTPUT_DEVICE_AUTO: Selection of output device is made through external switch (implemented
64          into the audio jack on the discovery board). When the Headphone is connected it is used
65          as output. When the headphone is disconnected from the audio jack, the output is
66          automatically switched to Speaker.
67       - OUTPUT_DEVICE_BOTH: both Speaker and Headphone are used as outputs for the audio stream
68          at the same time.
69    + Call the function BSP_AUDIO_OUT_Play(
70                                   pBuffer: pointer to the audio data file address
71                                   Size: size of the buffer to be sent in Bytes
72                                  )
73       to start playing (for the first time) from the audio file/stream.
74    + Call the function BSP_AUDIO_OUT_Pause() to pause playing
75    + Call the function BSP_AUDIO_OUT_Resume() to resume playing.
76        Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called
77           for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case).
78        Note. This function should be called only when the audio file is played or paused (not stopped).
79    + For each mode, you may need to implement the relative callback functions into your code.
80       The Callback functions are named BSP_AUDIO_OUT_XXXCallBack() and only their prototypes are declared in
81       the stm32f4_discovery_audio.h file. (refer to the example for more details on the callbacks implementations)
82    + To Stop playing, to modify the volume level, the frequency or to mute, use the functions
83        BSP_AUDIO_OUT_Stop(), BSP_AUDIO_OUT_SetVolume(), AUDIO_OUT_SetFrequency() BSP_AUDIO_OUT_SetOutputMode and BSP_AUDIO_OUT_SetMute().
84    + The driver API and the callback functions are at the end of the stm32f4_discovery_audio.h file.
85 
86 Driver architecture:
87 --------------------
88    + This driver provide the High Audio Layer: consists of the function API exported in the stm32f4_discovery_audio.h file
89        (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...)
90    + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/
91        providing the audio file/stream. These functions are also included as local functions into
92        the stm32f4_discovery_audio.c file (I2S3_Init()...)
93 
94 Known Limitations:
95 -------------------
96    1- When using the Speaker, if the audio file quality is not high enough, the speaker output
97       may produce high and uncomfortable noise level. To avoid this issue, to use speaker
98       output properly, try to increase audio file sampling rate (typically higher than 48KHz).
99       This operation will lead to larger file size.
100    2- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some
101       user interrupt routines (in this case, interrupts could be disabled just before the start of
102       communication then re-enabled when it is over). Note that this communication is only done at
103       the configuration phase (BSP_AUDIO_OUT_Init() or BSP_AUDIO_OUT_Stop()) and when Volume control modification is
104       performed (BSP_AUDIO_OUT_SetVolume() or BSP_AUDIO_OUT_SetMute()or BSP_AUDIO_OUT_SetOutputMode()).
105       When the audio data is played, no communication is required with the audio codec.
106    3- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size,
107       File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.
108    4- Supports only Stereo audio streaming. To play mono audio streams, each data should be sent twice
109       on the I2S or should be duplicated on the source buffer. Or convert the stream in stereo before playing.
110    5- Supports only 16-bits audio data size.
111 
112 b) RECORD A FILE:
113 ================
114    + Call the function BSP_AUDIO_IN_Init(
115                                     AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...)
116                                     )
117       This function configures all the hardware required for the audio application (I2S,
118       GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK.
119 
120    + Call the function BSP_AUDIO_IN_Record(
121                             pbuf Main buffer pointer for the recorded data storing
122                             size Current size of the recorded buffer
123                             )
124       to start recording from the microphone.
125 
126    + User needs to implement user callbacks to retrieve data saved in the record buffer
127       (AUDIO_IN_RxHalfCpltCallback/BSP_AUDIO_IN_ReceiveComplete_CallBack)
128 
129    + Call the function AUDIO_IN_STOP() to stop recording
130 
131 ==============================================================================*/
132 
133 /* Includes ------------------------------------------------------------------*/
134 #include "stm32f4_discovery_audio.h"
135 #include "pdm_filter.h"
136 #include "btstack_config.h"
137 
138 /** @addtogroup BSP
139   * @{
140   */
141 
142 /** @addtogroup STM32F4_DISCOVERY
143   * @{
144   */
145 
146 /** @defgroup STM32F4_DISCOVERY_AUDIO STM32F4 DISCOVERY AUDIO
147   * @brief This file includes the low layer audio driver available on STM32F4-Discovery
148   *        discovery board.
149   * @{
150   */
151 
152 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Types STM32F4 DISCOVERY AUDIO Private Types
153   * @{
154   */
155 /**
156   * @}
157   */
158 
159 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Defines STM32F4 DISCOVERY AUDIO Private Defines
160   * @{
161   */
162 /* These PLL parameters are valid when the f(VCO clock) = 1Mhz */
163 static const uint32_t I2SFreq[8] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000};
164 static const uint32_t I2SPLLN[8] = {256, 429, 213, 429, 426, 271, 258, 344};
165 static const uint32_t I2SPLLR[8] = {5, 4, 4, 4, 4, 6, 3, 1};
166 /**
167   * @}
168   */
169 
170 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Macros STM32F4 DISCOVERY AUDIO Private Macros
171   * @{
172   */
173 /**
174   * @}
175   */
176 
177 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Variables STM32F4 DISCOVERY AUDIO Private Variables
178   * @{
179   */
180 /*##### PLAY #####*/
181 static AUDIO_DrvTypeDef           *pAudioDrv;
182 I2S_HandleTypeDef                 hAudioOutI2s;
183 
184 /*### RECORDER ###*/
185 I2S_HandleTypeDef                 hAudioInI2s;
186 
187 static PDMFilter_InitStruct Filter[DEFAULT_AUDIO_IN_CHANNEL_NBR];
188 __IO uint16_t AudioInVolume = DEFAULT_AUDIO_IN_VOLUME;
189 /**
190   * @}
191   */
192 
193 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F4 DISCOVERY AUDIO Private Function Prototypes
194   * @{
195   */
196 static uint8_t I2S2_Init(uint32_t AudioFreq);
197 static uint8_t I2S3_Init(uint32_t AudioFreq);
198 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr);
199 
200 /**
201   * @}
202   */
203 
204 /** @defgroup STM32F4_DISCOVERY_AUDIO_OUT_Private_Functions STM32F4 DISCOVERY AUDIO OUT Private Functions
205   * @{
206   */
207 
208 /**
209   * @brief  Configures the audio peripherals.
210   * @param  OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
211   *                       OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO .
212   * @param  Volume: Initial volume level (from 0 (Mute) to 100 (Max))
213   * @param  AudioFreq: Audio frequency used to play the audio stream.
214   * @retval AUDIO_OK if correct communication, else wrong communication
215   */
216 uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
217 {
218   uint8_t ret = AUDIO_OK;
219 
220   /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
221   BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL);
222 
223   /* I2S data transfer preparation:
224   Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
225   hAudioOutI2s.Instance = I2S3;
226   if(HAL_I2S_GetState(&hAudioOutI2s) == HAL_I2S_STATE_RESET)
227   {
228     /* Init the I2S MSP: this __weak function can be redefined by the application*/
229     BSP_AUDIO_OUT_MspInit(&hAudioOutI2s, NULL);
230   }
231 
232   /* I2S data transfer preparation:
233   Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
234   /* Configure the I2S peripheral */
235   if(I2S3_Init(AudioFreq) != AUDIO_OK)
236   {
237     ret = AUDIO_ERROR;
238   }
239 
240   if(ret == AUDIO_OK)
241   {
242     /* Retieve audio codec identifier */
243     if(((cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS)) & CS43L22_ID_MASK) == CS43L22_ID)
244     {
245       /* Initialize the audio driver structure */
246       pAudioDrv = &cs43l22_drv;
247     }
248     else
249     {
250       ret = AUDIO_ERROR;
251     }
252   }
253 
254   if(ret == AUDIO_OK)
255   {
256     pAudioDrv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq);
257   }
258 
259   return ret;
260 }
261 
262 /**
263   * @brief  Starts playing audio stream from a data buffer for a determined size.
264   * @param  pBuffer: Pointer to the buffer
265   * @param  Size: Number of audio data BYTES.
266   * @retval AUDIO_OK if correct communication, else wrong communication
267   */
268 uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
269 {
270   /* Call the audio Codec Play function */
271   if(pAudioDrv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0)
272   {
273     return AUDIO_ERROR;
274   }
275   else
276   {
277     /* Update the Media layer and enable it for play */
278     HAL_I2S_Transmit_DMA(&hAudioOutI2s, pBuffer, DMA_MAX(Size/AUDIODATA_SIZE));
279 
280     /* Return AUDIO_OK when all operations are correctly done */
281     return AUDIO_OK;
282   }
283 }
284 
285 /**
286   * @brief  Sends n-Bytes on the I2S interface.
287   * @param  pData: Pointer to data address
288   * @param  Size: Number of data to be written
289   */
290 void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
291 {
292   HAL_I2S_Transmit_DMA(&hAudioOutI2s, pData, Size);
293 }
294 
295 /**
296   * @brief   Pauses the audio file stream. In case of using DMA, the DMA Pause
297   *          feature is used.
298   * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only the
299   *          BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play()
300   *          function for resume could lead to unexpected behavior).
301   * @retval  AUDIO_OK if correct communication, else wrong communication
302   */
303 uint8_t BSP_AUDIO_OUT_Pause(void)
304 {
305   /* Call the Audio Codec Pause/Resume function */
306   if(pAudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0)
307   {
308     return AUDIO_ERROR;
309   }
310   else
311   {
312     /* Call the Media layer pause function */
313     HAL_I2S_DMAPause(&hAudioOutI2s);
314 
315     /* Return AUDIO_OK when all operations are correctly done */
316     return AUDIO_OK;
317   }
318 }
319 
320 /**
321   * @brief   Resumes the audio file streaming.
322   * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only
323   *          BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play()
324   *          function for resume could lead to unexpected behavior).
325   * @retval  AUDIO_OK if correct communication, else wrong communication
326   */
327 uint8_t BSP_AUDIO_OUT_Resume(void)
328 {
329   /* Call the Audio Codec Pause/Resume function */
330   if(pAudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0)
331   {
332     return AUDIO_ERROR;
333   }
334   else
335   {
336     /* Call the Media layer resume function */
337     HAL_I2S_DMAResume(&hAudioOutI2s);
338 
339     /* Return AUDIO_OK when all operations are correctly done */
340     return AUDIO_OK;
341   }
342 }
343 
344 /**
345   * @brief  Stops audio playing and Power down the Audio Codec.
346   * @param  Option: could be one of the following parameters
347   *           - CODEC_PDWN_HW: completely shut down the codec (physically).
348   *                            Then need to reconfigure the Codec after power on.
349   * @retval AUDIO_OK if correct communication, else wrong communication
350   */
351 uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
352 {
353   /* Call DMA Stop to disable DMA stream before stopping codec */
354   HAL_I2S_DMAStop(&hAudioOutI2s);
355 
356   /* Call Audio Codec Stop function */
357   if(pAudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
358   {
359     return AUDIO_ERROR;
360   }
361   else
362   {
363     if(Option == CODEC_PDWN_HW)
364     {
365       /* Wait at least 1ms */
366       HAL_Delay(1);
367 
368       /* Reset the pin */
369       HAL_GPIO_WritePin(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, GPIO_PIN_RESET);
370     }
371 
372     /* Return AUDIO_OK when all operations are correctly done */
373     return AUDIO_OK;
374   }
375 }
376 
377 /**
378   * @brief  Controls the current audio volume level.
379   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for
380   *         Mute and 100 for Max volume level).
381   * @retval AUDIO_OK if correct communication, else wrong communication
382   */
383 uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
384 {
385   /* Call the codec volume control function with converted volume value */
386   if(pAudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
387   {
388     return AUDIO_ERROR;
389   }
390   else
391   {
392     /* Return AUDIO_OK when all operations are correctly done */
393     return AUDIO_OK;
394   }
395 }
396 
397 /**
398   * @brief  Enables or disables the MUTE mode by software
399   * @param  Cmd: could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to
400   *         unmute the codec and restore previous volume level.
401   * @retval AUDIO_OK if correct communication, else wrong communication
402   */
403 uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
404 {
405   /* Call the Codec Mute function */
406   if(pAudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
407   {
408     return AUDIO_ERROR;
409   }
410   else
411   {
412     /* Return AUDIO_OK when all operations are correctly done */
413     return AUDIO_OK;
414   }
415 }
416 
417 /**
418   * @brief  Switch dynamically (while audio file is played) the output target
419   *         (speaker or headphone).
420   * @note   This function modifies a global variable of the audio codec driver: OutputDev.
421   * @param  Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER,
422   *         OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO
423   * @retval AUDIO_OK if correct communication, else wrong communication
424   */
425 uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
426 {
427   /* Call the Codec output Device function */
428   if(pAudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
429   {
430     return AUDIO_ERROR;
431   }
432   else
433   {
434     /* Return AUDIO_OK when all operations are correctly done */
435     return AUDIO_OK;
436   }
437 }
438 
439 /**
440   * @brief  Update the audio frequency.
441   * @param  AudioFreq: Audio frequency used to play the audio stream.
442   * @note   This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
443   *         audio frequency.
444   */
445 void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
446 {
447   /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
448   BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL);
449 
450   /* Update the I2S audio frequency configuration */
451   I2S3_Init(AudioFreq);
452 }
453 
454 /**
455   * @brief  Tx Transfer completed callbacks.
456   * @param  hi2s: I2S handle
457   */
458 void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
459 {
460   if(hi2s->Instance == I2S3)
461   {
462     /* Call the user function which will manage directly transfer complete */
463     BSP_AUDIO_OUT_TransferComplete_CallBack();
464   }
465 }
466 
467 /**
468   * @brief  Tx Half Transfer completed callbacks.
469   * @param  hi2s: I2S handle
470   */
471 void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
472 {
473   if(hi2s->Instance == I2S3)
474   {
475     /* Manage the remaining file size and new address offset: This function should
476        be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */
477     BSP_AUDIO_OUT_HalfTransfer_CallBack();
478   }
479 }
480 
481 /**
482   * @brief  Clock Config.
483   * @param  hi2s: might be required to set audio peripheral predivider if any.
484   * @param  AudioFreq: Audio frequency used to play the audio stream.
485   * @note   This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency()
486   *         Being __weak it can be overwritten by the application
487   * @param  Params : pointer on additional configuration parameters, can be NULL.
488   */
489 __weak void BSP_AUDIO_OUT_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params)
490 {
491   RCC_PeriphCLKInitTypeDef rccclkinit;
492   uint8_t index = 0, freqindex = 0xFF;
493 
494   for(index = 0; index < 8; index++)
495   {
496     if(I2SFreq[index] == AudioFreq)
497     {
498       freqindex = index;
499     }
500   }
501   /* Enable PLLI2S clock */
502   HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit);
503   /* PLLI2S_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
504 
505   // BK use table if frequency found in table, otherwise use same settings as for 48 kHz
506   if (freqindex != 0xFF)
507   {
508     /* I2S clock config
509     PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) � (PLLI2SN/PLLM)
510     I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
511     rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S;
512     rccclkinit.PLLI2S.PLLI2SN = I2SPLLN[freqindex];
513     rccclkinit.PLLI2S.PLLI2SR = I2SPLLR[freqindex];
514     HAL_RCCEx_PeriphCLKConfig(&rccclkinit);
515   }
516   else
517   {
518     /* I2S clock config
519     PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) � (PLLI2SN/PLLM)
520     I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
521     rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S;
522     rccclkinit.PLLI2S.PLLI2SN = 258;
523     rccclkinit.PLLI2S.PLLI2SR = 3;
524     HAL_RCCEx_PeriphCLKConfig(&rccclkinit);
525   }
526 }
527 
528 /**
529   * @brief  AUDIO OUT I2S MSP Init.
530   * @param  hi2s: might be required to set audio peripheral predivider if any.
531   * @param  Params : pointer on additional configuration parameters, can be NULL.
532   */
533 __weak void BSP_AUDIO_OUT_MspInit(I2S_HandleTypeDef *hi2s, void *Params)
534 {
535   static DMA_HandleTypeDef hdma_i2sTx;
536   GPIO_InitTypeDef  GPIO_InitStruct;
537 
538   /* Enable I2S3 clock */
539   I2S3_CLK_ENABLE();
540 
541   /*** Configure the GPIOs ***/
542   /* Enable I2S GPIO clocks */
543   I2S3_SCK_SD_CLK_ENABLE();
544   I2S3_WS_CLK_ENABLE();
545 
546   /* I2S3 pins configuration: WS, SCK and SD pins ----------------------------*/
547   GPIO_InitStruct.Pin         = I2S3_SCK_PIN | I2S3_SD_PIN;
548   GPIO_InitStruct.Mode        = GPIO_MODE_AF_PP;
549   GPIO_InitStruct.Pull        = GPIO_NOPULL;
550   GPIO_InitStruct.Speed       = GPIO_SPEED_FAST;
551   GPIO_InitStruct.Alternate   = I2S3_SCK_SD_WS_AF;
552   HAL_GPIO_Init(I2S3_SCK_SD_GPIO_PORT, &GPIO_InitStruct);
553 
554   GPIO_InitStruct.Pin         = I2S3_WS_PIN ;
555   HAL_GPIO_Init(I2S3_WS_GPIO_PORT, &GPIO_InitStruct);
556 
557   /* I2S3 pins configuration: MCK pin */
558   I2S3_MCK_CLK_ENABLE();
559   GPIO_InitStruct.Pin         = I2S3_MCK_PIN;
560   HAL_GPIO_Init(I2S3_MCK_GPIO_PORT, &GPIO_InitStruct);
561 
562   /* Enable the I2S DMA clock */
563   I2S3_DMAx_CLK_ENABLE();
564 
565   if(hi2s->Instance == I2S3)
566   {
567     /* Configure the hdma_i2sTx handle parameters */
568     hdma_i2sTx.Init.Channel             = I2S3_DMAx_CHANNEL;
569     hdma_i2sTx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
570     hdma_i2sTx.Init.PeriphInc           = DMA_PINC_DISABLE;
571     hdma_i2sTx.Init.MemInc              = DMA_MINC_ENABLE;
572     hdma_i2sTx.Init.PeriphDataAlignment = I2S3_DMAx_PERIPH_DATA_SIZE;
573     hdma_i2sTx.Init.MemDataAlignment    = I2S3_DMAx_MEM_DATA_SIZE;
574     hdma_i2sTx.Init.Mode                = DMA_NORMAL;
575 
576     // BK: use circular DMA for hal_audio.h
577 #ifdef HAVE_HAL_AUDIO
578     hdma_i2sTx.Init.Mode                = DMA_CIRCULAR;
579 #endif
580     // BK: use circular DMA (end)
581 
582     hdma_i2sTx.Init.Priority            = DMA_PRIORITY_HIGH;
583     hdma_i2sTx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
584     hdma_i2sTx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
585     hdma_i2sTx.Init.MemBurst            = DMA_MBURST_SINGLE;
586     hdma_i2sTx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
587 
588     hdma_i2sTx.Instance                 = I2S3_DMAx_STREAM;
589 
590     /* Associate the DMA handle */
591     __HAL_LINKDMA(hi2s, hdmatx, hdma_i2sTx);
592 
593     /* Deinitialize the Stream for new transfer */
594     HAL_DMA_DeInit(&hdma_i2sTx);
595 
596     /* Configure the DMA Stream */
597     HAL_DMA_Init(&hdma_i2sTx);
598   }
599 
600   /* I2S DMA IRQ Channel configuration */
601   HAL_NVIC_SetPriority(I2S3_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
602   HAL_NVIC_EnableIRQ(I2S3_DMAx_IRQ);
603 }
604 
605 /**
606   * @brief  De-Initializes BSP_AUDIO_OUT MSP.
607   * @param  hi2s: might be required to set audio peripheral predivider if any.
608   * @param  Params : pointer on additional configuration parameters, can be NULL.
609   */
610 __weak void BSP_AUDIO_OUT_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params)
611 {
612   GPIO_InitTypeDef  GPIO_InitStruct;
613 
614   /* I2S DMA IRQ Channel deactivation */
615   HAL_NVIC_DisableIRQ(I2S3_DMAx_IRQ);
616 
617   if(hi2s->Instance == I2S3)
618   {
619     /* Deinitialize the Stream for new transfer */
620     HAL_DMA_DeInit(hi2s->hdmatx);
621   }
622 
623  /* Disable I2S block */
624   __HAL_I2S_DISABLE(hi2s);
625 
626   /* CODEC_I2S pins configuration: SCK and SD pins */
627   GPIO_InitStruct.Pin = I2S3_SCK_PIN | I2S3_SD_PIN;
628   HAL_GPIO_DeInit(I2S3_SCK_SD_GPIO_PORT, GPIO_InitStruct.Pin);
629 
630   /* CODEC_I2S pins configuration: WS pin */
631   GPIO_InitStruct.Pin = I2S3_WS_PIN;
632   HAL_GPIO_DeInit(I2S3_WS_GPIO_PORT, GPIO_InitStruct.Pin);
633 
634   /* CODEC_I2S pins configuration: MCK pin */
635   GPIO_InitStruct.Pin = I2S3_MCK_PIN;
636   HAL_GPIO_DeInit(I2S3_MCK_GPIO_PORT, GPIO_InitStruct.Pin);
637 
638   /* Disable I2S clock */
639   I2S3_CLK_DISABLE();
640 
641   /* GPIO pins clock and DMA clock can be shut down in the applic
642      by surcgarging this __weak function */
643 }
644 
645 /**
646   * @brief  Manages the DMA full Transfer complete event.
647   */
648 __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
649 {
650 }
651 
652 /**
653   * @brief  Manages the DMA Half Transfer complete event.
654   */
655 __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
656 {
657 }
658 
659 /**
660   * @brief  Manages the DMA FIFO error event.
661   */
662 __weak void BSP_AUDIO_OUT_Error_CallBack(void)
663 {
664 }
665 
666 /*******************************************************************************
667                             Static Functions
668 *******************************************************************************/
669 
670 /**
671   * @brief  Initializes the Audio Codec audio interface (I2S).
672   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral.
673   */
674 static uint8_t I2S3_Init(uint32_t AudioFreq)
675 {
676   /* Initialize the hAudioOutI2s Instance parameter */
677   hAudioOutI2s.Instance         = I2S3;
678 
679  /* Disable I2S block */
680   __HAL_I2S_DISABLE(&hAudioOutI2s);
681 
682   /* I2S3 peripheral configuration */
683   hAudioOutI2s.Init.AudioFreq   = AudioFreq;
684   hAudioOutI2s.Init.ClockSource = I2S_CLOCK_PLL;
685   hAudioOutI2s.Init.CPOL        = I2S_CPOL_LOW;
686   hAudioOutI2s.Init.DataFormat  = I2S_DATAFORMAT_16B;
687   hAudioOutI2s.Init.MCLKOutput  = I2S_MCLKOUTPUT_ENABLE;
688   hAudioOutI2s.Init.Mode        = I2S_MODE_MASTER_TX;
689   hAudioOutI2s.Init.Standard    = I2S_STANDARD;
690   /* Initialize the I2S peripheral with the structure above */
691   if(HAL_I2S_Init(&hAudioOutI2s) != HAL_OK)
692   {
693     return AUDIO_ERROR;
694   }
695   else
696   {
697     return AUDIO_OK;
698   }
699 }
700 
701 /**
702   * @}
703   */
704 
705 /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_Private_Functions STM32F4 DISCOVERY AUDIO IN Private Functions
706   * @{
707   */
708 
709 /**
710   * @brief  Initializes wave recording.
711   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral.
712   * @param  BitRes: Audio frequency to be configured for the I2S peripheral.
713   * @param  ChnlNbr: Audio frequency to be configured for the I2S peripheral.
714   * @retval AUDIO_OK if correct communication, else wrong communication
715   */
716 uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
717 {
718 
719 #if 0
720   // BK: only do PLL clock configuration in sink
721   /* Configure PLL clock */
722   BSP_AUDIO_IN_ClockConfig(&hAudioInI2s, AudioFreq, NULL);
723 #endif
724 
725   /* Configure the PDM library */
726   PDMDecoder_Init(AudioFreq, ChnlNbr);
727 
728   /* Configure the I2S peripheral */
729   hAudioInI2s.Instance = I2S2;
730   if(HAL_I2S_GetState(&hAudioInI2s) == HAL_I2S_STATE_RESET)
731   {
732     /* Initialize the I2S Msp: this __weak function can be rewritten by the application */
733     BSP_AUDIO_IN_MspInit(&hAudioInI2s, NULL);
734   }
735 
736   /* Configure the I2S2 */
737   I2S2_Init(AudioFreq);
738 
739   /* Return AUDIO_OK when all operations are correctly done */
740   return AUDIO_OK;
741 }
742 
743 /**
744   * @brief  Starts audio recording.
745   * @param  pbuf: Main buffer pointer for the recorded data storing
746   * @param  size: Current size of the recorded buffer
747   * @retval AUDIO_OK if correct communication, else wrong communication
748   */
749 uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size)
750 {
751   uint32_t ret = AUDIO_ERROR;
752 
753   /* Start the process receive DMA */
754   HAL_I2S_Receive_DMA(&hAudioInI2s, pbuf, size);
755 
756   /* Return AUDIO_OK when all operations are correctly done */
757   ret = AUDIO_OK;
758 
759   return ret;
760 }
761 
762 /**
763   * @brief  Stops audio recording.
764   * @retval AUDIO_OK if correct communication, else wrong communication
765   */
766 uint8_t BSP_AUDIO_IN_Stop(void)
767 {
768   uint32_t ret = AUDIO_ERROR;
769 
770   /* Call the Media layer pause function */
771   HAL_I2S_DMAStop(&hAudioInI2s);
772 
773   /* Return AUDIO_OK when all operations are correctly done */
774   ret = AUDIO_OK;
775 
776   return ret;
777 }
778 
779 /**
780   * @brief  Pauses the audio file stream.
781   * @retval AUDIO_OK if correct communication, else wrong communication
782   */
783 uint8_t BSP_AUDIO_IN_Pause(void)
784 {
785   /* Call the Media layer pause function */
786   HAL_I2S_DMAPause(&hAudioInI2s);
787 
788   /* Return AUDIO_OK when all operations are correctly done */
789   return AUDIO_OK;
790 }
791 
792 /**
793   * @brief  Resumes the audio file stream.
794   * @retval AUDIO_OK if correct communication, else wrong communication
795   */
796 uint8_t BSP_AUDIO_IN_Resume(void)
797 {
798   /* Call the Media layer pause/resume function */
799   HAL_I2S_DMAResume(&hAudioInI2s);
800 
801   /* Return AUDIO_OK when all operations are correctly done */
802   return AUDIO_OK;
803 }
804 
805 /**
806   * @brief  Controls the audio in volume level.
807   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for
808   *         Mute and 100 for Max volume level).
809   * @retval AUDIO_OK if correct communication, else wrong communication
810   */
811 uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume)
812 {
813   /* Set the Global variable AudioInVolume */
814   AudioInVolume = Volume;
815 
816   /* Return AUDIO_OK when all operations are correctly done */
817   return AUDIO_OK;
818 }
819 
820 /**
821   * @brief  Converts audio format from PDM to PCM.
822   * @param  PDMBuf: Pointer to data PDM buffer
823   * @param  PCMBuf: Pointer to data PCM buffer
824   * @retval AUDIO_OK if correct communication, else wrong communication
825   */
826 uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t *PDMBuf, uint16_t *PCMBuf)
827 {
828   uint16_t AppPDM[INTERNAL_BUFF_SIZE/2];
829   uint32_t index = 0;
830 
831   /* PDM Demux */
832   for(index = 0; index<INTERNAL_BUFF_SIZE/2; index++)
833   {
834     AppPDM[index] = HTONS(PDMBuf[index]);
835   }
836 
837   for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++)
838   {
839     /* PDM to PCM filter */
840     PDM_Filter_64_LSB((uint8_t*)&AppPDM[index], (uint16_t*)&(PCMBuf[index]), AudioInVolume , (PDMFilter_InitStruct *)&Filter[index]);
841   }
842 #if 0
843   // BK - generate mono output
844 
845   /* Duplicate samples since a single microphone in mounted on STM32F4-Discovery */
846   for(index = 0; index < PCM_OUT_SIZE; index++)
847   {
848     PCMBuf[(index<<1)+1] = PCMBuf[index<<1];
849   }
850 #endif
851 
852   /* Return AUDIO_OK when all operations are correctly done */
853   return AUDIO_OK;
854 }
855 
856 /**
857   * @brief  Rx Transfer completed callbacks
858   * @param  hi2s: I2S handle
859   */
860 void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
861 {
862   /* Call the record update function to get the next buffer to fill and its size (size is ignored) */
863   BSP_AUDIO_IN_TransferComplete_CallBack();
864 }
865 
866 /**
867   * @brief  Rx Half Transfer completed callbacks.
868   * @param  hi2s: I2S handle
869   */
870 void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
871 {
872   /* Manage the remaining file size and new address offset: This function
873      should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */
874   BSP_AUDIO_IN_HalfTransfer_CallBack();
875 }
876 
877 /**
878   * @brief  Audio In Clock Config.
879   * @param  hi2s: I2S handle
880   * @param  AudioFreq: Audio frequency used to record the audio stream.
881   * @param  Params : pointer on additional configuration parameters, can be NULL.
882   * @note   This API is called by BSP_AUDIO_IN_Init()
883   *         Being __weak it can be overwritten by the application
884   */
885 __weak void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params)
886 {
887   RCC_PeriphCLKInitTypeDef rccclkinit;
888 
889   /*Enable PLLI2S clock*/
890   HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit);
891   /* PLLI2S_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
892   if ((AudioFreq & 0x7) == 0)
893   {
894     /* Audio frequency multiple of 8 (8/16/32/48/96/192)*/
895     /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN = 192 Mhz */
896     /* I2SCLK = PLLI2S_VCO Output/PLLI2SR = 192/6 = 32 Mhz */
897     rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S;
898     rccclkinit.PLLI2S.PLLI2SN = 192;
899     rccclkinit.PLLI2S.PLLI2SR = 6;
900     HAL_RCCEx_PeriphCLKConfig(&rccclkinit);
901   }
902   else
903   {
904     /* Other Frequency (11.025/22.500/44.100) */
905     /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN = 290 Mhz */
906     /* I2SCLK = PLLI2S_VCO Output/PLLI2SR = 290/2 = 145 Mhz */
907     rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S;
908     rccclkinit.PLLI2S.PLLI2SN = 290;
909     rccclkinit.PLLI2S.PLLI2SR = 2;
910     HAL_RCCEx_PeriphCLKConfig(&rccclkinit);
911   }
912 }
913 
914 /**
915   * @brief  BSP AUDIO IN MSP Init.
916   * @param  hi2s: I2S handle
917   * @param  Params : pointer on additional configuration parameters, can be NULL.
918   */
919 __weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params)
920 {
921   static DMA_HandleTypeDef hdma_i2sRx;
922   GPIO_InitTypeDef  GPIO_InitStruct;
923 
924   /* Enable the I2S2 peripheral clock */
925   I2S2_CLK_ENABLE();
926 
927   /* Enable I2S GPIO clocks */
928   I2S2_SCK_GPIO_CLK_ENABLE();
929   I2S2_MOSI_GPIO_CLK_ENABLE();
930 
931   /* I2S2 pins configuration: SCK and MOSI pins ------------------------------*/
932   GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
933   GPIO_InitStruct.Pull      = GPIO_NOPULL;
934   GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;
935 
936   GPIO_InitStruct.Pin       = I2S2_SCK_PIN;
937   GPIO_InitStruct.Alternate = I2S2_SCK_AF;
938   HAL_GPIO_Init(I2S2_SCK_GPIO_PORT, &GPIO_InitStruct);
939 
940   GPIO_InitStruct.Pin       = I2S2_MOSI_PIN ;
941   GPIO_InitStruct.Alternate = I2S2_MOSI_AF;
942   HAL_GPIO_Init(I2S2_MOSI_GPIO_PORT, &GPIO_InitStruct);
943 
944   /* Enable the DMA clock */
945   I2S2_DMAx_CLK_ENABLE();
946 
947   if(hi2s->Instance == I2S2)
948   {
949     /* Configure the hdma_i2sRx handle parameters */
950     hdma_i2sRx.Init.Channel             = I2S2_DMAx_CHANNEL;
951     hdma_i2sRx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
952     hdma_i2sRx.Init.PeriphInc           = DMA_PINC_DISABLE;
953     hdma_i2sRx.Init.MemInc              = DMA_MINC_ENABLE;
954     hdma_i2sRx.Init.PeriphDataAlignment = I2S2_DMAx_PERIPH_DATA_SIZE;
955     hdma_i2sRx.Init.MemDataAlignment    = I2S2_DMAx_MEM_DATA_SIZE;
956     hdma_i2sRx.Init.Mode                = DMA_CIRCULAR;
957     hdma_i2sRx.Init.Priority            = DMA_PRIORITY_HIGH;
958     hdma_i2sRx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
959     hdma_i2sRx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
960     hdma_i2sRx.Init.MemBurst            = DMA_MBURST_SINGLE;
961     hdma_i2sRx.Init.PeriphBurst         = DMA_MBURST_SINGLE;
962 
963     hdma_i2sRx.Instance = I2S2_DMAx_STREAM;
964 
965     /* Associate the DMA handle */
966     __HAL_LINKDMA(hi2s, hdmarx, hdma_i2sRx);
967 
968     /* Deinitialize the Stream for new transfer */
969     HAL_DMA_DeInit(&hdma_i2sRx);
970 
971     /* Configure the DMA Stream */
972     HAL_DMA_Init(&hdma_i2sRx);
973   }
974 
975   /* I2S DMA IRQ Channel configuration */
976   HAL_NVIC_SetPriority(I2S2_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0);
977   HAL_NVIC_EnableIRQ(I2S2_DMAx_IRQ);
978 }
979 
980 /**
981   * @brief  DeInitializes BSP_AUDIO_IN MSP.
982   * @param  hi2s: I2S handle
983   * @param  Params : pointer on additional configuration parameters, can be NULL.
984   */
985 __weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params)
986 {
987   GPIO_InitTypeDef  gpio_init_structure;
988 
989   /* I2S DMA IRQ Channel deactivation */
990   HAL_NVIC_DisableIRQ(I2S2_DMAx_IRQ);
991 
992   if(hi2s->Instance == I2S2)
993   {
994     /* Deinitialize the Stream for new transfer */
995     HAL_DMA_DeInit(hi2s->hdmarx);
996   }
997 
998  /* Disable I2S block */
999   __HAL_I2S_DISABLE(hi2s);
1000 
1001   /* Disable pins: SCK and SD pins */
1002   gpio_init_structure.Pin = I2S2_SCK_PIN;
1003   HAL_GPIO_DeInit(I2S2_SCK_GPIO_PORT, gpio_init_structure.Pin);
1004   gpio_init_structure.Pin = I2S2_MOSI_PIN;
1005   HAL_GPIO_DeInit(I2S2_MOSI_GPIO_PORT, gpio_init_structure.Pin);
1006 
1007   /* Disable I2S clock */
1008   I2S2_CLK_DISABLE();
1009 
1010   /* GPIO pins clock and DMA clock can be shut down in the applic
1011      by surcgarging this __weak function */
1012 }
1013 
1014 /**
1015   * @brief  User callback when record buffer is filled.
1016   */
1017 __weak void BSP_AUDIO_IN_TransferComplete_CallBack(void)
1018 {
1019   /* This function should be implemented by the user application.
1020      It is called into this driver when the current buffer is filled
1021      to prepare the next buffer pointer and its size. */
1022 }
1023 
1024 /**
1025   * @brief  Manages the DMA Half Transfer complete event.
1026   */
1027 __weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
1028 {
1029   /* This function should be implemented by the user application.
1030      It is called into this driver when the current buffer is filled
1031      to prepare the next buffer pointer and its size. */
1032 }
1033 
1034 /**
1035   * @brief  Audio IN Error callback function.
1036   */
1037 __weak void BSP_AUDIO_IN_Error_Callback(void)
1038 {
1039   /* This function is called when an Interrupt due to transfer error on or peripheral
1040      error occurs. */
1041 }
1042 
1043 /*******************************************************************************
1044                             Static Functions
1045 *******************************************************************************/
1046 
1047 /**
1048   * @brief  Initialize the PDM library.
1049   * @param  AudioFreq: Audio sampling frequency
1050   * @param  ChnlNbr: Number of audio channels (1: mono; 2: stereo)
1051   */
1052 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr)
1053 {
1054 #if 1
1055   uint32_t i = 0;
1056 
1057   /* Enable CRC peripheral to unlock the PDM library */
1058   __CRC_CLK_ENABLE();
1059 
1060   for(i = 0; i < ChnlNbr; i++)
1061   {
1062     /* Filter LP and HP Init */
1063     Filter[i].LP_HZ = AudioFreq / 2;
1064     Filter[i].HP_HZ = 10;
1065     Filter[i].Fs = AudioFreq;
1066     /* On STM32F4-Discovery a single microphone is mounted, samples are duplicated
1067        to make stereo audio streams */
1068     // BK - generate mono output
1069     // Filter[i].Out_MicChannels = 2;
1070     Filter[i].Out_MicChannels = 1;
1071     Filter[i].In_MicChannels = ChnlNbr;
1072     PDM_Filter_Init((PDMFilter_InitStruct *)&Filter[i]);
1073   }
1074 #endif
1075 }
1076 
1077 /**
1078   * @brief  Initializes the Audio Codec audio interface (I2S)
1079   * @note   This function assumes that the I2S input clock (through PLL_R in
1080   *         Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y)
1081   *         is already configured and ready to be used.
1082   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral.
1083   */
1084 static uint8_t I2S2_Init(uint32_t AudioFreq)
1085 {
1086   /* Initialize the hAudioInI2s Instance parameter */
1087   hAudioInI2s.Instance          = I2S2;
1088 
1089   /* Disable I2S block */
1090   __HAL_I2S_DISABLE(&hAudioInI2s);
1091 
1092   /* I2S2 peripheral configuration */
1093   hAudioInI2s.Init.AudioFreq    = 2 * AudioFreq;
1094   hAudioInI2s.Init.ClockSource  = I2S_CLOCK_PLL;
1095   hAudioInI2s.Init.CPOL         = I2S_CPOL_HIGH;
1096   hAudioInI2s.Init.DataFormat   = I2S_DATAFORMAT_16B;
1097   hAudioInI2s.Init.MCLKOutput   = I2S_MCLKOUTPUT_DISABLE;
1098   hAudioInI2s.Init.Mode         = I2S_MODE_MASTER_RX;
1099   hAudioInI2s.Init.Standard     = I2S_STANDARD_LSB;
1100 
1101   /* Initialize the I2S peripheral with the structure above */
1102   if(HAL_I2S_Init(&hAudioInI2s) != HAL_OK)
1103   {
1104     return AUDIO_ERROR;
1105   }
1106   else
1107   {
1108     return AUDIO_OK;
1109   }
1110 }
1111 
1112 /**
1113   * @}
1114   */
1115 
1116 /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_OUT_Private_Functions STM32F4 DISCOVERY AUDIO IN OUT Private Functions
1117   * @{
1118   */
1119 
1120 /**
1121   * @brief  I2S error callbacks.
1122   * @param  hi2s: I2S handle
1123   */
1124 void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
1125 {
1126   /* Manage the error generated on DMA FIFO: This function
1127      should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */
1128   if(hi2s->Instance == I2S3)
1129   {
1130     BSP_AUDIO_OUT_Error_CallBack();
1131   }
1132   if(hi2s->Instance == I2S2)
1133   {
1134     BSP_AUDIO_IN_Error_Callback();
1135   }
1136  }
1137 
1138 /**
1139   * @}
1140   */
1141 
1142 /**
1143   * @}
1144   */
1145 
1146 /**
1147   * @}
1148   */
1149 
1150 /**
1151   * @}
1152   */
1153 
1154 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1155