STM32469I-Discovery BSP User Manual
|
stm32469i_discovery_audio.c
Go to the documentation of this file.
00001 /** 00002 ****************************************************************************** 00003 * @file stm32469i_discovery_audio.c 00004 * @author MCD Application Team 00005 * @version V2.0.0 00006 * @date 31-January-2017 00007 * @brief This file provides the Audio driver for the STM32469I-Discovery board. 00008 ****************************************************************************** 00009 * @attention 00010 * 00011 * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> 00012 * 00013 * Redistribution and use in source and binary forms, with or without modification, 00014 * are permitted provided that the following conditions are met: 00015 * 1. Redistributions of source code must retain the above copyright notice, 00016 * this list of conditions and the following disclaimer. 00017 * 2. Redistributions in binary form must reproduce the above copyright notice, 00018 * this list of conditions and the following disclaimer in the documentation 00019 * and/or other materials provided with the distribution. 00020 * 3. Neither the name of STMicroelectronics nor the names of its contributors 00021 * may be used to endorse or promote products derived from this software 00022 * without specific prior written permission. 00023 * 00024 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00025 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00026 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00027 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 00028 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00029 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00030 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00031 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00032 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00033 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00034 * 00035 ****************************************************************************** 00036 */ 00037 00038 /*============================================================================== 00039 User NOTES 00040 00041 How To use this driver: 00042 ----------------------- 00043 + This driver supports STM32F4xx devices on STM32469I-Discovery (MB1189) Discovery boards. 00044 + Call the function BSP_AUDIO_OUT_Init( 00045 OutputDevice: physical output mode (OUTPUT_DEVICE_HEADPHONE1, 00046 OUTPUT_DEVICE_HEADPHONE2 or OUTPUT_DEVICE_BOTH) 00047 Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) 00048 AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) 00049 this parameter is relative to the audio file/stream type. 00050 ) 00051 This function configures all the hardware required for the audio application (codec, I2C, SAI, 00052 GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. 00053 If the returned value is different from AUDIO_OK or the function is stuck then the communication with 00054 the codec or the MFX has failed (try to un-plug the power or reset device in this case). 00055 - OUTPUT_DEVICE_HEADPHONE1 : only headphones 1 will be set as output for the audio stream. 00056 - OUTPUT_DEVICE_HEADPHONE2 : only headphones 2 will be set as output for the audio stream. 00057 - OUTPUT_DEVICE_BOTH : both Headphones are used as outputs for the audio stream 00058 at the same time. 00059 Note. On STM32469I-Discovery SAI_DMA is configured in CIRCULAR mode. Due to this the application 00060 does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure straming. 00061 + Call the function BSP_Discovery_AUDIO_OUT_Play( 00062 pBuffer: pointer to the audio data file address 00063 Size : size of the buffer to be sent in Bytes 00064 ) 00065 to start playing (for the first time) from the audio file/stream. 00066 + Call the function BSP_AUDIO_OUT_Pause() to pause playing 00067 + Call the function BSP_AUDIO_OUT_Resume() to resume playing. 00068 Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called 00069 for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). 00070 Note. This function should be called only when the audio file is played or paused (not stopped). 00071 + For each mode, you may need to implement the relative callback functions into your code. 00072 The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in 00073 the stm32469i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) 00074 + To Stop playing, to modify the volume level, the frequency, the audio frame slot, 00075 the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), 00076 AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), 00077 BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). 00078 + The driver API and the callback functions are at the end of the stm32469i_discovery_audio.h file. 00079 00080 Driver architecture: 00081 -------------------- 00082 + This driver provide the High Audio Layer: consists of the function API exported in the stm32469i_discovery_audio.h file 00083 (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) 00084 + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ 00085 providing the audio file/stream. These functions are also included as local functions into 00086 the stm32469i_discovery_audio_codec.c file (I2Sx_Init(), I2Sx_DeInit(), SAIx_Init() and SAIx_DeInit()) 00087 00088 Known Limitations: 00089 ------------------ 00090 1- If the TDM Format used to paly in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second 00091 Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. 00092 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, 00093 File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. 00094 3- Supports only Stereo audio streaming. 00095 4- Supports only 16-bits audio data size. 00096 ==============================================================================*/ 00097 00098 /* Includes ------------------------------------------------------------------*/ 00099 #include <string.h> 00100 #include "stm32469i_discovery_audio.h" 00101 00102 /** @addtogroup BSP 00103 * @{ 00104 */ 00105 00106 /** @addtogroup STM32469I_Discovery 00107 * @{ 00108 */ 00109 00110 /** @defgroup STM32469I-Discovery_AUDIO STM32469I Discovery AUDIO 00111 * @brief This file includes the low layer driver for CS43L22 Audio Codec 00112 * available on STM32469I-Discovery board(MB1189). 00113 * @{ 00114 */ 00115 00116 /** @defgroup STM32469I-Discovery_AUDIO_Private_Types STM32469I Discovery AUDIO Private Types 00117 * @{ 00118 */ 00119 /** 00120 * @} 00121 */ 00122 00123 /** @defgroup STM32469I-Discovery_AUDIO_Private_Defines STM32469I Discovery AUDIO Private Defines 00124 * @brief Headphone1 (CN27 of STM32469I-Discovery board) is connected to the 00125 * HEADPHONE output of CS43L22 Audio Codec. 00126 * Headphone2 (CN26 of STM32469I-Discovery board) is connected to the 00127 * SPEAKER output of CS43L22 Audio Codec. 00128 * @{ 00129 */ 00130 #define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE 00131 00132 /* Headphone2 is connected to Speaker output of the CS43L22 codec */ 00133 #define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER 00134 /** 00135 * @} 00136 */ 00137 00138 /** @defgroup STM32469I-Discovery_AUDIO_Private_Macros STM32469I Discovery AUDIO Private macros 00139 * @{ 00140 */ 00141 00142 /*### PLAY ###*/ 00143 /* SCK(kHz) = SAI_CK_x/(SAIClockDivider*2*256) */ 00144 #define SAIClockDivider(__FREQUENCY__) \ 00145 (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 12 \ 00146 : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 2 \ 00147 : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 6 \ 00148 : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 1 \ 00149 : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 3 \ 00150 : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \ 00151 : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 2 : 1 \ 00152 00153 /** 00154 * @} 00155 */ 00156 00157 /** @defgroup STM32469I-Discovery_AUDIO_Private_Variables STM32469I Discovery AUDIO Private Variables 00158 * @{ 00159 */ 00160 00161 /* 00162 Note: 00163 these global variables are not compliant to naming rules (upper case without "_" ), 00164 but we keep this naming for compatibility, in fact these variables (not static) 00165 could have been used by the application, example the stm32f4xx_it.c: 00166 void DMA2_Stream6_IRQHandler(void) 00167 { HAL_DMA_IRQHandler(haudio_out_sai.hdmatx); } 00168 */ 00169 AUDIO_DrvTypeDef *audio_drv; 00170 SAI_HandleTypeDef haudio_out_sai; 00171 I2S_HandleTypeDef haudio_in_i2s; 00172 TIM_HandleTypeDef haudio_tim; 00173 00174 PDMFilter_InitStruct Filter[2]; 00175 uint8_t Channel_Demux[128] = { 00176 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, 00177 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, 00178 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, 00179 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, 00180 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, 00181 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, 00182 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, 00183 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, 00184 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, 00185 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, 00186 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, 00187 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, 00188 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, 00189 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, 00190 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, 00191 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f 00192 }; 00193 00194 uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; 00195 00196 /** 00197 * @} 00198 */ 00199 00200 /** @defgroup STM32469I-Discovery_AUDIO_Private_Function_Prototypes STM32469I Discovery AUDIO Private Prototypes 00201 * @{ 00202 */ 00203 static uint8_t SAIx_Init(uint32_t AudioFreq); 00204 static void SAIx_DeInit(void); 00205 static void I2Sx_Init(uint32_t AudioFreq); 00206 static void I2Sx_DeInit(void); 00207 static void TIMx_IC_MspInit(TIM_HandleTypeDef *htim); 00208 static void TIMx_IC_MspDeInit(TIM_HandleTypeDef *htim); 00209 static void TIMx_Init(void); 00210 static void TIMx_DeInit(void); 00211 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr); 00212 00213 void BSP_AUDIO_OUT_ChangeAudioConfig(uint32_t AudioOutOption); 00214 00215 /** 00216 * @} 00217 */ 00218 00219 /** @defgroup STM32469I-Discovery_AUDIO_out_Private_Functions STM32469I Discovery AUDIO OUT Private Functions 00220 * @{ 00221 */ 00222 00223 /** 00224 * @brief Configures the audio peripherals. 00225 * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, 00226 * or OUTPUT_DEVICE_BOTH. 00227 * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) 00228 * @param AudioFreq: Audio frequency used to play the audio stream. 00229 * @note The SAI PLL input clock must be done in the user application. 00230 * @retval AUDIO_OK if correct communication, else wrong communication 00231 */ 00232 uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, 00233 uint8_t Volume, 00234 uint32_t AudioFreq) 00235 { 00236 uint8_t ret = AUDIO_OK; 00237 00238 SAIx_DeInit(); 00239 00240 /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 00241 BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); 00242 00243 /* SAI data transfer preparation: 00244 Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ 00245 haudio_out_sai.Instance = AUDIO_SAIx; 00246 if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) 00247 { 00248 /* Init the SAI MSP: this __weak function can be redefined by the application*/ 00249 BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); 00250 } 00251 00252 if (SAIx_Init(AudioFreq) != AUDIO_OK) 00253 { 00254 ret = AUDIO_ERROR; 00255 } 00256 00257 if(ret == AUDIO_OK) 00258 { 00259 /* Retieve audio codec identifier */ 00260 if (cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS) == CS43L22_ID) 00261 { 00262 /* Initialize the audio driver structure */ 00263 audio_drv = &cs43l22_drv; 00264 } 00265 else 00266 { 00267 ret = AUDIO_ERROR; 00268 } 00269 } 00270 00271 if(ret == AUDIO_OK) 00272 { 00273 /* Initialize the audio codec internal registers */ 00274 if (audio_drv->Init(AUDIO_I2C_ADDRESS, 00275 OutputDevice, 00276 Volume, 00277 AudioFreq) != AUDIO_OK) 00278 { 00279 ret = AUDIO_ERROR; 00280 } 00281 } 00282 00283 return ret; 00284 } 00285 00286 /** 00287 * @brief Starts playing audio stream from a data buffer for a determined size. 00288 * @param pBuffer: Pointer to the buffer 00289 * @param Size: Number of audio data BYTES. 00290 * @retval AUDIO_OK if correct communication, else wrong communication 00291 */ 00292 uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) 00293 { 00294 uint8_t ret = AUDIO_OK; 00295 00296 /* Call the audio Codec Play function */ 00297 if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) 00298 { 00299 ret = AUDIO_ERROR; 00300 } 00301 00302 /* Initiate a DMA transfer of PCM samples towards the serial audio interface */ 00303 if(ret == AUDIO_OK) 00304 { 00305 if (HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE))!= HAL_OK) 00306 { 00307 ret = AUDIO_ERROR; 00308 } 00309 } 00310 00311 return ret; 00312 } 00313 00314 /** 00315 * @brief Sends n-Bytes on the SAI interface. 00316 * @param pData: pointer on PCM samples buffer 00317 * @param Size: number of data to be written 00318 */ 00319 void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) 00320 { 00321 HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); 00322 } 00323 00324 /** 00325 * @brief This function Pauses the audio file stream. In case 00326 * of using DMA, the DMA Pause feature is used. 00327 * @warning When calling BSP_AUDIO_OUT_Pause() function for pause, only 00328 * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 00329 * function for resume could lead to unexpected behavior). 00330 * @retval AUDIO_OK if correct communication, else wrong communication 00331 */ 00332 uint8_t BSP_AUDIO_OUT_Pause(void) 00333 { 00334 uint8_t ret = AUDIO_OK; 00335 00336 /* Call the Audio Codec Pause/Resume function */ 00337 if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) 00338 { 00339 ret = AUDIO_ERROR; 00340 } 00341 00342 /* Pause DMA transfer of PCM samples towards the serial audio interface */ 00343 if(ret == AUDIO_OK) 00344 { 00345 if (HAL_SAI_DMAPause(&haudio_out_sai)!= HAL_OK) 00346 { 00347 ret = AUDIO_ERROR; 00348 } 00349 } 00350 00351 /* Return AUDIO_OK when all operations are correctly done */ 00352 return ret; 00353 } 00354 00355 /** 00356 * @brief This function Resumes the audio file stream. 00357 * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only 00358 * BSP_AUDIO_OUT_Resume() function should be called for resume 00359 * (use of BSP_AUDIO_OUT_Play() function for resume could lead to 00360 * unexpected behavior). 00361 * @retval AUDIO_OK if correct communication, else wrong communication 00362 */ 00363 uint8_t BSP_AUDIO_OUT_Resume(void) 00364 { 00365 uint8_t ret = AUDIO_OK; 00366 00367 /* Call the Audio Codec Pause/Resume function */ 00368 if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) 00369 { 00370 ret = AUDIO_ERROR; 00371 } 00372 00373 /* Resume DMA transfer of PCM samples towards the serial audio interface */ 00374 if(ret == AUDIO_OK) 00375 { 00376 if (HAL_SAI_DMAResume(&haudio_out_sai)!= HAL_OK) 00377 { 00378 ret = AUDIO_ERROR; 00379 } 00380 } 00381 00382 /* Return AUDIO_OK when all operations are correctly done */ 00383 return ret; 00384 } 00385 00386 /** 00387 * @brief Stops audio playing and Power down the Audio Codec. 00388 * @param Option: could be one of the following parameters 00389 * - CODEC_PDWN_SW: for software power off (by writing registers). 00390 * Then no need to reconfigure the Codec after power on. 00391 * - CODEC_PDWN_HW: completely shut down the codec (physically). 00392 * Then need to reconfigure the Codec after power on. 00393 * @retval AUDIO_OK if correct communication, else wrong communication 00394 */ 00395 uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) 00396 { 00397 uint8_t ret = AUDIO_OK; 00398 00399 /* Call Audio Codec Stop function */ 00400 if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) 00401 { 00402 ret = AUDIO_ERROR; 00403 } 00404 00405 if(ret == AUDIO_OK) 00406 { 00407 if(Option == CODEC_PDWN_HW) 00408 { 00409 /* Wait at least 100us */ 00410 HAL_Delay(2); 00411 } 00412 00413 /* Stop DMA transfer of PCM samples towards the serial audio interface */ 00414 if (HAL_SAI_DMAStop(&haudio_out_sai)!= HAL_OK) 00415 { 00416 ret = AUDIO_ERROR; 00417 } 00418 } 00419 /* Return AUDIO_OK when all operations are correctly done */ 00420 return ret; 00421 } 00422 00423 /** 00424 * @brief Controls the current audio volume level. 00425 * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for 00426 * Mute and 100 for Max volume level). 00427 * @retval AUDIO_OK if correct communication, else wrong communication 00428 */ 00429 uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) 00430 { 00431 uint8_t ret = AUDIO_OK; 00432 00433 /* Call the codec volume control function with converted volume value */ 00434 if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) 00435 { 00436 ret = AUDIO_ERROR; 00437 } 00438 00439 /* Return AUDIO_OK when all operations are correctly done */ 00440 return ret; 00441 } 00442 00443 /** 00444 * @brief Enables or disables the MUTE mode by software 00445 * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to 00446 * unmute the codec and restore previous volume level. 00447 * @retval AUDIO_OK if correct communication, else wrong communication 00448 */ 00449 uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) 00450 { 00451 uint8_t ret = AUDIO_OK; 00452 00453 /* Call the Codec Mute function */ 00454 if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) 00455 { 00456 ret = AUDIO_ERROR; 00457 } 00458 00459 /* Return AUDIO_OK when all operations are correctly done */ 00460 return ret; 00461 } 00462 00463 /** 00464 * @brief Switch dynamically (while audio file is being played) the output 00465 * target (speaker or headphone). 00466 * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, 00467 * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH 00468 * @retval AUDIO_OK if correct communication, else wrong communication 00469 */ 00470 uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) 00471 { 00472 uint8_t ret = AUDIO_OK; 00473 00474 /* Call the Codec output device function */ 00475 if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) 00476 { 00477 ret = AUDIO_ERROR; 00478 } 00479 00480 /* Return AUDIO_OK when all operations are correctly done */ 00481 return ret; 00482 } 00483 00484 /** 00485 * @brief Updates the audio frequency. 00486 * @param AudioFreq: Audio frequency used to play the audio stream. 00487 * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the 00488 * audio frequency. 00489 */ 00490 void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) 00491 { 00492 /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 00493 BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); 00494 00495 /* Disable SAI peripheral to allow access to SAI internal registers */ 00496 __HAL_SAI_DISABLE(&haudio_out_sai); 00497 00498 /* Update the SAI audio frequency configuration */ 00499 haudio_out_sai.Init.AudioFrequency = AudioFreq; 00500 HAL_SAI_Init(&haudio_out_sai); 00501 00502 /* Enable SAI peripheral to generate MCLK */ 00503 __HAL_SAI_ENABLE(&haudio_out_sai); 00504 } 00505 00506 /** 00507 * @brief Changes the Audio Out Configuration. 00508 * @param AudioOutOption: specifies the audio out new configuration 00509 * This parameter can be any value of @ref BSP_Audio_Out_Option 00510 * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the 00511 * audio out configuration. 00512 */ 00513 void BSP_AUDIO_OUT_ChangeAudioConfig(uint32_t AudioOutOption) 00514 { 00515 /********** Playback Buffer circular/normal mode **********/ 00516 if(AudioOutOption & BSP_AUDIO_OUT_CIRCULARMODE) 00517 { 00518 /* Deinitialize the Stream to update DMA mode */ 00519 HAL_DMA_DeInit(haudio_out_sai.hdmatx); 00520 00521 /* Update the SAI audio Transfer DMA mode */ 00522 haudio_out_sai.hdmatx->Init.Mode = DMA_CIRCULAR; 00523 00524 /* Configure the DMA Stream with new Transfer DMA mode */ 00525 HAL_DMA_Init(haudio_out_sai.hdmatx); 00526 } 00527 else /* BSP_AUDIO_OUT_NORMALMODE */ 00528 { 00529 /* Deinitialize the Stream to update DMA mode */ 00530 HAL_DMA_DeInit(haudio_out_sai.hdmatx); 00531 00532 /* Update the SAI audio Transfer DMA mode */ 00533 haudio_out_sai.hdmatx->Init.Mode = DMA_NORMAL; 00534 00535 /* Configure the DMA Stream with new Transfer DMA mode */ 00536 HAL_DMA_Init(haudio_out_sai.hdmatx); 00537 } 00538 00539 /********** Playback Buffer stereo/mono mode **********/ 00540 if(AudioOutOption & BSP_AUDIO_OUT_STEREOMODE) 00541 { 00542 /* Disable SAI peripheral to allow access to SAI internal registers */ 00543 __HAL_SAI_DISABLE(&haudio_out_sai); 00544 00545 /* Update the SAI audio frame slot configuration */ 00546 haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; 00547 HAL_SAI_Init(&haudio_out_sai); 00548 00549 /* Enable SAI peripheral to generate MCLK */ 00550 __HAL_SAI_ENABLE(&haudio_out_sai); 00551 } 00552 else /* BSP_AUDIO_OUT_MONOMODE */ 00553 { 00554 /* Disable SAI peripheral to allow access to SAI internal registers */ 00555 __HAL_SAI_DISABLE(&haudio_out_sai); 00556 00557 /* Update the SAI audio frame slot configuration */ 00558 haudio_out_sai.Init.MonoStereoMode = SAI_MONOMODE; 00559 HAL_SAI_Init(&haudio_out_sai); 00560 00561 /* Enable SAI peripheral to generate MCLK */ 00562 __HAL_SAI_ENABLE(&haudio_out_sai); 00563 } 00564 } 00565 00566 /** 00567 * @brief Updates the Audio frame slot configuration. 00568 * @param AudioFrameSlot: specifies the audio Frame slot 00569 * This parameter can be any value of @ref CODEC_AudioFrame_SLOT_TDMMode 00570 * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the 00571 * audio frame slot. 00572 */ 00573 void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) 00574 { 00575 /* Disable SAI peripheral to allow access to SAI internal registers */ 00576 __HAL_SAI_DISABLE(&haudio_out_sai); 00577 00578 /* Update the SAI audio frame slot configuration */ 00579 haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; 00580 HAL_SAI_Init(&haudio_out_sai); 00581 00582 /* Enable SAI peripheral to generate MCLK */ 00583 __HAL_SAI_ENABLE(&haudio_out_sai); 00584 } 00585 00586 /** 00587 * @brief Deinit the audio peripherals. 00588 */ 00589 void BSP_AUDIO_OUT_DeInit(void) 00590 { 00591 SAIx_DeInit(); 00592 /* DeInit the SAI MSP : this __weak function can be rewritten by the applic */ 00593 BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); 00594 00595 /* Reset the audio output context */ 00596 memset(&audio_drv, 0, sizeof(audio_drv)); 00597 } 00598 00599 /** 00600 * @brief Tx Transfer completed callbacks. 00601 * @param hsai: SAI handle 00602 */ 00603 void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) 00604 { 00605 /* Manage the remaining file size and new address offset: This function 00606 should be coded by user (its prototype is already declared in stm32469i_discovery_audio.h) */ 00607 BSP_AUDIO_OUT_TransferComplete_CallBack(); 00608 } 00609 00610 /** 00611 * @brief Tx Half Transfer completed callbacks. 00612 * @param hsai: SAI handle 00613 */ 00614 void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) 00615 { 00616 /* Manage the remaining file size and new address offset: This function 00617 should be coded by user (its prototype is already declared in stm32469i_discovery_audio.h) */ 00618 BSP_AUDIO_OUT_HalfTransfer_CallBack(); 00619 } 00620 00621 /** 00622 * @brief SAI error callbacks. 00623 * @param hsai: SAI handle 00624 */ 00625 void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) 00626 { 00627 BSP_AUDIO_OUT_Error_CallBack(); 00628 } 00629 00630 /** 00631 * @brief Manages the DMA full Transfer complete event. 00632 */ 00633 __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) 00634 { 00635 } 00636 00637 /** 00638 * @brief Manages the DMA Half Transfer complete event. 00639 */ 00640 __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) 00641 { 00642 } 00643 00644 /** 00645 * @brief Manages the DMA FIFO error event. 00646 */ 00647 __weak void BSP_AUDIO_OUT_Error_CallBack(void) 00648 { 00649 } 00650 00651 /** 00652 * @brief Initializes BSP_AUDIO_OUT MSP. 00653 * @param hsai: SAI handle 00654 * @param Params : pointer on additional configuration parameters, can be NULL. 00655 */ 00656 __weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) 00657 { 00658 static DMA_HandleTypeDef hdma_sai_tx; 00659 GPIO_InitTypeDef gpio_init_structure; 00660 00661 /* Put CS43L2 codec reset high -----------------------------------*/ 00662 AUDIO_RESET_ENABLE(); 00663 gpio_init_structure.Pin = AUDIO_RESET_PIN; 00664 gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; 00665 gpio_init_structure.Pull = GPIO_NOPULL; 00666 gpio_init_structure.Speed = GPIO_SPEED_HIGH; 00667 HAL_GPIO_Init(AUDIO_RESET_GPIO_PORT, &gpio_init_structure); 00668 HAL_GPIO_WritePin(AUDIO_RESET_GPIO_PORT, AUDIO_RESET_PIN, GPIO_PIN_SET); 00669 00670 /* Enable SAI clock */ 00671 AUDIO_SAIx_CLK_ENABLE(); 00672 00673 /* Enable GPIO clock */ 00674 AUDIO_SAIx_MCLK_ENABLE(); 00675 AUDIO_SAIx_SCK_SD_FS_ENABLE(); 00676 00677 /* CODEC_SAI pins configuration: MCK pin -----------------------------------*/ 00678 gpio_init_structure.Pin = AUDIO_SAIx_MCK_PIN; 00679 gpio_init_structure.Mode = GPIO_MODE_AF_PP; 00680 gpio_init_structure.Pull = GPIO_NOPULL; 00681 gpio_init_structure.Speed = GPIO_SPEED_HIGH; 00682 gpio_init_structure.Alternate = AUDIO_SAIx_MCLK_SCK_SD_FS_AF; 00683 HAL_GPIO_Init(AUDIO_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); 00684 00685 /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ 00686 gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SCK_PIN | AUDIO_SAIx_SD_PIN; 00687 gpio_init_structure.Mode = GPIO_MODE_AF_PP; 00688 gpio_init_structure.Pull = GPIO_NOPULL; 00689 gpio_init_structure.Speed = GPIO_SPEED_HIGH; 00690 gpio_init_structure.Alternate = AUDIO_SAIx_MCLK_SCK_SD_FS_AF; 00691 HAL_GPIO_Init(AUDIO_SAIx_SCK_SD_FS_GPIO_PORT, &gpio_init_structure); 00692 00693 /* Enable the DMA clock */ 00694 AUDIO_SAIx_DMAx_CLK_ENABLE(); 00695 00696 if(hsai->Instance == AUDIO_SAIx) 00697 { 00698 /* Configure the hdma_saiTx handle parameters */ 00699 hdma_sai_tx.Init.Channel = AUDIO_SAIx_DMAx_CHANNEL; 00700 hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; 00701 hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; 00702 hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; 00703 hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE; 00704 hdma_sai_tx.Init.MemDataAlignment = AUDIO_SAIx_DMAx_MEM_DATA_SIZE; 00705 hdma_sai_tx.Init.Mode = DMA_CIRCULAR; 00706 hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; 00707 hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; 00708 hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; 00709 hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; 00710 hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; 00711 00712 hdma_sai_tx.Instance = AUDIO_SAIx_DMAx_STREAM; 00713 00714 /* Associate the DMA handle */ 00715 __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); 00716 00717 /* Deinitialize the Stream for new transfer */ 00718 HAL_DMA_DeInit(&hdma_sai_tx); 00719 00720 /* Configure the DMA Stream */ 00721 HAL_DMA_Init(&hdma_sai_tx); 00722 } 00723 00724 /* SAI DMA IRQ Channel configuration */ 00725 HAL_NVIC_SetPriority(AUDIO_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); 00726 HAL_NVIC_EnableIRQ(AUDIO_SAIx_DMAx_IRQ); 00727 00728 } 00729 /** 00730 * @brief Deinitializes BSP_AUDIO_OUT MSP. 00731 * @param hsai: SAI handle 00732 * @param Params : pointer on additional configuration parameters, can be NULL. 00733 */ 00734 __weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) 00735 { 00736 GPIO_InitTypeDef gpio_init_structure; 00737 00738 /* SAI DMA IRQ Channel deactivation */ 00739 HAL_NVIC_DisableIRQ(AUDIO_SAIx_DMAx_IRQ); 00740 00741 if(hsai->Instance == AUDIO_SAIx) 00742 { 00743 /* Deinitialize the DMA stream */ 00744 HAL_DMA_DeInit(hsai->hdmatx); 00745 } 00746 00747 /* Disable SAI peripheral */ 00748 __HAL_SAI_DISABLE(hsai); 00749 00750 /* Put CS43L2 codec reset low -----------------------------------*/ 00751 HAL_GPIO_WritePin(AUDIO_RESET_GPIO_PORT, AUDIO_RESET_PIN, GPIO_PIN_RESET); 00752 00753 /* Deactives CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ 00754 gpio_init_structure.Pin = AUDIO_SAIx_MCK_PIN; 00755 HAL_GPIO_DeInit(AUDIO_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); 00756 00757 gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN | AUDIO_SAIx_SCK_PIN | AUDIO_SAIx_SD_PIN; 00758 HAL_GPIO_DeInit(AUDIO_SAIx_SCK_SD_FS_GPIO_PORT, gpio_init_structure.Pin); 00759 00760 gpio_init_structure.Pin = AUDIO_RESET_PIN; 00761 HAL_GPIO_DeInit(AUDIO_RESET_GPIO_PORT, gpio_init_structure.Pin); 00762 00763 00764 /* Disable SAI clock */ 00765 AUDIO_SAIx_CLK_DISABLE(); 00766 00767 00768 /* GPIO pins clock and DMA clock can be shut down in the applic 00769 by surcgarging this __weak function */ 00770 } 00771 00772 /** 00773 * @brief Clock Config. 00774 * @param hsai: might be required to set audio peripheral predivider if any. 00775 * @param AudioFreq: Audio frequency used to play the audio stream. 00776 * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() 00777 * Being __weak it can be overwritten by the application 00778 * @param Params : pointer on additional configuration parameters, can be NULL. 00779 */ 00780 __weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) 00781 { 00782 RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; 00783 00784 HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); 00785 00786 /* Set the PLL configuration according to the audio frequency */ 00787 if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) 00788 { 00789 /* Configure PLLI2S prescalers */ 00790 /* PLLI2S_VCO: VCO_429M 00791 I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz 00792 I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */ 00793 rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI_PLLI2S; 00794 rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; 00795 rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; 00796 rcc_ex_clk_init_struct.PLLI2SDivQ = 19; 00797 00798 HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); 00799 00800 } 00801 else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */ 00802 { 00803 /* SAI clock config 00804 PLLSAI_VCO: VCO_344M 00805 I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz 00806 I2S_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */ 00807 rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI_PLLI2S; 00808 rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; 00809 rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; 00810 rcc_ex_clk_init_struct.PLLI2SDivQ = 1; 00811 00812 HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); 00813 } 00814 } 00815 00816 /******************************************************************************* 00817 Static Functions 00818 *******************************************************************************/ 00819 /** 00820 * @brief Initializes the Audio Codec audio interface (SAI). 00821 * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. 00822 * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 00823 * and user can update this configuration using 00824 */ 00825 static uint8_t SAIx_Init(uint32_t AudioFreq) 00826 { 00827 uint8_t ret = AUDIO_OK; 00828 00829 /* Initialize the haudio_out_sai Instance parameter */ 00830 haudio_out_sai.Instance = AUDIO_SAIx; 00831 00832 /* Disable SAI peripheral to allow access to SAI internal registers */ 00833 __HAL_SAI_DISABLE(&haudio_out_sai); 00834 00835 /* Configure SAI_Block_x 00836 LSBFirst: Disabled 00837 DataSize: 16 */ 00838 haudio_out_sai.Init.AudioFrequency = AudioFreq; 00839 haudio_out_sai.Init.ClockSource = SAI_CLKSOURCE_PLLI2S; 00840 haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; 00841 haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; 00842 haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; 00843 haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; 00844 haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; 00845 haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; 00846 haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; 00847 haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; 00848 haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; 00849 /* 00850 haudio_out_sai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV; 00851 haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; 00852 haudio_out_sai.Init.Mckdiv = SAIClockDivider(AudioFreq); 00853 haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; 00854 haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; 00855 haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; 00856 */ 00857 00858 /* Configure SAI_Block_x Frame 00859 Frame Length: 64 00860 Frame active Length: 32 00861 FS Definition: Start frame + Channel Side identification 00862 FS Polarity: FS active Low 00863 FS Offset: FS asserted one bit before the first bit of slot 0 */ 00864 haudio_out_sai.FrameInit.FrameLength = 64; 00865 haudio_out_sai.FrameInit.ActiveFrameLength = 32; 00866 haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; 00867 haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; 00868 haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; 00869 00870 /* Configure SAI Block_x Slot 00871 Slot First Bit Offset: 0 00872 Slot Size : 16 00873 Slot Number: 4 00874 Slot Active: All slot actives */ 00875 haudio_out_sai.SlotInit.FirstBitOffset = 0; 00876 haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; 00877 haudio_out_sai.SlotInit.SlotNumber = 4; 00878 haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; 00879 00880 /* Initializes the SAI peripheral*/ 00881 if (HAL_SAI_Init(&haudio_out_sai) != HAL_OK) 00882 { 00883 ret = AUDIO_ERROR; 00884 } 00885 00886 /* Enable SAI peripheral to generate MCLK */ 00887 __HAL_SAI_ENABLE(&haudio_out_sai); 00888 00889 return ret; 00890 00891 } 00892 00893 /** 00894 * @brief Deinitializes the Audio Codec audio interface (SAI). 00895 */ 00896 static void SAIx_DeInit(void) 00897 { 00898 /* Initialize the hAudioOutSai Instance parameter */ 00899 haudio_out_sai.Instance = AUDIO_SAIx; 00900 00901 /* Disable SAI peripheral */ 00902 __HAL_SAI_DISABLE(&haudio_out_sai); 00903 00904 HAL_SAI_DeInit(&haudio_out_sai); 00905 } 00906 00907 /** 00908 * @} 00909 */ 00910 00911 /** @defgroup STM32469I-Discovery_AUDIO_in_Private_Functions STM32469I Discovery AUDIO IN Private functions 00912 * @{ 00913 */ 00914 00915 /** 00916 * @brief Initializes wave recording. 00917 * @note This function assumes that the I2S input clock (through PLL_R in 00918 * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y) 00919 * is already configured and ready to be used. 00920 * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 00921 * @param BitRes: Audio frequency to be configured for the I2S peripheral. 00922 * @param ChnlNbr: Audio frequency to be configured for the I2S peripheral. 00923 * @retval AUDIO_OK if correct communication, else wrong communication 00924 */ 00925 uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) 00926 { 00927 /* DeInit the I2S */ 00928 I2Sx_DeInit(); 00929 00930 /* Configure PLL clock */ 00931 BSP_AUDIO_IN_ClockConfig(&haudio_in_i2s, NULL); 00932 00933 /* Configure the PDM library */ 00934 PDMDecoder_Init(AudioFreq, ChnlNbr); 00935 00936 /* Configure the I2S peripheral */ 00937 haudio_in_i2s.Instance = AUDIO_I2Sx; 00938 if(HAL_I2S_GetState(&haudio_in_i2s) == HAL_I2S_STATE_RESET) 00939 { 00940 /* Initialize the I2S Msp: this __weak function can be rewritten by the application */ 00941 BSP_AUDIO_IN_MspInit(&haudio_in_i2s, NULL); 00942 } 00943 00944 I2Sx_Init(AudioFreq); 00945 00946 /* Return AUDIO_OK when all operations are correctly done */ 00947 return AUDIO_OK; 00948 } 00949 00950 /** 00951 * @brief Starts audio recording. 00952 * @param pbuf: Main buffer pointer for the recorded data storing 00953 * @param size: Current size of the recorded buffer 00954 * @retval AUDIO_OK if correct communication, else wrong communication 00955 */ 00956 uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) 00957 { 00958 uint32_t ret = AUDIO_ERROR; 00959 00960 /* Start the process receive DMA */ 00961 HAL_I2S_Receive_DMA(&haudio_in_i2s, pbuf, size); 00962 00963 /* Return AUDIO_OK when all operations are correctly done */ 00964 ret = AUDIO_OK; 00965 00966 return ret; 00967 } 00968 00969 /** 00970 * @brief Stops audio recording. 00971 * @retval AUDIO_OK if correct communication, else wrong communication 00972 */ 00973 uint8_t BSP_AUDIO_IN_Stop(void) 00974 { 00975 uint32_t ret = AUDIO_ERROR; 00976 00977 /* Call the Media layer pause function */ 00978 HAL_I2S_DMAPause(&haudio_in_i2s); 00979 00980 /* TIMx Peripheral clock disable */ 00981 AUDIO_TIMx_CLK_DISABLE(); 00982 00983 /* Return AUDIO_OK when all operations are correctly done */ 00984 ret = AUDIO_OK; 00985 00986 return ret; 00987 } 00988 00989 /** 00990 * @brief Pauses the audio file stream. 00991 * @retval AUDIO_OK if correct communication, else wrong communication 00992 */ 00993 uint8_t BSP_AUDIO_IN_Pause(void) 00994 { 00995 /* Call the Media layer pause function */ 00996 HAL_I2S_DMAPause(&haudio_in_i2s); 00997 00998 /* Return AUDIO_OK when all operations are correctly done */ 00999 return AUDIO_OK; 01000 } 01001 01002 /** 01003 * @brief Resumes the audio file stream. 01004 * @retval AUDIO_OK if correct communication, else wrong communication 01005 */ 01006 uint8_t BSP_AUDIO_IN_Resume(void) 01007 { 01008 /* Call the Media layer pause/resume function */ 01009 HAL_I2S_DMAResume(&haudio_in_i2s); 01010 01011 /* Return AUDIO_OK when all operations are correctly done */ 01012 return AUDIO_OK; 01013 } 01014 01015 /** 01016 * @brief Controls the audio in volume level. 01017 * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for 01018 * Mute and 100 for Max volume level). 01019 * @retval AUDIO_OK if correct communication, else wrong communication 01020 */ 01021 uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) 01022 { 01023 /* Set the Global variable AudioInVolume */ 01024 AudioInVolume = Volume; 01025 01026 /* Return AUDIO_OK when all operations are correctly done */ 01027 return AUDIO_OK; 01028 } 01029 01030 /** 01031 * @brief Deinit the audio IN peripherals. 01032 */ 01033 void BSP_AUDIO_IN_DeInit(void) 01034 { 01035 I2Sx_DeInit(); 01036 /* DeInit the I2S MSP : this __weak function can be rewritten by the applic */ 01037 BSP_AUDIO_IN_MspDeInit(&haudio_in_i2s, NULL); 01038 TIMx_DeInit(); 01039 } 01040 01041 /** 01042 * @brief Converts audio format from PDM to PCM. 01043 * @param PDMBuf: Pointer to data PDM buffer 01044 * @param PCMBuf: Pointer to data PCM buffer 01045 * @retval AUDIO_OK if correct communication, else wrong communication 01046 */ 01047 uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t* PDMBuf, uint16_t* PCMBuf) 01048 { 01049 uint8_t app_pdm[INTERNAL_BUFF_SIZE*2]; 01050 uint8_t byte1 = 0, byte2 = 0; 01051 uint32_t index = 0; 01052 01053 /* PDM Demux */ 01054 for(index = 0; index<INTERNAL_BUFF_SIZE/2; index++) 01055 { 01056 byte2 = (PDMBuf[index] >> 8)& 0xFF; 01057 byte1 = (PDMBuf[index] & 0xFF); 01058 app_pdm[(index*2)+1] = Channel_Demux[byte1 & CHANNEL_DEMUX_MASK] | Channel_Demux[byte2 & CHANNEL_DEMUX_MASK] << 4; 01059 app_pdm[(index*2)] = Channel_Demux[(byte1 >> 1) & CHANNEL_DEMUX_MASK] | Channel_Demux[(byte2 >> 1) & CHANNEL_DEMUX_MASK] << 4; 01060 } 01061 01062 for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++) 01063 { 01064 /* PDM to PCM filter */ 01065 PDM_Filter_64_LSB((uint8_t*)&app_pdm[index], (uint16_t*)&(PCMBuf[index]), AudioInVolume , (PDMFilter_InitStruct *)&Filter[index]); 01066 } 01067 01068 /* Return AUDIO_OK when all operations are correctly done */ 01069 return AUDIO_OK; 01070 } 01071 01072 /** 01073 * @brief Rx Transfer completed callbacks. 01074 * @param hi2s: I2S handle 01075 */ 01076 void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) 01077 { 01078 /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ 01079 BSP_AUDIO_IN_TransferComplete_CallBack(); 01080 } 01081 01082 /** 01083 * @brief Rx Half Transfer completed callbacks. 01084 * @param hi2s: I2S handle 01085 */ 01086 void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) 01087 { 01088 /* Manage the remaining file size and new address offset: This function 01089 should be coded by user (its prototype is already declared in stm32469i_discovery_audio.h) */ 01090 BSP_AUDIO_IN_HalfTransfer_CallBack(); 01091 } 01092 01093 /** 01094 * @brief I2S error callbacks. 01095 * @param hi2s: I2S handle 01096 */ 01097 void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) 01098 { 01099 /* Manage the error generated on DMA FIFO: This function 01100 should be coded by user (its prototype is already declared in stm32469i_discovery_audio.h) */ 01101 BSP_AUDIO_IN_Error_Callback(); 01102 } 01103 01104 /** 01105 * @brief Clock Config. 01106 * @param hi2s: I2S handle 01107 * @param Params : pointer on additional configuration parameters, can be NULL. 01108 * @note This API is called by BSP_AUDIO_IN_Init() 01109 * Being __weak it can be overwritten by the application 01110 */ 01111 __weak void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, void *Params) 01112 { 01113 RCC_PeriphCLKInitTypeDef RCC_ExCLKInitStruct; 01114 01115 HAL_RCCEx_GetPeriphCLKConfig(&RCC_ExCLKInitStruct); 01116 RCC_ExCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S; 01117 RCC_ExCLKInitStruct.PLLI2S.PLLI2SN = 384; 01118 RCC_ExCLKInitStruct.PLLI2S.PLLI2SR = 2; 01119 HAL_RCCEx_PeriphCLKConfig(&RCC_ExCLKInitStruct); 01120 } 01121 01122 /** 01123 * @brief User callback when record buffer is filled. 01124 */ 01125 __weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) 01126 { 01127 /* This function should be implemented by the user application. 01128 It is called into this driver when the current buffer is filled 01129 to prepare the next buffer pointer and its size. */ 01130 } 01131 01132 /** 01133 * @brief Manages the DMA Half Transfer complete event. 01134 */ 01135 __weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) 01136 { 01137 /* This function should be implemented by the user application. 01138 It is called into this driver when the current buffer is filled 01139 to prepare the next buffer pointer and its size. */ 01140 } 01141 01142 /** 01143 * @brief Audio IN Error callback function. 01144 */ 01145 __weak void BSP_AUDIO_IN_Error_Callback(void) 01146 { 01147 /* This function is called when an Interrupt due to transfer error on or peripheral 01148 error occurs. */ 01149 } 01150 01151 /** 01152 * @brief BSP AUDIO IN MSP Init. 01153 * @param hi2s: I2S handle 01154 * @param Params : pointer on additional configuration parameters, can be NULL. 01155 */ 01156 __weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params) 01157 { 01158 static DMA_HandleTypeDef hdma_i2s_rx; 01159 GPIO_InitTypeDef gpio_init_structure; 01160 01161 /* Configure the Timer which clocks the MEMS */ 01162 /* Moved inside MSP to allow applic to redefine the TIMx_MspInit */ 01163 TIMx_Init(); 01164 01165 /* Enable I2S clock */ 01166 AUDIO_I2Sx_CLK_ENABLE(); 01167 01168 /* Enable SCK and SD GPIO clock */ 01169 AUDIO_I2Sx_SD_GPIO_CLK_ENABLE(); 01170 AUDIO_I2Sx_SCK_GPIO_CLK_ENABLE(); 01171 /* CODEC_I2S pins configuration: SCK and SD pins */ 01172 gpio_init_structure.Pin = AUDIO_I2Sx_SCK_PIN; 01173 gpio_init_structure.Mode = GPIO_MODE_AF_PP; 01174 gpio_init_structure.Pull = GPIO_NOPULL; 01175 gpio_init_structure.Speed = GPIO_SPEED_FAST; 01176 gpio_init_structure.Alternate = AUDIO_I2Sx_SCK_AF; 01177 HAL_GPIO_Init(AUDIO_I2Sx_SCK_GPIO_PORT, &gpio_init_structure); 01178 01179 gpio_init_structure.Pin = AUDIO_I2Sx_SD_PIN; 01180 gpio_init_structure.Alternate = AUDIO_I2Sx_SD_AF; 01181 HAL_GPIO_Init(AUDIO_I2Sx_SD_GPIO_PORT, &gpio_init_structure); 01182 01183 /* Enable PD12 (I2S3_CLK) connected to PB3 via jamper JP4 */ 01184 /* on Eval this was provided by PC6 (initialized in TIMx section) */ 01185 /* 01186 gpio_init_structure.Pin = GPIO_PIN_12; 01187 gpio_init_structure.Mode = GPIO_MODE_AF_PP; 01188 gpio_init_structure.Pull = GPIO_NOPULL; 01189 gpio_init_structure.Speed = GPIO_SPEED_FAST; 01190 gpio_init_structure.Alternate = AUDIO_I2Sx_SCK_AF; 01191 HAL_GPIO_Init(GPIOD, &gpio_init_structure); */ 01192 01193 01194 /* Enable the DMA clock */ 01195 AUDIO_I2Sx_DMAx_CLK_ENABLE(); 01196 01197 if(hi2s->Instance == AUDIO_I2Sx) 01198 { 01199 /* Configure the hdma_i2sRx handle parameters */ 01200 hdma_i2s_rx.Init.Channel = AUDIO_I2Sx_DMAx_CHANNEL; 01201 hdma_i2s_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; 01202 hdma_i2s_rx.Init.PeriphInc = DMA_PINC_DISABLE; 01203 hdma_i2s_rx.Init.MemInc = DMA_MINC_ENABLE; 01204 hdma_i2s_rx.Init.PeriphDataAlignment = AUDIO_I2Sx_DMAx_PERIPH_DATA_SIZE; 01205 hdma_i2s_rx.Init.MemDataAlignment = AUDIO_I2Sx_DMAx_MEM_DATA_SIZE; 01206 hdma_i2s_rx.Init.Mode = DMA_CIRCULAR; 01207 hdma_i2s_rx.Init.Priority = DMA_PRIORITY_HIGH; 01208 hdma_i2s_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 01209 hdma_i2s_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; 01210 hdma_i2s_rx.Init.MemBurst = DMA_MBURST_SINGLE; 01211 hdma_i2s_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; 01212 01213 hdma_i2s_rx.Instance = AUDIO_I2Sx_DMAx_STREAM; 01214 01215 /* Associate the DMA handle */ 01216 __HAL_LINKDMA(hi2s, hdmarx, hdma_i2s_rx); 01217 01218 /* Deinitialize the Stream for new transfer */ 01219 HAL_DMA_DeInit(&hdma_i2s_rx); 01220 01221 /* Configure the DMA Stream */ 01222 HAL_DMA_Init(&hdma_i2s_rx); 01223 } 01224 01225 /* I2S DMA IRQ Channel configuration */ 01226 HAL_NVIC_SetPriority(AUDIO_I2Sx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); 01227 HAL_NVIC_EnableIRQ(AUDIO_I2Sx_DMAx_IRQ); 01228 } 01229 01230 /** 01231 * @brief DeInitializes BSP_AUDIO_IN MSP. 01232 * @param hi2s: I2S handle 01233 * @param Params : pointer on additional configuration parameters, can be NULL. 01234 */ 01235 __weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params) 01236 { 01237 GPIO_InitTypeDef gpio_init_structure; 01238 01239 /* I2S DMA IRQ Channel deactivation */ 01240 HAL_NVIC_DisableIRQ(AUDIO_I2Sx_DMAx_IRQ); 01241 01242 if(hi2s->Instance == AUDIO_I2Sx) 01243 { 01244 /* Deinitialize the Stream for new transfer */ 01245 HAL_DMA_DeInit(hi2s->hdmarx); 01246 } 01247 01248 /* Disable I2S block */ 01249 __HAL_I2S_DISABLE(hi2s); 01250 01251 /* Disable pins: SCK and SD pins */ 01252 gpio_init_structure.Pin = AUDIO_I2Sx_SCK_PIN; 01253 HAL_GPIO_DeInit(AUDIO_I2Sx_SCK_GPIO_PORT, gpio_init_structure.Pin); 01254 gpio_init_structure.Pin = AUDIO_I2Sx_SD_PIN; 01255 HAL_GPIO_DeInit(AUDIO_I2Sx_SD_GPIO_PORT, gpio_init_structure.Pin); 01256 01257 /* Disable I2S clock */ 01258 AUDIO_I2Sx_CLK_DISABLE(); 01259 01260 /* GPIO pins clock and DMA clock can be shut down in the applic 01261 by surcgarging this __weak function */ 01262 } 01263 01264 /******************************************************************************* 01265 Static Functions 01266 *******************************************************************************/ 01267 01268 /** 01269 * @brief Initializes the PDM library. 01270 * @param AudioFreq: Audio sampling frequency 01271 * @param ChnlNbr: Number of audio channels (1: mono; 2: stereo) 01272 */ 01273 static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr) 01274 { 01275 uint32_t i = 0; 01276 01277 /* Enable CRC peripheral to unlock the PDM library */ 01278 __HAL_RCC_CRC_CLK_ENABLE(); 01279 01280 for(i = 0; i < ChnlNbr; i++) 01281 { 01282 /* Filter LP & HP Init */ 01283 Filter[i].LP_HZ = AudioFreq/2; 01284 Filter[i].HP_HZ = 10; 01285 Filter[i].Fs = AudioFreq; 01286 Filter[i].Out_MicChannels = ChnlNbr; 01287 Filter[i].In_MicChannels = ChnlNbr; 01288 PDM_Filter_Init((PDMFilter_InitStruct *)&Filter[i]); 01289 } 01290 } 01291 01292 /** 01293 * @brief Initializes the Audio Codec audio interface (I2S) 01294 * @note This function assumes that the I2S input clock (through dedicated PLLI2S_R) 01295 * is already configured and ready to be used. 01296 * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 01297 */ 01298 static void I2Sx_Init(uint32_t AudioFreq) 01299 { 01300 /* Initialize the haudio_in_i2s Instance parameter */ 01301 haudio_in_i2s.Instance = AUDIO_I2Sx; 01302 01303 /* Disable I2S block */ 01304 __HAL_I2S_DISABLE(&haudio_in_i2s); 01305 01306 /* I2S2 peripheral configuration */ 01307 haudio_in_i2s.Init.AudioFreq = 4 * AudioFreq; 01308 haudio_in_i2s.Init.ClockSource = I2S_CLOCK_PLL; 01309 haudio_in_i2s.Init.CPOL = I2S_CPOL_LOW; 01310 haudio_in_i2s.Init.DataFormat = I2S_DATAFORMAT_16B; 01311 haudio_in_i2s.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; 01312 haudio_in_i2s.Init.Mode = I2S_MODE_MASTER_RX; 01313 haudio_in_i2s.Init.Standard = I2S_STANDARD_LSB; 01314 01315 /* Init the I2S */ 01316 HAL_I2S_Init(&haudio_in_i2s); 01317 01318 /* Disable I2S block */ 01319 __HAL_I2S_ENABLE(&haudio_in_i2s); 01320 01321 } 01322 01323 /** 01324 * @brief Deinitializes the Audio Codec audio interface (I2S). 01325 */ 01326 static void I2Sx_DeInit(void) 01327 { 01328 /* Initialize the hAudioInI2s Instance parameter */ 01329 haudio_in_i2s.Instance = AUDIO_I2Sx; 01330 01331 /* Disable I2S block */ 01332 __HAL_I2S_DISABLE(&haudio_in_i2s); 01333 01334 /* DeInit the I2S */ 01335 HAL_I2S_DeInit(&haudio_in_i2s); 01336 } 01337 01338 01339 /** 01340 * @brief Initializes the TIM INput Capture MSP. 01341 * @param htim: TIM handle 01342 */ 01343 static void TIMx_IC_MspInit(TIM_HandleTypeDef *htim) 01344 { 01345 GPIO_InitTypeDef gpio_init_structure; 01346 01347 /* Enable peripherals and GPIO Clocks --------------------------------------*/ 01348 /* TIMx Peripheral clock enable */ 01349 AUDIO_TIMx_CLK_ENABLE(); 01350 01351 /* Enable GPIO Channels Clock */ 01352 AUDIO_TIMx_GPIO_CLK_ENABLE(); 01353 01354 /* Configure I/Os ----------------------------------------------------------*/ 01355 /* Common configuration for all channels */ 01356 gpio_init_structure.Mode = GPIO_MODE_AF_PP; 01357 gpio_init_structure.Pull = GPIO_NOPULL; 01358 gpio_init_structure.Speed = GPIO_SPEED_HIGH; 01359 gpio_init_structure.Alternate = AUDIO_TIMx_AF; 01360 01361 /* Configure TIM input channel */ 01362 gpio_init_structure.Pin = AUDIO_TIMx_IN_GPIO_PIN; 01363 HAL_GPIO_Init(AUDIO_TIMx_GPIO_PORT, &gpio_init_structure); 01364 01365 /* Configure TIM output channel */ 01366 gpio_init_structure.Pin = AUDIO_TIMx_OUT_GPIO_PIN; 01367 HAL_GPIO_Init(AUDIO_TIMx_GPIO_PORT, &gpio_init_structure); 01368 } 01369 01370 /** 01371 * @brief Initializes the TIM INput Capture MSP. 01372 * @param htim: TIM handle 01373 */ 01374 static void TIMx_IC_MspDeInit(TIM_HandleTypeDef *htim) 01375 { 01376 /* Disable TIMx Peripheral clock */ 01377 AUDIO_TIMx_CLK_DISABLE(); 01378 01379 /* GPIO pins clock and DMA clock can be shut down in the applic 01380 by surcgarging this __weak function */ 01381 } 01382 01383 /** 01384 * @brief Configure TIM as a clock divider by 2. 01385 * I2S_SCK is externally connected to TIMx input channel 01386 */ 01387 static void TIMx_Init(void) 01388 { 01389 TIM_IC_InitTypeDef s_ic_config; 01390 TIM_OC_InitTypeDef s_oc_config; 01391 TIM_ClockConfigTypeDef s_clk_source_config; 01392 TIM_SlaveConfigTypeDef s_slave_config; 01393 01394 /* Configure the TIM peripheral --------------------------------------------*/ 01395 /* Set TIMx instance */ 01396 haudio_tim.Instance = AUDIO_TIMx; 01397 /* Timer Input Capture Configuration Structure declaration */ 01398 /* Initialize TIMx peripheral as follow: 01399 + Period = 0xFFFF 01400 + Prescaler = 0 01401 + ClockDivision = 0 01402 + Counter direction = Up 01403 */ 01404 haudio_tim.Init.Period = 1; 01405 haudio_tim.Init.Prescaler = 0; 01406 haudio_tim.Init.ClockDivision = 0; 01407 haudio_tim.Init.CounterMode = TIM_COUNTERMODE_UP; 01408 01409 /* Initialize the TIMx peripheral with the structure above */ 01410 TIMx_IC_MspInit(&haudio_tim); 01411 HAL_TIM_IC_Init(&haudio_tim); 01412 01413 /* Configure the Input Capture channel -------------------------------------*/ 01414 /* Configure the Input Capture of channel 2 */ 01415 s_ic_config.ICPolarity = TIM_ICPOLARITY_FALLING; 01416 s_ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI; 01417 s_ic_config.ICPrescaler = TIM_ICPSC_DIV1; 01418 s_ic_config.ICFilter = 0; 01419 HAL_TIM_IC_ConfigChannel(&haudio_tim, &s_ic_config, AUDIO_TIMx_IN_CHANNEL); 01420 01421 /* Select external clock mode 1 */ 01422 s_clk_source_config.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; 01423 s_clk_source_config.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED; 01424 s_clk_source_config.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; 01425 s_clk_source_config.ClockFilter = 0; 01426 HAL_TIM_ConfigClockSource(&haudio_tim, &s_clk_source_config); 01427 01428 /* Select Input Channel as input trigger */ 01429 s_slave_config.InputTrigger = TIM_TS_TI1FP1; 01430 s_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; 01431 s_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED; 01432 s_slave_config.TriggerPrescaler = TIM_CLOCKPRESCALER_DIV1; 01433 s_slave_config.TriggerFilter = 0; 01434 HAL_TIM_SlaveConfigSynchronization(&haudio_tim, &s_slave_config); 01435 01436 /* Output Compare PWM Mode configuration: Channel2 */ 01437 s_oc_config.OCMode = TIM_OCMODE_PWM1; 01438 s_oc_config.OCIdleState = TIM_OCIDLESTATE_SET; 01439 s_oc_config.Pulse = 1; 01440 s_oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; 01441 s_oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; 01442 s_oc_config.OCFastMode = TIM_OCFAST_DISABLE; 01443 s_oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; 01444 01445 /* Initialize the TIM3 Channel2 with the structure above */ 01446 HAL_TIM_PWM_ConfigChannel(&haudio_tim, &s_oc_config, AUDIO_TIMx_OUT_CHANNEL); 01447 01448 /* Start the TIM3 Channel2 */ 01449 HAL_TIM_PWM_Start(&haudio_tim, AUDIO_TIMx_OUT_CHANNEL); 01450 01451 /* Start the TIM3 Channel1 */ 01452 HAL_TIM_IC_Start(&haudio_tim, AUDIO_TIMx_IN_CHANNEL); 01453 } 01454 01455 /** 01456 * @brief Configure TIM as a clock divider by 2. 01457 * I2S_SCK is externally connected to TIMx input channel 01458 */ 01459 static void TIMx_DeInit(void) 01460 { 01461 haudio_tim.Instance = AUDIO_TIMx; 01462 01463 /* Stop the TIM3 Channel2 */ 01464 HAL_TIM_PWM_Stop(&haudio_tim, AUDIO_TIMx_OUT_CHANNEL); 01465 /* Stop the TIM3 Channel1 */ 01466 HAL_TIM_IC_Stop(&haudio_tim, AUDIO_TIMx_IN_CHANNEL); 01467 01468 HAL_TIM_IC_DeInit(&haudio_tim); 01469 01470 /* Initialize the TIMx peripheral with the structure above */ 01471 TIMx_IC_MspDeInit(&haudio_tim); 01472 } 01473 01474 /** 01475 * @} 01476 */ 01477 01478 /** 01479 * @} 01480 */ 01481 01482 /** 01483 * @} 01484 */ 01485 01486 /** 01487 * @} 01488 */ 01489 01490 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
Generated on Fri Jan 13 2017 11:00:15 for STM32469I-Discovery BSP User Manual by
