xref: /btstack/port/stm32-f4discovery-cc256x/bsp/stm32f4_discovery_audio.c (revision e0a94143c1f0305eb5125b599df7b54ca2d10b42)
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 static uint32_t bsp_audio_out_actual_frequency = 0;
163 static uint32_t bsp_audio_out_frequency = 0;
164 
165 typedef struct {
166     uint32_t freq;
167     uint32_t actual;
168     uint16_t r;
169     uint16_t n;
170 } i2s_pll_entry_t;
171 
172 // HSE_VALUE = 8000000
173 // PLLM = 4
174 // MCK on
175 static const i2s_pll_entry_t i2s_pll_table[] = {
176     {  8000,  8000, 5, 128 }, /* i2sdiv:  12, odd: 1, rate error % (desired vs actual)%: 0.0000 */
177     { 11025, 11024, 2, 127 }, /* i2sdiv:  22, odd: 1, rate error % (desired vs actual)%: 0.0063 */
178     { 12000, 12000, 5, 192 }, /* i2sdiv:  12, odd: 1, rate error % (desired vs actual)%: 0.0000 */
179     { 16000, 16000, 4, 213 }, /* i2sdiv:  13, odd: 0, rate error % (desired vs actual)%: 0.0038 */
180     { 22050, 22048, 5, 127 }, /* i2sdiv:   4, odd: 1, rate error % (desired vs actual)%: 0.0063 */
181     { 24000, 24003, 3, 212 }, /* i2sdiv:  11, odd: 1, rate error % (desired vs actual)%: 0.0151 */
182     { 32000, 32001, 4, 213 }, /* i2sdiv:   6, odd: 1, rate error % (desired vs actual)%: 0.0038 */
183     { 44100, 44084, 2,  79 }, /* i2sdiv:   3, odd: 1, rate error % (desired vs actual)%: 0.0344 */
184     { 48000, 47991, 2,  86 }, /* i2sdiv:   3, odd: 1, rate error % (desired vs actual)%: 0.0186 */
185     { 96000, 95982, 2, 172 }, /* i2sdiv:   3, odd: 1, rate error % (desired vs actual)%: 0.0186 */
186 };
187 
188 #define BARRIER do { __asm__ volatile("" ::: "memory"); } while (0)
189 #define BINARY(I) do {                                            \
190                 base = ((base)[I].freq <= frequency)?base+I:base; \
191                 BARRIER;                                          \
192         } while (0)
193 
194 /** @brief  Searches I2S PLL parameter giving highest frequency accuracy possible
195   * @param  frequency: the frequency to seach PLL parameter for
196   * @retval The PLL config with helps setting specified frequency
197   * @note   This assembles a unrolled binary search for a fixed table size,
198   *         so changes to the table size need to be reflected here. Or should
199   *         be auto-generated
200   */
i2s_find_pll_params(uint32_t frequency)201 static i2s_pll_entry_t const *i2s_find_pll_params( uint32_t frequency ) {
202     i2s_pll_entry_t const* base = i2s_pll_table;
203     BINARY(5);
204     BINARY(2);
205     BINARY(1);
206     BINARY(1);
207     return base;
208 }
209 
210 /**
211   * @}
212   */
213 
214 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Macros STM32F4 DISCOVERY AUDIO Private Macros
215   * @{
216   */
217 /**
218   * @}
219   */
220 
221 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Variables STM32F4 DISCOVERY AUDIO Private Variables
222   * @{
223   */
224 /*##### PLAY #####*/
225 static AUDIO_DrvTypeDef           *pAudioDrv;
226 I2S_HandleTypeDef                 hAudioOutI2s;
227 
228 /*### RECORDER ###*/
229 I2S_HandleTypeDef                 hAudioInI2s;
230 
231 static PDMFilter_InitStruct Filter[DEFAULT_AUDIO_IN_CHANNEL_NBR];
232 __IO uint16_t AudioInVolume = DEFAULT_AUDIO_IN_VOLUME;
233 /**
234   * @}
235   */
236 
237 /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F4 DISCOVERY AUDIO Private Function Prototypes
238   * @{
239   */
240 static uint8_t I2S2_Init(uint32_t AudioFreq);
241 static uint8_t I2S3_Init(uint32_t AudioFreq);
242 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr);
243 
244 /**
245   * @}
246   */
247 
248 /** @defgroup STM32F4_DISCOVERY_AUDIO_OUT_Private_Functions STM32F4 DISCOVERY AUDIO OUT Private Functions
249   * @{
250   */
251 
252 /**
253   * @brief  Configures the audio peripherals.
254   * @param  OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
255   *                       OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO .
256   * @param  Volume: Initial volume level (from 0 (Mute) to 100 (Max))
257   * @param  AudioFreq: Audio frequency used to play the audio stream.
258   * @retval AUDIO_OK if correct communication, else wrong communication
259   */
BSP_AUDIO_OUT_Init(uint16_t OutputDevice,uint8_t Volume,uint32_t AudioFreq)260 uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
261 {
262   uint8_t ret = AUDIO_OK;
263 
264   /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
265   BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL);
266 
267   /* I2S data transfer preparation:
268   Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
269   hAudioOutI2s.Instance = I2S3;
270   if(HAL_I2S_GetState(&hAudioOutI2s) == HAL_I2S_STATE_RESET)
271   {
272     /* Init the I2S MSP: this __weak function can be redefined by the application*/
273     BSP_AUDIO_OUT_MspInit(&hAudioOutI2s, NULL);
274   }
275 
276   /* I2S data transfer preparation:
277   Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
278   /* Configure the I2S peripheral */
279   if(I2S3_Init(AudioFreq) != AUDIO_OK)
280   {
281     ret = AUDIO_ERROR;
282   }
283 
284   if(ret == AUDIO_OK)
285   {
286     /* Retieve audio codec identifier */
287     if(((cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS)) & CS43L22_ID_MASK) == CS43L22_ID)
288     {
289       /* Initialize the audio driver structure */
290       pAudioDrv = &cs43l22_drv;
291     }
292     else
293     {
294       ret = AUDIO_ERROR;
295     }
296   }
297 
298   if(ret == AUDIO_OK)
299   {
300     pAudioDrv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq);
301   }
302 
303   return ret;
304 }
305 
306 /**
307   * @brief  Starts playing audio stream from a data buffer for a determined size.
308   * @param  pBuffer: Pointer to the buffer
309   * @param  Size: Number of audio data BYTES.
310   * @retval AUDIO_OK if correct communication, else wrong communication
311   */
BSP_AUDIO_OUT_Play(uint16_t * pBuffer,uint32_t Size)312 uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
313 {
314   /* Call the audio Codec Play function */
315   if(pAudioDrv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0)
316   {
317     return AUDIO_ERROR;
318   }
319   else
320   {
321     bsp_audio_out_frequency = bsp_audio_out_actual_frequency;
322     /* Update the Media layer and enable it for play */
323     HAL_I2S_Transmit_DMA(&hAudioOutI2s, pBuffer, DMA_MAX(Size/AUDIODATA_SIZE));
324 
325     /* Return AUDIO_OK when all operations are correctly done */
326     return AUDIO_OK;
327   }
328 }
329 
330 /**
331   * @brief  Sends n-Bytes on the I2S interface.
332   * @param  pData: Pointer to data address
333   * @param  Size: Number of data to be written
334   */
BSP_AUDIO_OUT_ChangeBuffer(uint16_t * pData,uint16_t Size)335 void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
336 {
337   HAL_I2S_Transmit_DMA(&hAudioOutI2s, pData, Size);
338 }
339 
340 /**
341   * @brief   Pauses the audio file stream. In case of using DMA, the DMA Pause
342   *          feature is used.
343   * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only the
344   *          BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play()
345   *          function for resume could lead to unexpected behavior).
346   * @retval  AUDIO_OK if correct communication, else wrong communication
347   */
BSP_AUDIO_OUT_Pause(void)348 uint8_t BSP_AUDIO_OUT_Pause(void)
349 {
350   /* Call the Audio Codec Pause/Resume function */
351   if(pAudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0)
352   {
353     return AUDIO_ERROR;
354   }
355   else
356   {
357     /* Call the Media layer pause function */
358     HAL_I2S_DMAPause(&hAudioOutI2s);
359 
360     /* Return AUDIO_OK when all operations are correctly done */
361     return AUDIO_OK;
362   }
363 }
364 
365 /**
366   * @brief   Resumes the audio file streaming.
367   * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only
368   *          BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play()
369   *          function for resume could lead to unexpected behavior).
370   * @retval  AUDIO_OK if correct communication, else wrong communication
371   */
BSP_AUDIO_OUT_Resume(void)372 uint8_t BSP_AUDIO_OUT_Resume(void)
373 {
374   /* Call the Audio Codec Pause/Resume function */
375   if(pAudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0)
376   {
377     return AUDIO_ERROR;
378   }
379   else
380   {
381     /* Call the Media layer resume function */
382     HAL_I2S_DMAResume(&hAudioOutI2s);
383 
384     /* Return AUDIO_OK when all operations are correctly done */
385     return AUDIO_OK;
386   }
387 }
388 
389 /**
390   * @brief  Stops audio playing and Power down the Audio Codec.
391   * @param  Option: could be one of the following parameters
392   *           - CODEC_PDWN_HW: completely shut down the codec (physically).
393   *                            Then need to reconfigure the Codec after power on.
394   * @retval AUDIO_OK if correct communication, else wrong communication
395   */
BSP_AUDIO_OUT_Stop(uint32_t Option)396 uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
397 {
398   /* Call DMA Stop to disable DMA stream before stopping codec */
399   HAL_I2S_DMAStop(&hAudioOutI2s);
400 
401   bsp_audio_out_frequency = 0;
402 
403   /* Call Audio Codec Stop function */
404   if(pAudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
405   {
406     return AUDIO_ERROR;
407   }
408   else
409   {
410     if(Option == CODEC_PDWN_HW)
411     {
412       /* Wait at least 1ms */
413       HAL_Delay(1);
414 
415       /* Reset the pin */
416       HAL_GPIO_WritePin(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, GPIO_PIN_RESET);
417     }
418 
419     /* Return AUDIO_OK when all operations are correctly done */
420     return AUDIO_OK;
421   }
422 }
423 
424 /**
425   * @brief  Controls the current audio volume level.
426   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for
427   *         Mute and 100 for Max volume level).
428   * @retval AUDIO_OK if correct communication, else wrong communication
429   */
BSP_AUDIO_OUT_SetVolume(uint8_t Volume)430 uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
431 {
432   /* Call the codec volume control function with converted volume value */
433   if(pAudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
434   {
435     return AUDIO_ERROR;
436   }
437   else
438   {
439     /* Return AUDIO_OK when all operations are correctly done */
440     return AUDIO_OK;
441   }
442 }
443 
444 /**
445   * @brief  Enables or disables the MUTE mode by software
446   * @param  Cmd: could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to
447   *         unmute the codec and restore previous volume level.
448   * @retval AUDIO_OK if correct communication, else wrong communication
449   */
BSP_AUDIO_OUT_SetMute(uint32_t Cmd)450 uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
451 {
452   /* Call the Codec Mute function */
453   if(pAudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
454   {
455     return AUDIO_ERROR;
456   }
457   else
458   {
459     /* Return AUDIO_OK when all operations are correctly done */
460     return AUDIO_OK;
461   }
462 }
463 
464 /**
465   * @brief  Switch dynamically (while audio file is played) the output target
466   *         (speaker or headphone).
467   * @note   This function modifies a global variable of the audio codec driver: OutputDev.
468   * @param  Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER,
469   *         OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO
470   * @retval AUDIO_OK if correct communication, else wrong communication
471   */
BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)472 uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
473 {
474   /* Call the Codec output Device function */
475   if(pAudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
476   {
477     return AUDIO_ERROR;
478   }
479   else
480   {
481     /* Return AUDIO_OK when all operations are correctly done */
482     return AUDIO_OK;
483   }
484 }
485 
486 /**
487   * @brief  Update the audio frequency.
488   * @param  AudioFreq: Audio frequency used to play the audio stream.
489   * @note   This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
490   *         audio frequency.
491   */
BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)492 void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
493 {
494   /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
495   BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL);
496 
497   /* Update the I2S audio frequency configuration */
498   I2S3_Init(AudioFreq);
499 }
500 
501 /**
502   * @brief  Tx Transfer completed callbacks.
503   * @param  hi2s: I2S handle
504   */
HAL_I2S_TxCpltCallback(I2S_HandleTypeDef * hi2s)505 void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
506 {
507   if(hi2s->Instance == I2S3)
508   {
509     /* Call the user function which will manage directly transfer complete */
510     BSP_AUDIO_OUT_TransferComplete_CallBack();
511   }
512 }
513 
514 /**
515   * @brief  Tx Half Transfer completed callbacks.
516   * @param  hi2s: I2S handle
517   */
HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef * hi2s)518 void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
519 {
520   if(hi2s->Instance == I2S3)
521   {
522     /* Manage the remaining file size and new address offset: This function should
523        be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */
524     BSP_AUDIO_OUT_HalfTransfer_CallBack();
525   }
526 }
527 
528 /**
529   * @brief  Clock Config.
530   * @param  hi2s: might be required to set audio peripheral predivider if any.
531   * @param  AudioFreq: Audio frequency used to play the audio stream.
532   * @note   This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency()
533   *         Being __weak it can be overwritten by the application
534   * @param  Params : pointer on additional configuration parameters, can be NULL.
535   */
BSP_AUDIO_OUT_ClockConfig(I2S_HandleTypeDef * hi2s,uint32_t AudioFreq,void * Params)536 __weak void BSP_AUDIO_OUT_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params)
537 {
538   RCC_PeriphCLKInitTypeDef rccclkinit;
539 
540   i2s_pll_entry_t const *pll_params = i2s_find_pll_params( AudioFreq );
541 
542   bsp_audio_out_actual_frequency = pll_params->actual;
543 
544   /* Enable PLLI2S clock */
545   HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit);
546   /* PLLI2S_VCO Input = HSE_VALUE/PLL_M */
547 
548   /* I2S clock config
549   PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) � (PLLI2SN/PLLM)
550   I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */
551   rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S;
552   rccclkinit.PLLI2S.PLLI2SN = pll_params->n;
553   rccclkinit.PLLI2S.PLLI2SR = pll_params->r;
554   HAL_RCCEx_PeriphCLKConfig(&rccclkinit);
555 }
556 
557 /**
558   * @brief  AUDIO OUT I2S MSP Init.
559   * @param  hi2s: might be required to set audio peripheral predivider if any.
560   * @param  Params : pointer on additional configuration parameters, can be NULL.
561   */
BSP_AUDIO_OUT_MspInit(I2S_HandleTypeDef * hi2s,void * Params)562 __weak void BSP_AUDIO_OUT_MspInit(I2S_HandleTypeDef *hi2s, void *Params)
563 {
564   static DMA_HandleTypeDef hdma_i2sTx;
565   GPIO_InitTypeDef  GPIO_InitStruct;
566 
567   /* Enable I2S3 clock */
568   I2S3_CLK_ENABLE();
569 
570   /*** Configure the GPIOs ***/
571   /* Enable I2S GPIO clocks */
572   I2S3_SCK_SD_CLK_ENABLE();
573   I2S3_WS_CLK_ENABLE();
574 
575   /* I2S3 pins configuration: WS, SCK and SD pins ----------------------------*/
576   GPIO_InitStruct.Pin         = I2S3_SCK_PIN | I2S3_SD_PIN;
577   GPIO_InitStruct.Mode        = GPIO_MODE_AF_PP;
578   GPIO_InitStruct.Pull        = GPIO_NOPULL;
579   GPIO_InitStruct.Speed       = GPIO_SPEED_FAST;
580   GPIO_InitStruct.Alternate   = I2S3_SCK_SD_WS_AF;
581   HAL_GPIO_Init(I2S3_SCK_SD_GPIO_PORT, &GPIO_InitStruct);
582 
583   GPIO_InitStruct.Pin         = I2S3_WS_PIN ;
584   HAL_GPIO_Init(I2S3_WS_GPIO_PORT, &GPIO_InitStruct);
585 
586   /* I2S3 pins configuration: MCK pin */
587   I2S3_MCK_CLK_ENABLE();
588   GPIO_InitStruct.Pin         = I2S3_MCK_PIN;
589   HAL_GPIO_Init(I2S3_MCK_GPIO_PORT, &GPIO_InitStruct);
590 
591   /* Enable the I2S DMA clock */
592   I2S3_DMAx_CLK_ENABLE();
593 
594   if(hi2s->Instance == I2S3)
595   {
596     /* Configure the hdma_i2sTx handle parameters */
597     hdma_i2sTx.Init.Channel             = I2S3_DMAx_CHANNEL;
598     hdma_i2sTx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
599     hdma_i2sTx.Init.PeriphInc           = DMA_PINC_DISABLE;
600     hdma_i2sTx.Init.MemInc              = DMA_MINC_ENABLE;
601     hdma_i2sTx.Init.PeriphDataAlignment = I2S3_DMAx_PERIPH_DATA_SIZE;
602     hdma_i2sTx.Init.MemDataAlignment    = I2S3_DMAx_MEM_DATA_SIZE;
603     hdma_i2sTx.Init.Mode                = DMA_NORMAL;
604 
605     // BK: use circular DMA for hal_audio.h
606 #ifdef HAVE_HAL_AUDIO
607     hdma_i2sTx.Init.Mode                = DMA_CIRCULAR;
608 #endif
609     // BK: use circular DMA (end)
610 
611     hdma_i2sTx.Init.Priority            = DMA_PRIORITY_HIGH;
612     hdma_i2sTx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
613     hdma_i2sTx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
614     hdma_i2sTx.Init.MemBurst            = DMA_MBURST_SINGLE;
615     hdma_i2sTx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
616 
617     hdma_i2sTx.Instance                 = I2S3_DMAx_STREAM;
618 
619     /* Associate the DMA handle */
620     __HAL_LINKDMA(hi2s, hdmatx, hdma_i2sTx);
621 
622     /* Deinitialize the Stream for new transfer */
623     HAL_DMA_DeInit(&hdma_i2sTx);
624 
625     /* Configure the DMA Stream */
626     HAL_DMA_Init(&hdma_i2sTx);
627   }
628 
629   /* I2S DMA IRQ Channel configuration */
630   HAL_NVIC_SetPriority(I2S3_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
631   HAL_NVIC_EnableIRQ(I2S3_DMAx_IRQ);
632 }
633 
634 /**
635   * @brief  De-Initializes BSP_AUDIO_OUT MSP.
636   * @param  hi2s: might be required to set audio peripheral predivider if any.
637   * @param  Params : pointer on additional configuration parameters, can be NULL.
638   */
BSP_AUDIO_OUT_MspDeInit(I2S_HandleTypeDef * hi2s,void * Params)639 __weak void BSP_AUDIO_OUT_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params)
640 {
641   GPIO_InitTypeDef  GPIO_InitStruct;
642 
643   /* I2S DMA IRQ Channel deactivation */
644   HAL_NVIC_DisableIRQ(I2S3_DMAx_IRQ);
645 
646   if(hi2s->Instance == I2S3)
647   {
648     /* Deinitialize the Stream for new transfer */
649     HAL_DMA_DeInit(hi2s->hdmatx);
650   }
651 
652  /* Disable I2S block */
653   __HAL_I2S_DISABLE(hi2s);
654 
655   /* CODEC_I2S pins configuration: SCK and SD pins */
656   GPIO_InitStruct.Pin = I2S3_SCK_PIN | I2S3_SD_PIN;
657   HAL_GPIO_DeInit(I2S3_SCK_SD_GPIO_PORT, GPIO_InitStruct.Pin);
658 
659   /* CODEC_I2S pins configuration: WS pin */
660   GPIO_InitStruct.Pin = I2S3_WS_PIN;
661   HAL_GPIO_DeInit(I2S3_WS_GPIO_PORT, GPIO_InitStruct.Pin);
662 
663   /* CODEC_I2S pins configuration: MCK pin */
664   GPIO_InitStruct.Pin = I2S3_MCK_PIN;
665   HAL_GPIO_DeInit(I2S3_MCK_GPIO_PORT, GPIO_InitStruct.Pin);
666 
667   /* Disable I2S clock */
668   I2S3_CLK_DISABLE();
669 
670   /* GPIO pins clock and DMA clock can be shut down in the applic
671      by surcgarging this __weak function */
672 }
673 
674 /**
675   * @brief  Manages the DMA full Transfer complete event.
676   */
BSP_AUDIO_OUT_TransferComplete_CallBack(void)677 __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
678 {
679 }
680 
681 /**
682   * @brief  Manages the DMA Half Transfer complete event.
683   */
BSP_AUDIO_OUT_HalfTransfer_CallBack(void)684 __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
685 {
686 }
687 
688 /**
689   * @brief  Manages the DMA FIFO error event.
690   */
BSP_AUDIO_OUT_Error_CallBack(void)691 __weak void BSP_AUDIO_OUT_Error_CallBack(void)
692 {
693 }
694 
695 /*******************************************************************************
696                             Static Functions
697 *******************************************************************************/
698 
699 /**
700   * @brief  Initializes the Audio Codec audio interface (I2S).
701   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral.
702   */
I2S3_Init(uint32_t AudioFreq)703 static uint8_t I2S3_Init(uint32_t AudioFreq)
704 {
705   /* Initialize the hAudioOutI2s Instance parameter */
706   hAudioOutI2s.Instance         = I2S3;
707 
708  /* Disable I2S block */
709   __HAL_I2S_DISABLE(&hAudioOutI2s);
710 
711   /* I2S3 peripheral configuration */
712   hAudioOutI2s.Init.AudioFreq   = AudioFreq;
713   hAudioOutI2s.Init.ClockSource = I2S_CLOCK_PLL;
714   hAudioOutI2s.Init.CPOL        = I2S_CPOL_LOW;
715   hAudioOutI2s.Init.DataFormat  = I2S_DATAFORMAT_16B;
716   hAudioOutI2s.Init.MCLKOutput  = I2S_MCLKOUTPUT_ENABLE;
717   hAudioOutI2s.Init.Mode        = I2S_MODE_MASTER_TX;
718   hAudioOutI2s.Init.Standard    = I2S_STANDARD;
719   /* Initialize the I2S peripheral with the structure above */
720   if(HAL_I2S_Init(&hAudioOutI2s) != HAL_OK)
721   {
722     return AUDIO_ERROR;
723   }
724   else
725   {
726     return AUDIO_OK;
727   }
728 }
729 
730 /**
731   * @}
732   */
733 
734 /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_Private_Functions STM32F4 DISCOVERY AUDIO IN Private Functions
735   * @{
736   */
737 
738 /**
739   * @brief  Initializes wave recording.
740   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral.
741   * @param  BitRes: Audio frequency to be configured for the I2S peripheral.
742   * @param  ChnlNbr: Audio frequency to be configured for the I2S peripheral.
743   * @retval AUDIO_OK if correct communication, else wrong communication
744   */
BSP_AUDIO_IN_Init(uint32_t AudioFreq,uint32_t BitRes,uint32_t ChnlNbr)745 uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
746 {
747 
748 #if 0
749   // BK: only do PLL clock configuration in sink
750   /* Configure PLL clock */
751   BSP_AUDIO_IN_ClockConfig(&hAudioInI2s, AudioFreq, NULL);
752 #endif
753 
754   /* Configure the PDM library */
755   PDMDecoder_Init(AudioFreq, ChnlNbr);
756 
757   /* Configure the I2S peripheral */
758   hAudioInI2s.Instance = I2S2;
759   if(HAL_I2S_GetState(&hAudioInI2s) == HAL_I2S_STATE_RESET)
760   {
761     /* Initialize the I2S Msp: this __weak function can be rewritten by the application */
762     BSP_AUDIO_IN_MspInit(&hAudioInI2s, NULL);
763   }
764 
765   /* Configure the I2S2 */
766   I2S2_Init(AudioFreq);
767 
768   /* Return AUDIO_OK when all operations are correctly done */
769   return AUDIO_OK;
770 }
771 
772 /**
773   * @brief  Starts audio recording.
774   * @param  pbuf: Main buffer pointer for the recorded data storing
775   * @param  size: Current size of the recorded buffer
776   * @retval AUDIO_OK if correct communication, else wrong communication
777   */
BSP_AUDIO_IN_Record(uint16_t * pbuf,uint32_t size)778 uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size)
779 {
780   uint32_t ret = AUDIO_ERROR;
781 
782   /* Start the process receive DMA */
783   HAL_I2S_Receive_DMA(&hAudioInI2s, pbuf, size);
784 
785   /* Return AUDIO_OK when all operations are correctly done */
786   ret = AUDIO_OK;
787 
788   return ret;
789 }
790 
791 /**
792   * @brief  Stops audio recording.
793   * @retval AUDIO_OK if correct communication, else wrong communication
794   */
BSP_AUDIO_IN_Stop(void)795 uint8_t BSP_AUDIO_IN_Stop(void)
796 {
797   uint32_t ret = AUDIO_ERROR;
798 
799   /* Call the Media layer pause function */
800   HAL_I2S_DMAStop(&hAudioInI2s);
801 
802   /* Return AUDIO_OK when all operations are correctly done */
803   ret = AUDIO_OK;
804 
805   return ret;
806 }
807 
808 /**
809   * @brief  Pauses the audio file stream.
810   * @retval AUDIO_OK if correct communication, else wrong communication
811   */
BSP_AUDIO_IN_Pause(void)812 uint8_t BSP_AUDIO_IN_Pause(void)
813 {
814   /* Call the Media layer pause function */
815   HAL_I2S_DMAPause(&hAudioInI2s);
816 
817   /* Return AUDIO_OK when all operations are correctly done */
818   return AUDIO_OK;
819 }
820 
821 /**
822   * @brief  Resumes the audio file stream.
823   * @retval AUDIO_OK if correct communication, else wrong communication
824   */
BSP_AUDIO_IN_Resume(void)825 uint8_t BSP_AUDIO_IN_Resume(void)
826 {
827   /* Call the Media layer pause/resume function */
828   HAL_I2S_DMAResume(&hAudioInI2s);
829 
830   /* Return AUDIO_OK when all operations are correctly done */
831   return AUDIO_OK;
832 }
833 
834 /**
835   * @brief  Controls the audio in volume level.
836   * @param  Volume: Volume level to be set in percentage from 0% to 100% (0 for
837   *         Mute and 100 for Max volume level).
838   * @retval AUDIO_OK if correct communication, else wrong communication
839   */
BSP_AUDIO_IN_SetVolume(uint8_t Volume)840 uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume)
841 {
842   /* Set the Global variable AudioInVolume */
843   AudioInVolume = Volume;
844 
845   /* Return AUDIO_OK when all operations are correctly done */
846   return AUDIO_OK;
847 }
848 
849 /**
850   * @brief  Converts audio format from PDM to PCM.
851   * @param  PDMBuf: Pointer to data PDM buffer
852   * @param  PCMBuf: Pointer to data PCM buffer
853   * @retval AUDIO_OK if correct communication, else wrong communication
854   */
BSP_AUDIO_IN_PDMToPCM(uint16_t * PDMBuf,uint16_t * PCMBuf)855 uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t *PDMBuf, uint16_t *PCMBuf)
856 {
857   uint16_t AppPDM[INTERNAL_BUFF_SIZE/2];
858   uint32_t index = 0;
859 
860   /* PDM Demux */
861   for(index = 0; index<INTERNAL_BUFF_SIZE/2; index++)
862   {
863     AppPDM[index] = HTONS(PDMBuf[index]);
864   }
865 
866   for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++)
867   {
868     /* PDM to PCM filter */
869     PDM_Filter_64_LSB((uint8_t*)&AppPDM[index], (uint16_t*)&(PCMBuf[index]), AudioInVolume , (PDMFilter_InitStruct *)&Filter[index]);
870   }
871 #if 0
872   // BK - generate mono output
873 
874   /* Duplicate samples since a single microphone in mounted on STM32F4-Discovery */
875   for(index = 0; index < PCM_OUT_SIZE; index++)
876   {
877     PCMBuf[(index<<1)+1] = PCMBuf[index<<1];
878   }
879 #endif
880 
881   /* Return AUDIO_OK when all operations are correctly done */
882   return AUDIO_OK;
883 }
884 
885 /**
886   * @brief  Rx Transfer completed callbacks
887   * @param  hi2s: I2S handle
888   */
HAL_I2S_RxCpltCallback(I2S_HandleTypeDef * hi2s)889 void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
890 {
891   /* Call the record update function to get the next buffer to fill and its size (size is ignored) */
892   BSP_AUDIO_IN_TransferComplete_CallBack();
893 }
894 
895 /**
896   * @brief  Rx Half Transfer completed callbacks.
897   * @param  hi2s: I2S handle
898   */
HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef * hi2s)899 void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
900 {
901   /* Manage the remaining file size and new address offset: This function
902      should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */
903   BSP_AUDIO_IN_HalfTransfer_CallBack();
904 }
905 
906 /**
907   * @brief  Retrive the audio frequency.
908   * @retval AudioFreq: Audio frequency used to play the audio stream.
909   * @note   This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
910   *         audio frequency.
911   */
BSP_AUDIO_OUT_GetFrequency(uint32_t AudioFreq)912 uint32_t BSP_AUDIO_OUT_GetFrequency(uint32_t AudioFreq)
913 {
914   return bsp_audio_out_frequency;
915 }
916 
917 /**
918   * @brief  Audio In Clock Config.
919   * @param  hi2s: I2S handle
920   * @param  AudioFreq: Audio frequency used to record the audio stream.
921   * @param  Params : pointer on additional configuration parameters, can be NULL.
922   * @note   This API is called by BSP_AUDIO_IN_Init()
923   *         Being __weak it can be overwritten by the application
924   */
BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef * hi2s,uint32_t AudioFreq,void * Params)925 __weak void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params)
926 {
927   RCC_PeriphCLKInitTypeDef rccclkinit;
928 
929   /*Enable PLLI2S clock*/
930   HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit);
931 
932   i2s_pll_entry_t const *pll_params = i2s_find_pll_params( AudioFreq );
933 
934   rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S;
935   rccclkinit.PLLI2S.PLLI2SN = pll_params->n;
936   rccclkinit.PLLI2S.PLLI2SR = pll_params->r;
937   HAL_RCCEx_PeriphCLKConfig(&rccclkinit);
938 }
939 
940 /**
941   * @brief  BSP AUDIO IN MSP Init.
942   * @param  hi2s: I2S handle
943   * @param  Params : pointer on additional configuration parameters, can be NULL.
944   */
BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef * hi2s,void * Params)945 __weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params)
946 {
947   static DMA_HandleTypeDef hdma_i2sRx;
948   GPIO_InitTypeDef  GPIO_InitStruct;
949 
950   /* Enable the I2S2 peripheral clock */
951   I2S2_CLK_ENABLE();
952 
953   /* Enable I2S GPIO clocks */
954   I2S2_SCK_GPIO_CLK_ENABLE();
955   I2S2_MOSI_GPIO_CLK_ENABLE();
956 
957   /* I2S2 pins configuration: SCK and MOSI pins ------------------------------*/
958   GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
959   GPIO_InitStruct.Pull      = GPIO_NOPULL;
960   GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;
961 
962   GPIO_InitStruct.Pin       = I2S2_SCK_PIN;
963   GPIO_InitStruct.Alternate = I2S2_SCK_AF;
964   HAL_GPIO_Init(I2S2_SCK_GPIO_PORT, &GPIO_InitStruct);
965 
966   GPIO_InitStruct.Pin       = I2S2_MOSI_PIN ;
967   GPIO_InitStruct.Alternate = I2S2_MOSI_AF;
968   HAL_GPIO_Init(I2S2_MOSI_GPIO_PORT, &GPIO_InitStruct);
969 
970   /* Enable the DMA clock */
971   I2S2_DMAx_CLK_ENABLE();
972 
973   if(hi2s->Instance == I2S2)
974   {
975     /* Configure the hdma_i2sRx handle parameters */
976     hdma_i2sRx.Init.Channel             = I2S2_DMAx_CHANNEL;
977     hdma_i2sRx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
978     hdma_i2sRx.Init.PeriphInc           = DMA_PINC_DISABLE;
979     hdma_i2sRx.Init.MemInc              = DMA_MINC_ENABLE;
980     hdma_i2sRx.Init.PeriphDataAlignment = I2S2_DMAx_PERIPH_DATA_SIZE;
981     hdma_i2sRx.Init.MemDataAlignment    = I2S2_DMAx_MEM_DATA_SIZE;
982     hdma_i2sRx.Init.Mode                = DMA_CIRCULAR;
983     hdma_i2sRx.Init.Priority            = DMA_PRIORITY_HIGH;
984     hdma_i2sRx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
985     hdma_i2sRx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
986     hdma_i2sRx.Init.MemBurst            = DMA_MBURST_SINGLE;
987     hdma_i2sRx.Init.PeriphBurst         = DMA_MBURST_SINGLE;
988 
989     hdma_i2sRx.Instance = I2S2_DMAx_STREAM;
990 
991     /* Associate the DMA handle */
992     __HAL_LINKDMA(hi2s, hdmarx, hdma_i2sRx);
993 
994     /* Deinitialize the Stream for new transfer */
995     HAL_DMA_DeInit(&hdma_i2sRx);
996 
997     /* Configure the DMA Stream */
998     HAL_DMA_Init(&hdma_i2sRx);
999   }
1000 
1001   /* I2S DMA IRQ Channel configuration */
1002   HAL_NVIC_SetPriority(I2S2_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0);
1003   HAL_NVIC_EnableIRQ(I2S2_DMAx_IRQ);
1004 }
1005 
1006 /**
1007   * @brief  DeInitializes BSP_AUDIO_IN MSP.
1008   * @param  hi2s: I2S handle
1009   * @param  Params : pointer on additional configuration parameters, can be NULL.
1010   */
BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef * hi2s,void * Params)1011 __weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params)
1012 {
1013   GPIO_InitTypeDef  gpio_init_structure;
1014 
1015   /* I2S DMA IRQ Channel deactivation */
1016   HAL_NVIC_DisableIRQ(I2S2_DMAx_IRQ);
1017 
1018   if(hi2s->Instance == I2S2)
1019   {
1020     /* Deinitialize the Stream for new transfer */
1021     HAL_DMA_DeInit(hi2s->hdmarx);
1022   }
1023 
1024  /* Disable I2S block */
1025   __HAL_I2S_DISABLE(hi2s);
1026 
1027   /* Disable pins: SCK and SD pins */
1028   gpio_init_structure.Pin = I2S2_SCK_PIN;
1029   HAL_GPIO_DeInit(I2S2_SCK_GPIO_PORT, gpio_init_structure.Pin);
1030   gpio_init_structure.Pin = I2S2_MOSI_PIN;
1031   HAL_GPIO_DeInit(I2S2_MOSI_GPIO_PORT, gpio_init_structure.Pin);
1032 
1033   /* Disable I2S clock */
1034   I2S2_CLK_DISABLE();
1035 
1036   /* GPIO pins clock and DMA clock can be shut down in the applic
1037      by surcgarging this __weak function */
1038 }
1039 
1040 /**
1041   * @brief  User callback when record buffer is filled.
1042   */
BSP_AUDIO_IN_TransferComplete_CallBack(void)1043 __weak void BSP_AUDIO_IN_TransferComplete_CallBack(void)
1044 {
1045   /* This function should be implemented by the user application.
1046      It is called into this driver when the current buffer is filled
1047      to prepare the next buffer pointer and its size. */
1048 }
1049 
1050 /**
1051   * @brief  Manages the DMA Half Transfer complete event.
1052   */
BSP_AUDIO_IN_HalfTransfer_CallBack(void)1053 __weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
1054 {
1055   /* This function should be implemented by the user application.
1056      It is called into this driver when the current buffer is filled
1057      to prepare the next buffer pointer and its size. */
1058 }
1059 
1060 /**
1061   * @brief  Audio IN Error callback function.
1062   */
BSP_AUDIO_IN_Error_Callback(void)1063 __weak void BSP_AUDIO_IN_Error_Callback(void)
1064 {
1065   /* This function is called when an Interrupt due to transfer error on or peripheral
1066      error occurs. */
1067 }
1068 
1069 /*******************************************************************************
1070                             Static Functions
1071 *******************************************************************************/
1072 
1073 /**
1074   * @brief  Initialize the PDM library.
1075   * @param  AudioFreq: Audio sampling frequency
1076   * @param  ChnlNbr: Number of audio channels (1: mono; 2: stereo)
1077   */
PDMDecoder_Init(uint32_t AudioFreq,uint32_t ChnlNbr)1078 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr)
1079 {
1080 #if 1
1081   uint32_t i = 0;
1082 
1083   /* Enable CRC peripheral to unlock the PDM library */
1084   __CRC_CLK_ENABLE();
1085 
1086   for(i = 0; i < ChnlNbr; i++)
1087   {
1088     /* Filter LP and HP Init */
1089     Filter[i].LP_HZ = AudioFreq / 2;
1090     Filter[i].HP_HZ = 10;
1091     Filter[i].Fs = AudioFreq;
1092     /* On STM32F4-Discovery a single microphone is mounted, samples are duplicated
1093        to make stereo audio streams */
1094     // BK - generate mono output
1095     // Filter[i].Out_MicChannels = 2;
1096     Filter[i].Out_MicChannels = 1;
1097     Filter[i].In_MicChannels = ChnlNbr;
1098     PDM_Filter_Init((PDMFilter_InitStruct *)&Filter[i]);
1099   }
1100 #endif
1101 }
1102 
1103 /**
1104   * @brief  Initializes the Audio Codec audio interface (I2S)
1105   * @note   This function assumes that the I2S input clock (through PLL_R in
1106   *         Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y)
1107   *         is already configured and ready to be used.
1108   * @param  AudioFreq: Audio frequency to be configured for the I2S peripheral.
1109   */
I2S2_Init(uint32_t AudioFreq)1110 static uint8_t I2S2_Init(uint32_t AudioFreq)
1111 {
1112   /* Initialize the hAudioInI2s Instance parameter */
1113   hAudioInI2s.Instance          = I2S2;
1114 
1115   /* Disable I2S block */
1116   __HAL_I2S_DISABLE(&hAudioInI2s);
1117 
1118   /* I2S2 peripheral configuration */
1119   hAudioInI2s.Init.AudioFreq    = 2 * AudioFreq;
1120   hAudioInI2s.Init.ClockSource  = I2S_CLOCK_PLL;
1121   hAudioInI2s.Init.CPOL         = I2S_CPOL_HIGH;
1122   hAudioInI2s.Init.DataFormat   = I2S_DATAFORMAT_16B;
1123   hAudioInI2s.Init.MCLKOutput   = I2S_MCLKOUTPUT_DISABLE;
1124   hAudioInI2s.Init.Mode         = I2S_MODE_MASTER_RX;
1125   hAudioInI2s.Init.Standard     = I2S_STANDARD_LSB;
1126 
1127   /* Initialize the I2S peripheral with the structure above */
1128   if(HAL_I2S_Init(&hAudioInI2s) != HAL_OK)
1129   {
1130     return AUDIO_ERROR;
1131   }
1132   else
1133   {
1134     return AUDIO_OK;
1135   }
1136 }
1137 
1138 /**
1139   * @}
1140   */
1141 
1142 /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_OUT_Private_Functions STM32F4 DISCOVERY AUDIO IN OUT Private Functions
1143   * @{
1144   */
1145 
1146 /**
1147   * @brief  I2S error callbacks.
1148   * @param  hi2s: I2S handle
1149   */
HAL_I2S_ErrorCallback(I2S_HandleTypeDef * hi2s)1150 void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s)
1151 {
1152   /* Manage the error generated on DMA FIFO: This function
1153      should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */
1154   if(hi2s->Instance == I2S3)
1155   {
1156     BSP_AUDIO_OUT_Error_CallBack();
1157   }
1158   if(hi2s->Instance == I2S2)
1159   {
1160     BSP_AUDIO_IN_Error_Callback();
1161   }
1162  }
1163 
1164 /**
1165   * @}
1166   */
1167 
1168 /**
1169   * @}
1170   */
1171 
1172 /**
1173   * @}
1174   */
1175 
1176 /**
1177   * @}
1178   */
1179 
1180 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1181