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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 674 __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) 675 { 676 } 677 678 /** 679 * @brief Manages the DMA Half Transfer complete event. 680 */ 681 __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) 682 { 683 } 684 685 /** 686 * @brief Manages the DMA FIFO error event. 687 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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