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