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>© 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