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