1*f763b8ceSMatthias Ringwald /** 2*f763b8ceSMatthias Ringwald ****************************************************************************** 3*f763b8ceSMatthias Ringwald * @file stm32f4_discovery_audio.c 4*f763b8ceSMatthias Ringwald * @author MCD Application Team 5*f763b8ceSMatthias Ringwald * @version V2.1.2 6*f763b8ceSMatthias Ringwald * @date 27-January-2017 7*f763b8ceSMatthias Ringwald * @brief This file provides the Audio driver for the STM32F4-Discovery 8*f763b8ceSMatthias Ringwald * board. 9*f763b8ceSMatthias Ringwald ****************************************************************************** 10*f763b8ceSMatthias Ringwald * @attention 11*f763b8ceSMatthias Ringwald * 12*f763b8ceSMatthias Ringwald * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> 13*f763b8ceSMatthias Ringwald * 14*f763b8ceSMatthias Ringwald * Redistribution and use in source and binary forms, with or without modification, 15*f763b8ceSMatthias Ringwald * are permitted provided that the following conditions are met: 16*f763b8ceSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright notice, 17*f763b8ceSMatthias Ringwald * this list of conditions and the following disclaimer. 18*f763b8ceSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright notice, 19*f763b8ceSMatthias Ringwald * this list of conditions and the following disclaimer in the documentation 20*f763b8ceSMatthias Ringwald * and/or other materials provided with the distribution. 21*f763b8ceSMatthias Ringwald * 3. Neither the name of STMicroelectronics nor the names of its contributors 22*f763b8ceSMatthias Ringwald * may be used to endorse or promote products derived from this software 23*f763b8ceSMatthias Ringwald * without specific prior written permission. 24*f763b8ceSMatthias Ringwald * 25*f763b8ceSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26*f763b8ceSMatthias Ringwald * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27*f763b8ceSMatthias Ringwald * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28*f763b8ceSMatthias Ringwald * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 29*f763b8ceSMatthias Ringwald * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30*f763b8ceSMatthias Ringwald * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31*f763b8ceSMatthias Ringwald * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32*f763b8ceSMatthias Ringwald * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33*f763b8ceSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34*f763b8ceSMatthias Ringwald * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35*f763b8ceSMatthias Ringwald * 36*f763b8ceSMatthias Ringwald ****************************************************************************** 37*f763b8ceSMatthias Ringwald */ 38*f763b8ceSMatthias Ringwald 39*f763b8ceSMatthias Ringwald /*============================================================================== 40*f763b8ceSMatthias Ringwald User NOTES 41*f763b8ceSMatthias Ringwald 1. How To use this driver: 42*f763b8ceSMatthias Ringwald -------------------------- 43*f763b8ceSMatthias Ringwald - This driver supports STM32F4xx devices on STM32F4-Discovery Kit: 44*f763b8ceSMatthias Ringwald a) to play an audio file (all functions names start by BSP_AUDIO_OUT_xxx) 45*f763b8ceSMatthias Ringwald b) to record an audio file through MP45DT02, ST MEMS (all functions names start by AUDIO_IN_xxx) 46*f763b8ceSMatthias Ringwald 47*f763b8ceSMatthias Ringwald a) PLAY A FILE: 48*f763b8ceSMatthias Ringwald ============== 49*f763b8ceSMatthias Ringwald + Call the function BSP_AUDIO_OUT_Init( 50*f763b8ceSMatthias Ringwald OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, 51*f763b8ceSMatthias Ringwald OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_AUTO or 52*f763b8ceSMatthias Ringwald OUTPUT_DEVICE_BOTH) 53*f763b8ceSMatthias Ringwald Volume: initial volume to be set (0 is min (mute), 100 is max (100%) 54*f763b8ceSMatthias Ringwald AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...) 55*f763b8ceSMatthias Ringwald this parameter is relative to the audio file/stream type. 56*f763b8ceSMatthias Ringwald ) 57*f763b8ceSMatthias Ringwald This function configures all the hardware required for the audio application (codec, I2C, I2S, 58*f763b8ceSMatthias Ringwald GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK. 59*f763b8ceSMatthias Ringwald If the returned value is different from 0 or the function is stuck then the communication with 60*f763b8ceSMatthias Ringwald the codec (try to un-plug the power or reset device in this case). 61*f763b8ceSMatthias Ringwald - OUTPUT_DEVICE_SPEAKER: only speaker will be set as output for the audio stream. 62*f763b8ceSMatthias Ringwald - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. 63*f763b8ceSMatthias Ringwald - OUTPUT_DEVICE_AUTO: Selection of output device is made through external switch (implemented 64*f763b8ceSMatthias Ringwald into the audio jack on the discovery board). When the Headphone is connected it is used 65*f763b8ceSMatthias Ringwald as output. When the headphone is disconnected from the audio jack, the output is 66*f763b8ceSMatthias Ringwald automatically switched to Speaker. 67*f763b8ceSMatthias Ringwald - OUTPUT_DEVICE_BOTH: both Speaker and Headphone are used as outputs for the audio stream 68*f763b8ceSMatthias Ringwald at the same time. 69*f763b8ceSMatthias Ringwald + Call the function BSP_AUDIO_OUT_Play( 70*f763b8ceSMatthias Ringwald pBuffer: pointer to the audio data file address 71*f763b8ceSMatthias Ringwald Size: size of the buffer to be sent in Bytes 72*f763b8ceSMatthias Ringwald ) 73*f763b8ceSMatthias Ringwald to start playing (for the first time) from the audio file/stream. 74*f763b8ceSMatthias Ringwald + Call the function BSP_AUDIO_OUT_Pause() to pause playing 75*f763b8ceSMatthias Ringwald + Call the function BSP_AUDIO_OUT_Resume() to resume playing. 76*f763b8ceSMatthias Ringwald Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called 77*f763b8ceSMatthias Ringwald for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). 78*f763b8ceSMatthias Ringwald Note. This function should be called only when the audio file is played or paused (not stopped). 79*f763b8ceSMatthias Ringwald + For each mode, you may need to implement the relative callback functions into your code. 80*f763b8ceSMatthias Ringwald The Callback functions are named BSP_AUDIO_OUT_XXXCallBack() and only their prototypes are declared in 81*f763b8ceSMatthias Ringwald the stm32f4_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) 82*f763b8ceSMatthias Ringwald + To Stop playing, to modify the volume level, the frequency or to mute, use the functions 83*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_Stop(), BSP_AUDIO_OUT_SetVolume(), AUDIO_OUT_SetFrequency() BSP_AUDIO_OUT_SetOutputMode and BSP_AUDIO_OUT_SetMute(). 84*f763b8ceSMatthias Ringwald + The driver API and the callback functions are at the end of the stm32f4_discovery_audio.h file. 85*f763b8ceSMatthias Ringwald 86*f763b8ceSMatthias Ringwald Driver architecture: 87*f763b8ceSMatthias Ringwald -------------------- 88*f763b8ceSMatthias Ringwald + This driver provide the High Audio Layer: consists of the function API exported in the stm32f4_discovery_audio.h file 89*f763b8ceSMatthias Ringwald (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) 90*f763b8ceSMatthias Ringwald + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ 91*f763b8ceSMatthias Ringwald providing the audio file/stream. These functions are also included as local functions into 92*f763b8ceSMatthias Ringwald the stm32f4_discovery_audio.c file (I2S3_Init()...) 93*f763b8ceSMatthias Ringwald 94*f763b8ceSMatthias Ringwald Known Limitations: 95*f763b8ceSMatthias Ringwald ------------------- 96*f763b8ceSMatthias Ringwald 1- When using the Speaker, if the audio file quality is not high enough, the speaker output 97*f763b8ceSMatthias Ringwald may produce high and uncomfortable noise level. To avoid this issue, to use speaker 98*f763b8ceSMatthias Ringwald output properly, try to increase audio file sampling rate (typically higher than 48KHz). 99*f763b8ceSMatthias Ringwald This operation will lead to larger file size. 100*f763b8ceSMatthias Ringwald 2- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some 101*f763b8ceSMatthias Ringwald user interrupt routines (in this case, interrupts could be disabled just before the start of 102*f763b8ceSMatthias Ringwald communication then re-enabled when it is over). Note that this communication is only done at 103*f763b8ceSMatthias Ringwald the configuration phase (BSP_AUDIO_OUT_Init() or BSP_AUDIO_OUT_Stop()) and when Volume control modification is 104*f763b8ceSMatthias Ringwald performed (BSP_AUDIO_OUT_SetVolume() or BSP_AUDIO_OUT_SetMute()or BSP_AUDIO_OUT_SetOutputMode()). 105*f763b8ceSMatthias Ringwald When the audio data is played, no communication is required with the audio codec. 106*f763b8ceSMatthias Ringwald 3- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, 107*f763b8ceSMatthias Ringwald File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. 108*f763b8ceSMatthias Ringwald 4- Supports only Stereo audio streaming. To play mono audio streams, each data should be sent twice 109*f763b8ceSMatthias Ringwald on the I2S or should be duplicated on the source buffer. Or convert the stream in stereo before playing. 110*f763b8ceSMatthias Ringwald 5- Supports only 16-bits audio data size. 111*f763b8ceSMatthias Ringwald 112*f763b8ceSMatthias Ringwald b) RECORD A FILE: 113*f763b8ceSMatthias Ringwald ================ 114*f763b8ceSMatthias Ringwald + Call the function BSP_AUDIO_IN_Init( 115*f763b8ceSMatthias Ringwald AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...) 116*f763b8ceSMatthias Ringwald ) 117*f763b8ceSMatthias Ringwald This function configures all the hardware required for the audio application (I2S, 118*f763b8ceSMatthias Ringwald GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK. 119*f763b8ceSMatthias Ringwald 120*f763b8ceSMatthias Ringwald + Call the function BSP_AUDIO_IN_Record( 121*f763b8ceSMatthias Ringwald pbuf Main buffer pointer for the recorded data storing 122*f763b8ceSMatthias Ringwald size Current size of the recorded buffer 123*f763b8ceSMatthias Ringwald ) 124*f763b8ceSMatthias Ringwald to start recording from the microphone. 125*f763b8ceSMatthias Ringwald 126*f763b8ceSMatthias Ringwald + User needs to implement user callbacks to retrieve data saved in the record buffer 127*f763b8ceSMatthias Ringwald (AUDIO_IN_RxHalfCpltCallback/BSP_AUDIO_IN_ReceiveComplete_CallBack) 128*f763b8ceSMatthias Ringwald 129*f763b8ceSMatthias Ringwald + Call the function AUDIO_IN_STOP() to stop recording 130*f763b8ceSMatthias Ringwald 131*f763b8ceSMatthias Ringwald ==============================================================================*/ 132*f763b8ceSMatthias Ringwald 133*f763b8ceSMatthias Ringwald /* Includes ------------------------------------------------------------------*/ 134*f763b8ceSMatthias Ringwald #include "stm32f4_discovery_audio.h" 135*f763b8ceSMatthias Ringwald #include "pdm_filter.h" 136*f763b8ceSMatthias Ringwald #include "btstack_config.h" 137*f763b8ceSMatthias Ringwald 138*f763b8ceSMatthias Ringwald /** @addtogroup BSP 139*f763b8ceSMatthias Ringwald * @{ 140*f763b8ceSMatthias Ringwald */ 141*f763b8ceSMatthias Ringwald 142*f763b8ceSMatthias Ringwald /** @addtogroup STM32F4_DISCOVERY 143*f763b8ceSMatthias Ringwald * @{ 144*f763b8ceSMatthias Ringwald */ 145*f763b8ceSMatthias Ringwald 146*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO STM32F4 DISCOVERY AUDIO 147*f763b8ceSMatthias Ringwald * @brief This file includes the low layer audio driver available on STM32F4-Discovery 148*f763b8ceSMatthias Ringwald * discovery board. 149*f763b8ceSMatthias Ringwald * @{ 150*f763b8ceSMatthias Ringwald */ 151*f763b8ceSMatthias Ringwald 152*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Types STM32F4 DISCOVERY AUDIO Private Types 153*f763b8ceSMatthias Ringwald * @{ 154*f763b8ceSMatthias Ringwald */ 155*f763b8ceSMatthias Ringwald /** 156*f763b8ceSMatthias Ringwald * @} 157*f763b8ceSMatthias Ringwald */ 158*f763b8ceSMatthias Ringwald 159*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Defines STM32F4 DISCOVERY AUDIO Private Defines 160*f763b8ceSMatthias Ringwald * @{ 161*f763b8ceSMatthias Ringwald */ 162*f763b8ceSMatthias Ringwald /* These PLL parameters are valid when the f(VCO clock) = 1Mhz */ 163*f763b8ceSMatthias Ringwald static const uint32_t I2SFreq[8] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000}; 164*f763b8ceSMatthias Ringwald static const uint32_t I2SPLLN[8] = {256, 429, 213, 429, 426, 271, 258, 344}; 165*f763b8ceSMatthias Ringwald static const uint32_t I2SPLLR[8] = {5, 4, 4, 4, 4, 6, 3, 1}; 166*f763b8ceSMatthias Ringwald /** 167*f763b8ceSMatthias Ringwald * @} 168*f763b8ceSMatthias Ringwald */ 169*f763b8ceSMatthias Ringwald 170*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Macros STM32F4 DISCOVERY AUDIO Private Macros 171*f763b8ceSMatthias Ringwald * @{ 172*f763b8ceSMatthias Ringwald */ 173*f763b8ceSMatthias Ringwald /** 174*f763b8ceSMatthias Ringwald * @} 175*f763b8ceSMatthias Ringwald */ 176*f763b8ceSMatthias Ringwald 177*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Variables STM32F4 DISCOVERY AUDIO Private Variables 178*f763b8ceSMatthias Ringwald * @{ 179*f763b8ceSMatthias Ringwald */ 180*f763b8ceSMatthias Ringwald /*##### PLAY #####*/ 181*f763b8ceSMatthias Ringwald static AUDIO_DrvTypeDef *pAudioDrv; 182*f763b8ceSMatthias Ringwald I2S_HandleTypeDef hAudioOutI2s; 183*f763b8ceSMatthias Ringwald 184*f763b8ceSMatthias Ringwald /*### RECORDER ###*/ 185*f763b8ceSMatthias Ringwald I2S_HandleTypeDef hAudioInI2s; 186*f763b8ceSMatthias Ringwald 187*f763b8ceSMatthias Ringwald static PDMFilter_InitStruct Filter[DEFAULT_AUDIO_IN_CHANNEL_NBR]; 188*f763b8ceSMatthias Ringwald __IO uint16_t AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; 189*f763b8ceSMatthias Ringwald /** 190*f763b8ceSMatthias Ringwald * @} 191*f763b8ceSMatthias Ringwald */ 192*f763b8ceSMatthias Ringwald 193*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F4 DISCOVERY AUDIO Private Function Prototypes 194*f763b8ceSMatthias Ringwald * @{ 195*f763b8ceSMatthias Ringwald */ 196*f763b8ceSMatthias Ringwald static uint8_t I2S2_Init(uint32_t AudioFreq); 197*f763b8ceSMatthias Ringwald static uint8_t I2S3_Init(uint32_t AudioFreq); 198*f763b8ceSMatthias Ringwald static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr); 199*f763b8ceSMatthias Ringwald 200*f763b8ceSMatthias Ringwald /** 201*f763b8ceSMatthias Ringwald * @} 202*f763b8ceSMatthias Ringwald */ 203*f763b8ceSMatthias Ringwald 204*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_OUT_Private_Functions STM32F4 DISCOVERY AUDIO OUT Private Functions 205*f763b8ceSMatthias Ringwald * @{ 206*f763b8ceSMatthias Ringwald */ 207*f763b8ceSMatthias Ringwald 208*f763b8ceSMatthias Ringwald /** 209*f763b8ceSMatthias Ringwald * @brief Configures the audio peripherals. 210*f763b8ceSMatthias Ringwald * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, 211*f763b8ceSMatthias Ringwald * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO . 212*f763b8ceSMatthias Ringwald * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) 213*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency used to play the audio stream. 214*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 215*f763b8ceSMatthias Ringwald */ 216*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) 217*f763b8ceSMatthias Ringwald { 218*f763b8ceSMatthias Ringwald uint8_t ret = AUDIO_OK; 219*f763b8ceSMatthias Ringwald 220*f763b8ceSMatthias Ringwald /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 221*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL); 222*f763b8ceSMatthias Ringwald 223*f763b8ceSMatthias Ringwald /* I2S data transfer preparation: 224*f763b8ceSMatthias Ringwald Prepare the Media to be used for the audio transfer from memory to I2S peripheral */ 225*f763b8ceSMatthias Ringwald hAudioOutI2s.Instance = I2S3; 226*f763b8ceSMatthias Ringwald if(HAL_I2S_GetState(&hAudioOutI2s) == HAL_I2S_STATE_RESET) 227*f763b8ceSMatthias Ringwald { 228*f763b8ceSMatthias Ringwald /* Init the I2S MSP: this __weak function can be redefined by the application*/ 229*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_MspInit(&hAudioOutI2s, NULL); 230*f763b8ceSMatthias Ringwald } 231*f763b8ceSMatthias Ringwald 232*f763b8ceSMatthias Ringwald /* I2S data transfer preparation: 233*f763b8ceSMatthias Ringwald Prepare the Media to be used for the audio transfer from memory to I2S peripheral */ 234*f763b8ceSMatthias Ringwald /* Configure the I2S peripheral */ 235*f763b8ceSMatthias Ringwald if(I2S3_Init(AudioFreq) != AUDIO_OK) 236*f763b8ceSMatthias Ringwald { 237*f763b8ceSMatthias Ringwald ret = AUDIO_ERROR; 238*f763b8ceSMatthias Ringwald } 239*f763b8ceSMatthias Ringwald 240*f763b8ceSMatthias Ringwald if(ret == AUDIO_OK) 241*f763b8ceSMatthias Ringwald { 242*f763b8ceSMatthias Ringwald /* Retieve audio codec identifier */ 243*f763b8ceSMatthias Ringwald if(((cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS)) & CS43L22_ID_MASK) == CS43L22_ID) 244*f763b8ceSMatthias Ringwald { 245*f763b8ceSMatthias Ringwald /* Initialize the audio driver structure */ 246*f763b8ceSMatthias Ringwald pAudioDrv = &cs43l22_drv; 247*f763b8ceSMatthias Ringwald } 248*f763b8ceSMatthias Ringwald else 249*f763b8ceSMatthias Ringwald { 250*f763b8ceSMatthias Ringwald ret = AUDIO_ERROR; 251*f763b8ceSMatthias Ringwald } 252*f763b8ceSMatthias Ringwald } 253*f763b8ceSMatthias Ringwald 254*f763b8ceSMatthias Ringwald if(ret == AUDIO_OK) 255*f763b8ceSMatthias Ringwald { 256*f763b8ceSMatthias Ringwald pAudioDrv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); 257*f763b8ceSMatthias Ringwald } 258*f763b8ceSMatthias Ringwald 259*f763b8ceSMatthias Ringwald return ret; 260*f763b8ceSMatthias Ringwald } 261*f763b8ceSMatthias Ringwald 262*f763b8ceSMatthias Ringwald /** 263*f763b8ceSMatthias Ringwald * @brief Starts playing audio stream from a data buffer for a determined size. 264*f763b8ceSMatthias Ringwald * @param pBuffer: Pointer to the buffer 265*f763b8ceSMatthias Ringwald * @param Size: Number of audio data BYTES. 266*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 267*f763b8ceSMatthias Ringwald */ 268*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) 269*f763b8ceSMatthias Ringwald { 270*f763b8ceSMatthias Ringwald /* Call the audio Codec Play function */ 271*f763b8ceSMatthias Ringwald if(pAudioDrv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) 272*f763b8ceSMatthias Ringwald { 273*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 274*f763b8ceSMatthias Ringwald } 275*f763b8ceSMatthias Ringwald else 276*f763b8ceSMatthias Ringwald { 277*f763b8ceSMatthias Ringwald /* Update the Media layer and enable it for play */ 278*f763b8ceSMatthias Ringwald HAL_I2S_Transmit_DMA(&hAudioOutI2s, pBuffer, DMA_MAX(Size/AUDIODATA_SIZE)); 279*f763b8ceSMatthias Ringwald 280*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 281*f763b8ceSMatthias Ringwald return AUDIO_OK; 282*f763b8ceSMatthias Ringwald } 283*f763b8ceSMatthias Ringwald } 284*f763b8ceSMatthias Ringwald 285*f763b8ceSMatthias Ringwald /** 286*f763b8ceSMatthias Ringwald * @brief Sends n-Bytes on the I2S interface. 287*f763b8ceSMatthias Ringwald * @param pData: Pointer to data address 288*f763b8ceSMatthias Ringwald * @param Size: Number of data to be written 289*f763b8ceSMatthias Ringwald */ 290*f763b8ceSMatthias Ringwald void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) 291*f763b8ceSMatthias Ringwald { 292*f763b8ceSMatthias Ringwald HAL_I2S_Transmit_DMA(&hAudioOutI2s, pData, Size); 293*f763b8ceSMatthias Ringwald } 294*f763b8ceSMatthias Ringwald 295*f763b8ceSMatthias Ringwald /** 296*f763b8ceSMatthias Ringwald * @brief Pauses the audio file stream. In case of using DMA, the DMA Pause 297*f763b8ceSMatthias Ringwald * feature is used. 298*f763b8ceSMatthias Ringwald * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only the 299*f763b8ceSMatthias Ringwald * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 300*f763b8ceSMatthias Ringwald * function for resume could lead to unexpected behavior). 301*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 302*f763b8ceSMatthias Ringwald */ 303*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_Pause(void) 304*f763b8ceSMatthias Ringwald { 305*f763b8ceSMatthias Ringwald /* Call the Audio Codec Pause/Resume function */ 306*f763b8ceSMatthias Ringwald if(pAudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0) 307*f763b8ceSMatthias Ringwald { 308*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 309*f763b8ceSMatthias Ringwald } 310*f763b8ceSMatthias Ringwald else 311*f763b8ceSMatthias Ringwald { 312*f763b8ceSMatthias Ringwald /* Call the Media layer pause function */ 313*f763b8ceSMatthias Ringwald HAL_I2S_DMAPause(&hAudioOutI2s); 314*f763b8ceSMatthias Ringwald 315*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 316*f763b8ceSMatthias Ringwald return AUDIO_OK; 317*f763b8ceSMatthias Ringwald } 318*f763b8ceSMatthias Ringwald } 319*f763b8ceSMatthias Ringwald 320*f763b8ceSMatthias Ringwald /** 321*f763b8ceSMatthias Ringwald * @brief Resumes the audio file streaming. 322*f763b8ceSMatthias Ringwald * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only 323*f763b8ceSMatthias Ringwald * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 324*f763b8ceSMatthias Ringwald * function for resume could lead to unexpected behavior). 325*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 326*f763b8ceSMatthias Ringwald */ 327*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_Resume(void) 328*f763b8ceSMatthias Ringwald { 329*f763b8ceSMatthias Ringwald /* Call the Audio Codec Pause/Resume function */ 330*f763b8ceSMatthias Ringwald if(pAudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0) 331*f763b8ceSMatthias Ringwald { 332*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 333*f763b8ceSMatthias Ringwald } 334*f763b8ceSMatthias Ringwald else 335*f763b8ceSMatthias Ringwald { 336*f763b8ceSMatthias Ringwald /* Call the Media layer resume function */ 337*f763b8ceSMatthias Ringwald HAL_I2S_DMAResume(&hAudioOutI2s); 338*f763b8ceSMatthias Ringwald 339*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 340*f763b8ceSMatthias Ringwald return AUDIO_OK; 341*f763b8ceSMatthias Ringwald } 342*f763b8ceSMatthias Ringwald } 343*f763b8ceSMatthias Ringwald 344*f763b8ceSMatthias Ringwald /** 345*f763b8ceSMatthias Ringwald * @brief Stops audio playing and Power down the Audio Codec. 346*f763b8ceSMatthias Ringwald * @param Option: could be one of the following parameters 347*f763b8ceSMatthias Ringwald * - CODEC_PDWN_HW: completely shut down the codec (physically). 348*f763b8ceSMatthias Ringwald * Then need to reconfigure the Codec after power on. 349*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 350*f763b8ceSMatthias Ringwald */ 351*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) 352*f763b8ceSMatthias Ringwald { 353*f763b8ceSMatthias Ringwald /* Call DMA Stop to disable DMA stream before stopping codec */ 354*f763b8ceSMatthias Ringwald HAL_I2S_DMAStop(&hAudioOutI2s); 355*f763b8ceSMatthias Ringwald 356*f763b8ceSMatthias Ringwald /* Call Audio Codec Stop function */ 357*f763b8ceSMatthias Ringwald if(pAudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) 358*f763b8ceSMatthias Ringwald { 359*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 360*f763b8ceSMatthias Ringwald } 361*f763b8ceSMatthias Ringwald else 362*f763b8ceSMatthias Ringwald { 363*f763b8ceSMatthias Ringwald if(Option == CODEC_PDWN_HW) 364*f763b8ceSMatthias Ringwald { 365*f763b8ceSMatthias Ringwald /* Wait at least 1ms */ 366*f763b8ceSMatthias Ringwald HAL_Delay(1); 367*f763b8ceSMatthias Ringwald 368*f763b8ceSMatthias Ringwald /* Reset the pin */ 369*f763b8ceSMatthias Ringwald HAL_GPIO_WritePin(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, GPIO_PIN_RESET); 370*f763b8ceSMatthias Ringwald } 371*f763b8ceSMatthias Ringwald 372*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 373*f763b8ceSMatthias Ringwald return AUDIO_OK; 374*f763b8ceSMatthias Ringwald } 375*f763b8ceSMatthias Ringwald } 376*f763b8ceSMatthias Ringwald 377*f763b8ceSMatthias Ringwald /** 378*f763b8ceSMatthias Ringwald * @brief Controls the current audio volume level. 379*f763b8ceSMatthias Ringwald * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for 380*f763b8ceSMatthias Ringwald * Mute and 100 for Max volume level). 381*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 382*f763b8ceSMatthias Ringwald */ 383*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) 384*f763b8ceSMatthias Ringwald { 385*f763b8ceSMatthias Ringwald /* Call the codec volume control function with converted volume value */ 386*f763b8ceSMatthias Ringwald if(pAudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) 387*f763b8ceSMatthias Ringwald { 388*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 389*f763b8ceSMatthias Ringwald } 390*f763b8ceSMatthias Ringwald else 391*f763b8ceSMatthias Ringwald { 392*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 393*f763b8ceSMatthias Ringwald return AUDIO_OK; 394*f763b8ceSMatthias Ringwald } 395*f763b8ceSMatthias Ringwald } 396*f763b8ceSMatthias Ringwald 397*f763b8ceSMatthias Ringwald /** 398*f763b8ceSMatthias Ringwald * @brief Enables or disables the MUTE mode by software 399*f763b8ceSMatthias Ringwald * @param Cmd: could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to 400*f763b8ceSMatthias Ringwald * unmute the codec and restore previous volume level. 401*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 402*f763b8ceSMatthias Ringwald */ 403*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) 404*f763b8ceSMatthias Ringwald { 405*f763b8ceSMatthias Ringwald /* Call the Codec Mute function */ 406*f763b8ceSMatthias Ringwald if(pAudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) 407*f763b8ceSMatthias Ringwald { 408*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 409*f763b8ceSMatthias Ringwald } 410*f763b8ceSMatthias Ringwald else 411*f763b8ceSMatthias Ringwald { 412*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 413*f763b8ceSMatthias Ringwald return AUDIO_OK; 414*f763b8ceSMatthias Ringwald } 415*f763b8ceSMatthias Ringwald } 416*f763b8ceSMatthias Ringwald 417*f763b8ceSMatthias Ringwald /** 418*f763b8ceSMatthias Ringwald * @brief Switch dynamically (while audio file is played) the output target 419*f763b8ceSMatthias Ringwald * (speaker or headphone). 420*f763b8ceSMatthias Ringwald * @note This function modifies a global variable of the audio codec driver: OutputDev. 421*f763b8ceSMatthias Ringwald * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER, 422*f763b8ceSMatthias Ringwald * OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO 423*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 424*f763b8ceSMatthias Ringwald */ 425*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) 426*f763b8ceSMatthias Ringwald { 427*f763b8ceSMatthias Ringwald /* Call the Codec output Device function */ 428*f763b8ceSMatthias Ringwald if(pAudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) 429*f763b8ceSMatthias Ringwald { 430*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 431*f763b8ceSMatthias Ringwald } 432*f763b8ceSMatthias Ringwald else 433*f763b8ceSMatthias Ringwald { 434*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 435*f763b8ceSMatthias Ringwald return AUDIO_OK; 436*f763b8ceSMatthias Ringwald } 437*f763b8ceSMatthias Ringwald } 438*f763b8ceSMatthias Ringwald 439*f763b8ceSMatthias Ringwald /** 440*f763b8ceSMatthias Ringwald * @brief Update the audio frequency. 441*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency used to play the audio stream. 442*f763b8ceSMatthias Ringwald * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the 443*f763b8ceSMatthias Ringwald * audio frequency. 444*f763b8ceSMatthias Ringwald */ 445*f763b8ceSMatthias Ringwald void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) 446*f763b8ceSMatthias Ringwald { 447*f763b8ceSMatthias Ringwald /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 448*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL); 449*f763b8ceSMatthias Ringwald 450*f763b8ceSMatthias Ringwald /* Update the I2S audio frequency configuration */ 451*f763b8ceSMatthias Ringwald I2S3_Init(AudioFreq); 452*f763b8ceSMatthias Ringwald } 453*f763b8ceSMatthias Ringwald 454*f763b8ceSMatthias Ringwald /** 455*f763b8ceSMatthias Ringwald * @brief Tx Transfer completed callbacks. 456*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 457*f763b8ceSMatthias Ringwald */ 458*f763b8ceSMatthias Ringwald void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) 459*f763b8ceSMatthias Ringwald { 460*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S3) 461*f763b8ceSMatthias Ringwald { 462*f763b8ceSMatthias Ringwald /* Call the user function which will manage directly transfer complete */ 463*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_TransferComplete_CallBack(); 464*f763b8ceSMatthias Ringwald } 465*f763b8ceSMatthias Ringwald } 466*f763b8ceSMatthias Ringwald 467*f763b8ceSMatthias Ringwald /** 468*f763b8ceSMatthias Ringwald * @brief Tx Half Transfer completed callbacks. 469*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 470*f763b8ceSMatthias Ringwald */ 471*f763b8ceSMatthias Ringwald void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) 472*f763b8ceSMatthias Ringwald { 473*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S3) 474*f763b8ceSMatthias Ringwald { 475*f763b8ceSMatthias Ringwald /* Manage the remaining file size and new address offset: This function should 476*f763b8ceSMatthias Ringwald be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */ 477*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_HalfTransfer_CallBack(); 478*f763b8ceSMatthias Ringwald } 479*f763b8ceSMatthias Ringwald } 480*f763b8ceSMatthias Ringwald 481*f763b8ceSMatthias Ringwald /** 482*f763b8ceSMatthias Ringwald * @brief Clock Config. 483*f763b8ceSMatthias Ringwald * @param hi2s: might be required to set audio peripheral predivider if any. 484*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency used to play the audio stream. 485*f763b8ceSMatthias Ringwald * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() 486*f763b8ceSMatthias Ringwald * Being __weak it can be overwritten by the application 487*f763b8ceSMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 488*f763b8ceSMatthias Ringwald */ 489*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_OUT_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params) 490*f763b8ceSMatthias Ringwald { 491*f763b8ceSMatthias Ringwald RCC_PeriphCLKInitTypeDef rccclkinit; 492*f763b8ceSMatthias Ringwald uint8_t index = 0, freqindex = 0xFF; 493*f763b8ceSMatthias Ringwald 494*f763b8ceSMatthias Ringwald for(index = 0; index < 8; index++) 495*f763b8ceSMatthias Ringwald { 496*f763b8ceSMatthias Ringwald if(I2SFreq[index] == AudioFreq) 497*f763b8ceSMatthias Ringwald { 498*f763b8ceSMatthias Ringwald freqindex = index; 499*f763b8ceSMatthias Ringwald } 500*f763b8ceSMatthias Ringwald } 501*f763b8ceSMatthias Ringwald /* Enable PLLI2S clock */ 502*f763b8ceSMatthias Ringwald HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit); 503*f763b8ceSMatthias Ringwald /* PLLI2S_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ 504*f763b8ceSMatthias Ringwald 505*f763b8ceSMatthias Ringwald // BK use table if frequency found in table, otherwise use same settings as for 48 kHz 506*f763b8ceSMatthias Ringwald if (freqindex != 0xFF) 507*f763b8ceSMatthias Ringwald { 508*f763b8ceSMatthias Ringwald /* I2S clock config 509*f763b8ceSMatthias Ringwald PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) � (PLLI2SN/PLLM) 510*f763b8ceSMatthias Ringwald I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */ 511*f763b8ceSMatthias Ringwald rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S; 512*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SN = I2SPLLN[freqindex]; 513*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SR = I2SPLLR[freqindex]; 514*f763b8ceSMatthias Ringwald HAL_RCCEx_PeriphCLKConfig(&rccclkinit); 515*f763b8ceSMatthias Ringwald } 516*f763b8ceSMatthias Ringwald else 517*f763b8ceSMatthias Ringwald { 518*f763b8ceSMatthias Ringwald /* I2S clock config 519*f763b8ceSMatthias Ringwald PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) � (PLLI2SN/PLLM) 520*f763b8ceSMatthias Ringwald I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */ 521*f763b8ceSMatthias Ringwald rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S; 522*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SN = 258; 523*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SR = 3; 524*f763b8ceSMatthias Ringwald HAL_RCCEx_PeriphCLKConfig(&rccclkinit); 525*f763b8ceSMatthias Ringwald } 526*f763b8ceSMatthias Ringwald } 527*f763b8ceSMatthias Ringwald 528*f763b8ceSMatthias Ringwald /** 529*f763b8ceSMatthias Ringwald * @brief AUDIO OUT I2S MSP Init. 530*f763b8ceSMatthias Ringwald * @param hi2s: might be required to set audio peripheral predivider if any. 531*f763b8ceSMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 532*f763b8ceSMatthias Ringwald */ 533*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_OUT_MspInit(I2S_HandleTypeDef *hi2s, void *Params) 534*f763b8ceSMatthias Ringwald { 535*f763b8ceSMatthias Ringwald static DMA_HandleTypeDef hdma_i2sTx; 536*f763b8ceSMatthias Ringwald GPIO_InitTypeDef GPIO_InitStruct; 537*f763b8ceSMatthias Ringwald 538*f763b8ceSMatthias Ringwald /* Enable I2S3 clock */ 539*f763b8ceSMatthias Ringwald I2S3_CLK_ENABLE(); 540*f763b8ceSMatthias Ringwald 541*f763b8ceSMatthias Ringwald /*** Configure the GPIOs ***/ 542*f763b8ceSMatthias Ringwald /* Enable I2S GPIO clocks */ 543*f763b8ceSMatthias Ringwald I2S3_SCK_SD_CLK_ENABLE(); 544*f763b8ceSMatthias Ringwald I2S3_WS_CLK_ENABLE(); 545*f763b8ceSMatthias Ringwald 546*f763b8ceSMatthias Ringwald /* I2S3 pins configuration: WS, SCK and SD pins ----------------------------*/ 547*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S3_SCK_PIN | I2S3_SD_PIN; 548*f763b8ceSMatthias Ringwald GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 549*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pull = GPIO_NOPULL; 550*f763b8ceSMatthias Ringwald GPIO_InitStruct.Speed = GPIO_SPEED_FAST; 551*f763b8ceSMatthias Ringwald GPIO_InitStruct.Alternate = I2S3_SCK_SD_WS_AF; 552*f763b8ceSMatthias Ringwald HAL_GPIO_Init(I2S3_SCK_SD_GPIO_PORT, &GPIO_InitStruct); 553*f763b8ceSMatthias Ringwald 554*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S3_WS_PIN ; 555*f763b8ceSMatthias Ringwald HAL_GPIO_Init(I2S3_WS_GPIO_PORT, &GPIO_InitStruct); 556*f763b8ceSMatthias Ringwald 557*f763b8ceSMatthias Ringwald /* I2S3 pins configuration: MCK pin */ 558*f763b8ceSMatthias Ringwald I2S3_MCK_CLK_ENABLE(); 559*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S3_MCK_PIN; 560*f763b8ceSMatthias Ringwald HAL_GPIO_Init(I2S3_MCK_GPIO_PORT, &GPIO_InitStruct); 561*f763b8ceSMatthias Ringwald 562*f763b8ceSMatthias Ringwald /* Enable the I2S DMA clock */ 563*f763b8ceSMatthias Ringwald I2S3_DMAx_CLK_ENABLE(); 564*f763b8ceSMatthias Ringwald 565*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S3) 566*f763b8ceSMatthias Ringwald { 567*f763b8ceSMatthias Ringwald /* Configure the hdma_i2sTx handle parameters */ 568*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.Channel = I2S3_DMAx_CHANNEL; 569*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.Direction = DMA_MEMORY_TO_PERIPH; 570*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.PeriphInc = DMA_PINC_DISABLE; 571*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.MemInc = DMA_MINC_ENABLE; 572*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.PeriphDataAlignment = I2S3_DMAx_PERIPH_DATA_SIZE; 573*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.MemDataAlignment = I2S3_DMAx_MEM_DATA_SIZE; 574*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.Mode = DMA_NORMAL; 575*f763b8ceSMatthias Ringwald 576*f763b8ceSMatthias Ringwald // BK: use circular DMA for hal_audio.h 577*f763b8ceSMatthias Ringwald #ifdef HAVE_HAL_AUDIO 578*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.Mode = DMA_CIRCULAR; 579*f763b8ceSMatthias Ringwald #endif 580*f763b8ceSMatthias Ringwald // BK: use circular DMA (end) 581*f763b8ceSMatthias Ringwald 582*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.Priority = DMA_PRIORITY_HIGH; 583*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; 584*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; 585*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.MemBurst = DMA_MBURST_SINGLE; 586*f763b8ceSMatthias Ringwald hdma_i2sTx.Init.PeriphBurst = DMA_PBURST_SINGLE; 587*f763b8ceSMatthias Ringwald 588*f763b8ceSMatthias Ringwald hdma_i2sTx.Instance = I2S3_DMAx_STREAM; 589*f763b8ceSMatthias Ringwald 590*f763b8ceSMatthias Ringwald /* Associate the DMA handle */ 591*f763b8ceSMatthias Ringwald __HAL_LINKDMA(hi2s, hdmatx, hdma_i2sTx); 592*f763b8ceSMatthias Ringwald 593*f763b8ceSMatthias Ringwald /* Deinitialize the Stream for new transfer */ 594*f763b8ceSMatthias Ringwald HAL_DMA_DeInit(&hdma_i2sTx); 595*f763b8ceSMatthias Ringwald 596*f763b8ceSMatthias Ringwald /* Configure the DMA Stream */ 597*f763b8ceSMatthias Ringwald HAL_DMA_Init(&hdma_i2sTx); 598*f763b8ceSMatthias Ringwald } 599*f763b8ceSMatthias Ringwald 600*f763b8ceSMatthias Ringwald /* I2S DMA IRQ Channel configuration */ 601*f763b8ceSMatthias Ringwald HAL_NVIC_SetPriority(I2S3_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); 602*f763b8ceSMatthias Ringwald HAL_NVIC_EnableIRQ(I2S3_DMAx_IRQ); 603*f763b8ceSMatthias Ringwald } 604*f763b8ceSMatthias Ringwald 605*f763b8ceSMatthias Ringwald /** 606*f763b8ceSMatthias Ringwald * @brief De-Initializes BSP_AUDIO_OUT MSP. 607*f763b8ceSMatthias Ringwald * @param hi2s: might be required to set audio peripheral predivider if any. 608*f763b8ceSMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 609*f763b8ceSMatthias Ringwald */ 610*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_OUT_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params) 611*f763b8ceSMatthias Ringwald { 612*f763b8ceSMatthias Ringwald GPIO_InitTypeDef GPIO_InitStruct; 613*f763b8ceSMatthias Ringwald 614*f763b8ceSMatthias Ringwald /* I2S DMA IRQ Channel deactivation */ 615*f763b8ceSMatthias Ringwald HAL_NVIC_DisableIRQ(I2S3_DMAx_IRQ); 616*f763b8ceSMatthias Ringwald 617*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S3) 618*f763b8ceSMatthias Ringwald { 619*f763b8ceSMatthias Ringwald /* Deinitialize the Stream for new transfer */ 620*f763b8ceSMatthias Ringwald HAL_DMA_DeInit(hi2s->hdmatx); 621*f763b8ceSMatthias Ringwald } 622*f763b8ceSMatthias Ringwald 623*f763b8ceSMatthias Ringwald /* Disable I2S block */ 624*f763b8ceSMatthias Ringwald __HAL_I2S_DISABLE(hi2s); 625*f763b8ceSMatthias Ringwald 626*f763b8ceSMatthias Ringwald /* CODEC_I2S pins configuration: SCK and SD pins */ 627*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S3_SCK_PIN | I2S3_SD_PIN; 628*f763b8ceSMatthias Ringwald HAL_GPIO_DeInit(I2S3_SCK_SD_GPIO_PORT, GPIO_InitStruct.Pin); 629*f763b8ceSMatthias Ringwald 630*f763b8ceSMatthias Ringwald /* CODEC_I2S pins configuration: WS pin */ 631*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S3_WS_PIN; 632*f763b8ceSMatthias Ringwald HAL_GPIO_DeInit(I2S3_WS_GPIO_PORT, GPIO_InitStruct.Pin); 633*f763b8ceSMatthias Ringwald 634*f763b8ceSMatthias Ringwald /* CODEC_I2S pins configuration: MCK pin */ 635*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S3_MCK_PIN; 636*f763b8ceSMatthias Ringwald HAL_GPIO_DeInit(I2S3_MCK_GPIO_PORT, GPIO_InitStruct.Pin); 637*f763b8ceSMatthias Ringwald 638*f763b8ceSMatthias Ringwald /* Disable I2S clock */ 639*f763b8ceSMatthias Ringwald I2S3_CLK_DISABLE(); 640*f763b8ceSMatthias Ringwald 641*f763b8ceSMatthias Ringwald /* GPIO pins clock and DMA clock can be shut down in the applic 642*f763b8ceSMatthias Ringwald by surcgarging this __weak function */ 643*f763b8ceSMatthias Ringwald } 644*f763b8ceSMatthias Ringwald 645*f763b8ceSMatthias Ringwald /** 646*f763b8ceSMatthias Ringwald * @brief Manages the DMA full Transfer complete event. 647*f763b8ceSMatthias Ringwald */ 648*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) 649*f763b8ceSMatthias Ringwald { 650*f763b8ceSMatthias Ringwald } 651*f763b8ceSMatthias Ringwald 652*f763b8ceSMatthias Ringwald /** 653*f763b8ceSMatthias Ringwald * @brief Manages the DMA Half Transfer complete event. 654*f763b8ceSMatthias Ringwald */ 655*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) 656*f763b8ceSMatthias Ringwald { 657*f763b8ceSMatthias Ringwald } 658*f763b8ceSMatthias Ringwald 659*f763b8ceSMatthias Ringwald /** 660*f763b8ceSMatthias Ringwald * @brief Manages the DMA FIFO error event. 661*f763b8ceSMatthias Ringwald */ 662*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_OUT_Error_CallBack(void) 663*f763b8ceSMatthias Ringwald { 664*f763b8ceSMatthias Ringwald } 665*f763b8ceSMatthias Ringwald 666*f763b8ceSMatthias Ringwald /******************************************************************************* 667*f763b8ceSMatthias Ringwald Static Functions 668*f763b8ceSMatthias Ringwald *******************************************************************************/ 669*f763b8ceSMatthias Ringwald 670*f763b8ceSMatthias Ringwald /** 671*f763b8ceSMatthias Ringwald * @brief Initializes the Audio Codec audio interface (I2S). 672*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 673*f763b8ceSMatthias Ringwald */ 674*f763b8ceSMatthias Ringwald static uint8_t I2S3_Init(uint32_t AudioFreq) 675*f763b8ceSMatthias Ringwald { 676*f763b8ceSMatthias Ringwald /* Initialize the hAudioOutI2s Instance parameter */ 677*f763b8ceSMatthias Ringwald hAudioOutI2s.Instance = I2S3; 678*f763b8ceSMatthias Ringwald 679*f763b8ceSMatthias Ringwald /* Disable I2S block */ 680*f763b8ceSMatthias Ringwald __HAL_I2S_DISABLE(&hAudioOutI2s); 681*f763b8ceSMatthias Ringwald 682*f763b8ceSMatthias Ringwald /* I2S3 peripheral configuration */ 683*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.AudioFreq = AudioFreq; 684*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.ClockSource = I2S_CLOCK_PLL; 685*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.CPOL = I2S_CPOL_LOW; 686*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.DataFormat = I2S_DATAFORMAT_16B; 687*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; 688*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.Mode = I2S_MODE_MASTER_TX; 689*f763b8ceSMatthias Ringwald hAudioOutI2s.Init.Standard = I2S_STANDARD; 690*f763b8ceSMatthias Ringwald /* Initialize the I2S peripheral with the structure above */ 691*f763b8ceSMatthias Ringwald if(HAL_I2S_Init(&hAudioOutI2s) != HAL_OK) 692*f763b8ceSMatthias Ringwald { 693*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 694*f763b8ceSMatthias Ringwald } 695*f763b8ceSMatthias Ringwald else 696*f763b8ceSMatthias Ringwald { 697*f763b8ceSMatthias Ringwald return AUDIO_OK; 698*f763b8ceSMatthias Ringwald } 699*f763b8ceSMatthias Ringwald } 700*f763b8ceSMatthias Ringwald 701*f763b8ceSMatthias Ringwald /** 702*f763b8ceSMatthias Ringwald * @} 703*f763b8ceSMatthias Ringwald */ 704*f763b8ceSMatthias Ringwald 705*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_Private_Functions STM32F4 DISCOVERY AUDIO IN Private Functions 706*f763b8ceSMatthias Ringwald * @{ 707*f763b8ceSMatthias Ringwald */ 708*f763b8ceSMatthias Ringwald 709*f763b8ceSMatthias Ringwald /** 710*f763b8ceSMatthias Ringwald * @brief Initializes wave recording. 711*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 712*f763b8ceSMatthias Ringwald * @param BitRes: Audio frequency to be configured for the I2S peripheral. 713*f763b8ceSMatthias Ringwald * @param ChnlNbr: Audio frequency to be configured for the I2S peripheral. 714*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 715*f763b8ceSMatthias Ringwald */ 716*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) 717*f763b8ceSMatthias Ringwald { 718*f763b8ceSMatthias Ringwald 719*f763b8ceSMatthias Ringwald #if 0 720*f763b8ceSMatthias Ringwald // BK: only do PLL clock configuration in sink 721*f763b8ceSMatthias Ringwald /* Configure PLL clock */ 722*f763b8ceSMatthias Ringwald BSP_AUDIO_IN_ClockConfig(&hAudioInI2s, AudioFreq, NULL); 723*f763b8ceSMatthias Ringwald #endif 724*f763b8ceSMatthias Ringwald 725*f763b8ceSMatthias Ringwald /* Configure the PDM library */ 726*f763b8ceSMatthias Ringwald PDMDecoder_Init(AudioFreq, ChnlNbr); 727*f763b8ceSMatthias Ringwald 728*f763b8ceSMatthias Ringwald /* Configure the I2S peripheral */ 729*f763b8ceSMatthias Ringwald hAudioInI2s.Instance = I2S2; 730*f763b8ceSMatthias Ringwald if(HAL_I2S_GetState(&hAudioInI2s) == HAL_I2S_STATE_RESET) 731*f763b8ceSMatthias Ringwald { 732*f763b8ceSMatthias Ringwald /* Initialize the I2S Msp: this __weak function can be rewritten by the application */ 733*f763b8ceSMatthias Ringwald BSP_AUDIO_IN_MspInit(&hAudioInI2s, NULL); 734*f763b8ceSMatthias Ringwald } 735*f763b8ceSMatthias Ringwald 736*f763b8ceSMatthias Ringwald /* Configure the I2S2 */ 737*f763b8ceSMatthias Ringwald I2S2_Init(AudioFreq); 738*f763b8ceSMatthias Ringwald 739*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 740*f763b8ceSMatthias Ringwald return AUDIO_OK; 741*f763b8ceSMatthias Ringwald } 742*f763b8ceSMatthias Ringwald 743*f763b8ceSMatthias Ringwald /** 744*f763b8ceSMatthias Ringwald * @brief Starts audio recording. 745*f763b8ceSMatthias Ringwald * @param pbuf: Main buffer pointer for the recorded data storing 746*f763b8ceSMatthias Ringwald * @param size: Current size of the recorded buffer 747*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 748*f763b8ceSMatthias Ringwald */ 749*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) 750*f763b8ceSMatthias Ringwald { 751*f763b8ceSMatthias Ringwald uint32_t ret = AUDIO_ERROR; 752*f763b8ceSMatthias Ringwald 753*f763b8ceSMatthias Ringwald /* Start the process receive DMA */ 754*f763b8ceSMatthias Ringwald HAL_I2S_Receive_DMA(&hAudioInI2s, pbuf, size); 755*f763b8ceSMatthias Ringwald 756*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 757*f763b8ceSMatthias Ringwald ret = AUDIO_OK; 758*f763b8ceSMatthias Ringwald 759*f763b8ceSMatthias Ringwald return ret; 760*f763b8ceSMatthias Ringwald } 761*f763b8ceSMatthias Ringwald 762*f763b8ceSMatthias Ringwald /** 763*f763b8ceSMatthias Ringwald * @brief Stops audio recording. 764*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 765*f763b8ceSMatthias Ringwald */ 766*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_Stop(void) 767*f763b8ceSMatthias Ringwald { 768*f763b8ceSMatthias Ringwald uint32_t ret = AUDIO_ERROR; 769*f763b8ceSMatthias Ringwald 770*f763b8ceSMatthias Ringwald /* Call the Media layer pause function */ 771*f763b8ceSMatthias Ringwald HAL_I2S_DMAStop(&hAudioInI2s); 772*f763b8ceSMatthias Ringwald 773*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 774*f763b8ceSMatthias Ringwald ret = AUDIO_OK; 775*f763b8ceSMatthias Ringwald 776*f763b8ceSMatthias Ringwald return ret; 777*f763b8ceSMatthias Ringwald } 778*f763b8ceSMatthias Ringwald 779*f763b8ceSMatthias Ringwald /** 780*f763b8ceSMatthias Ringwald * @brief Pauses the audio file stream. 781*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 782*f763b8ceSMatthias Ringwald */ 783*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_Pause(void) 784*f763b8ceSMatthias Ringwald { 785*f763b8ceSMatthias Ringwald /* Call the Media layer pause function */ 786*f763b8ceSMatthias Ringwald HAL_I2S_DMAPause(&hAudioInI2s); 787*f763b8ceSMatthias Ringwald 788*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 789*f763b8ceSMatthias Ringwald return AUDIO_OK; 790*f763b8ceSMatthias Ringwald } 791*f763b8ceSMatthias Ringwald 792*f763b8ceSMatthias Ringwald /** 793*f763b8ceSMatthias Ringwald * @brief Resumes the audio file stream. 794*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 795*f763b8ceSMatthias Ringwald */ 796*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_Resume(void) 797*f763b8ceSMatthias Ringwald { 798*f763b8ceSMatthias Ringwald /* Call the Media layer pause/resume function */ 799*f763b8ceSMatthias Ringwald HAL_I2S_DMAResume(&hAudioInI2s); 800*f763b8ceSMatthias Ringwald 801*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 802*f763b8ceSMatthias Ringwald return AUDIO_OK; 803*f763b8ceSMatthias Ringwald } 804*f763b8ceSMatthias Ringwald 805*f763b8ceSMatthias Ringwald /** 806*f763b8ceSMatthias Ringwald * @brief Controls the audio in volume level. 807*f763b8ceSMatthias Ringwald * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for 808*f763b8ceSMatthias Ringwald * Mute and 100 for Max volume level). 809*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 810*f763b8ceSMatthias Ringwald */ 811*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) 812*f763b8ceSMatthias Ringwald { 813*f763b8ceSMatthias Ringwald /* Set the Global variable AudioInVolume */ 814*f763b8ceSMatthias Ringwald AudioInVolume = Volume; 815*f763b8ceSMatthias Ringwald 816*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 817*f763b8ceSMatthias Ringwald return AUDIO_OK; 818*f763b8ceSMatthias Ringwald } 819*f763b8ceSMatthias Ringwald 820*f763b8ceSMatthias Ringwald /** 821*f763b8ceSMatthias Ringwald * @brief Converts audio format from PDM to PCM. 822*f763b8ceSMatthias Ringwald * @param PDMBuf: Pointer to data PDM buffer 823*f763b8ceSMatthias Ringwald * @param PCMBuf: Pointer to data PCM buffer 824*f763b8ceSMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 825*f763b8ceSMatthias Ringwald */ 826*f763b8ceSMatthias Ringwald uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t *PDMBuf, uint16_t *PCMBuf) 827*f763b8ceSMatthias Ringwald { 828*f763b8ceSMatthias Ringwald uint16_t AppPDM[INTERNAL_BUFF_SIZE/2]; 829*f763b8ceSMatthias Ringwald uint32_t index = 0; 830*f763b8ceSMatthias Ringwald 831*f763b8ceSMatthias Ringwald /* PDM Demux */ 832*f763b8ceSMatthias Ringwald for(index = 0; index<INTERNAL_BUFF_SIZE/2; index++) 833*f763b8ceSMatthias Ringwald { 834*f763b8ceSMatthias Ringwald AppPDM[index] = HTONS(PDMBuf[index]); 835*f763b8ceSMatthias Ringwald } 836*f763b8ceSMatthias Ringwald 837*f763b8ceSMatthias Ringwald for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++) 838*f763b8ceSMatthias Ringwald { 839*f763b8ceSMatthias Ringwald /* PDM to PCM filter */ 840*f763b8ceSMatthias Ringwald PDM_Filter_64_LSB((uint8_t*)&AppPDM[index], (uint16_t*)&(PCMBuf[index]), AudioInVolume , (PDMFilter_InitStruct *)&Filter[index]); 841*f763b8ceSMatthias Ringwald } 842*f763b8ceSMatthias Ringwald #if 0 843*f763b8ceSMatthias Ringwald // BK - generate mono output 844*f763b8ceSMatthias Ringwald 845*f763b8ceSMatthias Ringwald /* Duplicate samples since a single microphone in mounted on STM32F4-Discovery */ 846*f763b8ceSMatthias Ringwald for(index = 0; index < PCM_OUT_SIZE; index++) 847*f763b8ceSMatthias Ringwald { 848*f763b8ceSMatthias Ringwald PCMBuf[(index<<1)+1] = PCMBuf[index<<1]; 849*f763b8ceSMatthias Ringwald } 850*f763b8ceSMatthias Ringwald #endif 851*f763b8ceSMatthias Ringwald 852*f763b8ceSMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 853*f763b8ceSMatthias Ringwald return AUDIO_OK; 854*f763b8ceSMatthias Ringwald } 855*f763b8ceSMatthias Ringwald 856*f763b8ceSMatthias Ringwald /** 857*f763b8ceSMatthias Ringwald * @brief Rx Transfer completed callbacks 858*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 859*f763b8ceSMatthias Ringwald */ 860*f763b8ceSMatthias Ringwald void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) 861*f763b8ceSMatthias Ringwald { 862*f763b8ceSMatthias Ringwald /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ 863*f763b8ceSMatthias Ringwald BSP_AUDIO_IN_TransferComplete_CallBack(); 864*f763b8ceSMatthias Ringwald } 865*f763b8ceSMatthias Ringwald 866*f763b8ceSMatthias Ringwald /** 867*f763b8ceSMatthias Ringwald * @brief Rx Half Transfer completed callbacks. 868*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 869*f763b8ceSMatthias Ringwald */ 870*f763b8ceSMatthias Ringwald void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) 871*f763b8ceSMatthias Ringwald { 872*f763b8ceSMatthias Ringwald /* Manage the remaining file size and new address offset: This function 873*f763b8ceSMatthias Ringwald should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */ 874*f763b8ceSMatthias Ringwald BSP_AUDIO_IN_HalfTransfer_CallBack(); 875*f763b8ceSMatthias Ringwald } 876*f763b8ceSMatthias Ringwald 877*f763b8ceSMatthias Ringwald /** 878*f763b8ceSMatthias Ringwald * @brief Audio In Clock Config. 879*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 880*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency used to record the audio stream. 881*f763b8ceSMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 882*f763b8ceSMatthias Ringwald * @note This API is called by BSP_AUDIO_IN_Init() 883*f763b8ceSMatthias Ringwald * Being __weak it can be overwritten by the application 884*f763b8ceSMatthias Ringwald */ 885*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params) 886*f763b8ceSMatthias Ringwald { 887*f763b8ceSMatthias Ringwald RCC_PeriphCLKInitTypeDef rccclkinit; 888*f763b8ceSMatthias Ringwald 889*f763b8ceSMatthias Ringwald /*Enable PLLI2S clock*/ 890*f763b8ceSMatthias Ringwald HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit); 891*f763b8ceSMatthias Ringwald /* PLLI2S_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ 892*f763b8ceSMatthias Ringwald if ((AudioFreq & 0x7) == 0) 893*f763b8ceSMatthias Ringwald { 894*f763b8ceSMatthias Ringwald /* Audio frequency multiple of 8 (8/16/32/48/96/192)*/ 895*f763b8ceSMatthias Ringwald /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN = 192 Mhz */ 896*f763b8ceSMatthias Ringwald /* I2SCLK = PLLI2S_VCO Output/PLLI2SR = 192/6 = 32 Mhz */ 897*f763b8ceSMatthias Ringwald rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S; 898*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SN = 192; 899*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SR = 6; 900*f763b8ceSMatthias Ringwald HAL_RCCEx_PeriphCLKConfig(&rccclkinit); 901*f763b8ceSMatthias Ringwald } 902*f763b8ceSMatthias Ringwald else 903*f763b8ceSMatthias Ringwald { 904*f763b8ceSMatthias Ringwald /* Other Frequency (11.025/22.500/44.100) */ 905*f763b8ceSMatthias Ringwald /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN = 290 Mhz */ 906*f763b8ceSMatthias Ringwald /* I2SCLK = PLLI2S_VCO Output/PLLI2SR = 290/2 = 145 Mhz */ 907*f763b8ceSMatthias Ringwald rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S; 908*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SN = 290; 909*f763b8ceSMatthias Ringwald rccclkinit.PLLI2S.PLLI2SR = 2; 910*f763b8ceSMatthias Ringwald HAL_RCCEx_PeriphCLKConfig(&rccclkinit); 911*f763b8ceSMatthias Ringwald } 912*f763b8ceSMatthias Ringwald } 913*f763b8ceSMatthias Ringwald 914*f763b8ceSMatthias Ringwald /** 915*f763b8ceSMatthias Ringwald * @brief BSP AUDIO IN MSP Init. 916*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 917*f763b8ceSMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 918*f763b8ceSMatthias Ringwald */ 919*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params) 920*f763b8ceSMatthias Ringwald { 921*f763b8ceSMatthias Ringwald static DMA_HandleTypeDef hdma_i2sRx; 922*f763b8ceSMatthias Ringwald GPIO_InitTypeDef GPIO_InitStruct; 923*f763b8ceSMatthias Ringwald 924*f763b8ceSMatthias Ringwald /* Enable the I2S2 peripheral clock */ 925*f763b8ceSMatthias Ringwald I2S2_CLK_ENABLE(); 926*f763b8ceSMatthias Ringwald 927*f763b8ceSMatthias Ringwald /* Enable I2S GPIO clocks */ 928*f763b8ceSMatthias Ringwald I2S2_SCK_GPIO_CLK_ENABLE(); 929*f763b8ceSMatthias Ringwald I2S2_MOSI_GPIO_CLK_ENABLE(); 930*f763b8ceSMatthias Ringwald 931*f763b8ceSMatthias Ringwald /* I2S2 pins configuration: SCK and MOSI pins ------------------------------*/ 932*f763b8ceSMatthias Ringwald GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 933*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pull = GPIO_NOPULL; 934*f763b8ceSMatthias Ringwald GPIO_InitStruct.Speed = GPIO_SPEED_FAST; 935*f763b8ceSMatthias Ringwald 936*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S2_SCK_PIN; 937*f763b8ceSMatthias Ringwald GPIO_InitStruct.Alternate = I2S2_SCK_AF; 938*f763b8ceSMatthias Ringwald HAL_GPIO_Init(I2S2_SCK_GPIO_PORT, &GPIO_InitStruct); 939*f763b8ceSMatthias Ringwald 940*f763b8ceSMatthias Ringwald GPIO_InitStruct.Pin = I2S2_MOSI_PIN ; 941*f763b8ceSMatthias Ringwald GPIO_InitStruct.Alternate = I2S2_MOSI_AF; 942*f763b8ceSMatthias Ringwald HAL_GPIO_Init(I2S2_MOSI_GPIO_PORT, &GPIO_InitStruct); 943*f763b8ceSMatthias Ringwald 944*f763b8ceSMatthias Ringwald /* Enable the DMA clock */ 945*f763b8ceSMatthias Ringwald I2S2_DMAx_CLK_ENABLE(); 946*f763b8ceSMatthias Ringwald 947*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S2) 948*f763b8ceSMatthias Ringwald { 949*f763b8ceSMatthias Ringwald /* Configure the hdma_i2sRx handle parameters */ 950*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.Channel = I2S2_DMAx_CHANNEL; 951*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.Direction = DMA_PERIPH_TO_MEMORY; 952*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.PeriphInc = DMA_PINC_DISABLE; 953*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.MemInc = DMA_MINC_ENABLE; 954*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.PeriphDataAlignment = I2S2_DMAx_PERIPH_DATA_SIZE; 955*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.MemDataAlignment = I2S2_DMAx_MEM_DATA_SIZE; 956*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.Mode = DMA_CIRCULAR; 957*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.Priority = DMA_PRIORITY_HIGH; 958*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 959*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; 960*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.MemBurst = DMA_MBURST_SINGLE; 961*f763b8ceSMatthias Ringwald hdma_i2sRx.Init.PeriphBurst = DMA_MBURST_SINGLE; 962*f763b8ceSMatthias Ringwald 963*f763b8ceSMatthias Ringwald hdma_i2sRx.Instance = I2S2_DMAx_STREAM; 964*f763b8ceSMatthias Ringwald 965*f763b8ceSMatthias Ringwald /* Associate the DMA handle */ 966*f763b8ceSMatthias Ringwald __HAL_LINKDMA(hi2s, hdmarx, hdma_i2sRx); 967*f763b8ceSMatthias Ringwald 968*f763b8ceSMatthias Ringwald /* Deinitialize the Stream for new transfer */ 969*f763b8ceSMatthias Ringwald HAL_DMA_DeInit(&hdma_i2sRx); 970*f763b8ceSMatthias Ringwald 971*f763b8ceSMatthias Ringwald /* Configure the DMA Stream */ 972*f763b8ceSMatthias Ringwald HAL_DMA_Init(&hdma_i2sRx); 973*f763b8ceSMatthias Ringwald } 974*f763b8ceSMatthias Ringwald 975*f763b8ceSMatthias Ringwald /* I2S DMA IRQ Channel configuration */ 976*f763b8ceSMatthias Ringwald HAL_NVIC_SetPriority(I2S2_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); 977*f763b8ceSMatthias Ringwald HAL_NVIC_EnableIRQ(I2S2_DMAx_IRQ); 978*f763b8ceSMatthias Ringwald } 979*f763b8ceSMatthias Ringwald 980*f763b8ceSMatthias Ringwald /** 981*f763b8ceSMatthias Ringwald * @brief DeInitializes BSP_AUDIO_IN MSP. 982*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 983*f763b8ceSMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 984*f763b8ceSMatthias Ringwald */ 985*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params) 986*f763b8ceSMatthias Ringwald { 987*f763b8ceSMatthias Ringwald GPIO_InitTypeDef gpio_init_structure; 988*f763b8ceSMatthias Ringwald 989*f763b8ceSMatthias Ringwald /* I2S DMA IRQ Channel deactivation */ 990*f763b8ceSMatthias Ringwald HAL_NVIC_DisableIRQ(I2S2_DMAx_IRQ); 991*f763b8ceSMatthias Ringwald 992*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S2) 993*f763b8ceSMatthias Ringwald { 994*f763b8ceSMatthias Ringwald /* Deinitialize the Stream for new transfer */ 995*f763b8ceSMatthias Ringwald HAL_DMA_DeInit(hi2s->hdmarx); 996*f763b8ceSMatthias Ringwald } 997*f763b8ceSMatthias Ringwald 998*f763b8ceSMatthias Ringwald /* Disable I2S block */ 999*f763b8ceSMatthias Ringwald __HAL_I2S_DISABLE(hi2s); 1000*f763b8ceSMatthias Ringwald 1001*f763b8ceSMatthias Ringwald /* Disable pins: SCK and SD pins */ 1002*f763b8ceSMatthias Ringwald gpio_init_structure.Pin = I2S2_SCK_PIN; 1003*f763b8ceSMatthias Ringwald HAL_GPIO_DeInit(I2S2_SCK_GPIO_PORT, gpio_init_structure.Pin); 1004*f763b8ceSMatthias Ringwald gpio_init_structure.Pin = I2S2_MOSI_PIN; 1005*f763b8ceSMatthias Ringwald HAL_GPIO_DeInit(I2S2_MOSI_GPIO_PORT, gpio_init_structure.Pin); 1006*f763b8ceSMatthias Ringwald 1007*f763b8ceSMatthias Ringwald /* Disable I2S clock */ 1008*f763b8ceSMatthias Ringwald I2S2_CLK_DISABLE(); 1009*f763b8ceSMatthias Ringwald 1010*f763b8ceSMatthias Ringwald /* GPIO pins clock and DMA clock can be shut down in the applic 1011*f763b8ceSMatthias Ringwald by surcgarging this __weak function */ 1012*f763b8ceSMatthias Ringwald } 1013*f763b8ceSMatthias Ringwald 1014*f763b8ceSMatthias Ringwald /** 1015*f763b8ceSMatthias Ringwald * @brief User callback when record buffer is filled. 1016*f763b8ceSMatthias Ringwald */ 1017*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) 1018*f763b8ceSMatthias Ringwald { 1019*f763b8ceSMatthias Ringwald /* This function should be implemented by the user application. 1020*f763b8ceSMatthias Ringwald It is called into this driver when the current buffer is filled 1021*f763b8ceSMatthias Ringwald to prepare the next buffer pointer and its size. */ 1022*f763b8ceSMatthias Ringwald } 1023*f763b8ceSMatthias Ringwald 1024*f763b8ceSMatthias Ringwald /** 1025*f763b8ceSMatthias Ringwald * @brief Manages the DMA Half Transfer complete event. 1026*f763b8ceSMatthias Ringwald */ 1027*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) 1028*f763b8ceSMatthias Ringwald { 1029*f763b8ceSMatthias Ringwald /* This function should be implemented by the user application. 1030*f763b8ceSMatthias Ringwald It is called into this driver when the current buffer is filled 1031*f763b8ceSMatthias Ringwald to prepare the next buffer pointer and its size. */ 1032*f763b8ceSMatthias Ringwald } 1033*f763b8ceSMatthias Ringwald 1034*f763b8ceSMatthias Ringwald /** 1035*f763b8ceSMatthias Ringwald * @brief Audio IN Error callback function. 1036*f763b8ceSMatthias Ringwald */ 1037*f763b8ceSMatthias Ringwald __weak void BSP_AUDIO_IN_Error_Callback(void) 1038*f763b8ceSMatthias Ringwald { 1039*f763b8ceSMatthias Ringwald /* This function is called when an Interrupt due to transfer error on or peripheral 1040*f763b8ceSMatthias Ringwald error occurs. */ 1041*f763b8ceSMatthias Ringwald } 1042*f763b8ceSMatthias Ringwald 1043*f763b8ceSMatthias Ringwald /******************************************************************************* 1044*f763b8ceSMatthias Ringwald Static Functions 1045*f763b8ceSMatthias Ringwald *******************************************************************************/ 1046*f763b8ceSMatthias Ringwald 1047*f763b8ceSMatthias Ringwald /** 1048*f763b8ceSMatthias Ringwald * @brief Initialize the PDM library. 1049*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio sampling frequency 1050*f763b8ceSMatthias Ringwald * @param ChnlNbr: Number of audio channels (1: mono; 2: stereo) 1051*f763b8ceSMatthias Ringwald */ 1052*f763b8ceSMatthias Ringwald static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr) 1053*f763b8ceSMatthias Ringwald { 1054*f763b8ceSMatthias Ringwald #if 1 1055*f763b8ceSMatthias Ringwald uint32_t i = 0; 1056*f763b8ceSMatthias Ringwald 1057*f763b8ceSMatthias Ringwald /* Enable CRC peripheral to unlock the PDM library */ 1058*f763b8ceSMatthias Ringwald __CRC_CLK_ENABLE(); 1059*f763b8ceSMatthias Ringwald 1060*f763b8ceSMatthias Ringwald for(i = 0; i < ChnlNbr; i++) 1061*f763b8ceSMatthias Ringwald { 1062*f763b8ceSMatthias Ringwald /* Filter LP and HP Init */ 1063*f763b8ceSMatthias Ringwald Filter[i].LP_HZ = AudioFreq / 2; 1064*f763b8ceSMatthias Ringwald Filter[i].HP_HZ = 10; 1065*f763b8ceSMatthias Ringwald Filter[i].Fs = AudioFreq; 1066*f763b8ceSMatthias Ringwald /* On STM32F4-Discovery a single microphone is mounted, samples are duplicated 1067*f763b8ceSMatthias Ringwald to make stereo audio streams */ 1068*f763b8ceSMatthias Ringwald // BK - generate mono output 1069*f763b8ceSMatthias Ringwald // Filter[i].Out_MicChannels = 2; 1070*f763b8ceSMatthias Ringwald Filter[i].Out_MicChannels = 1; 1071*f763b8ceSMatthias Ringwald Filter[i].In_MicChannels = ChnlNbr; 1072*f763b8ceSMatthias Ringwald PDM_Filter_Init((PDMFilter_InitStruct *)&Filter[i]); 1073*f763b8ceSMatthias Ringwald } 1074*f763b8ceSMatthias Ringwald #endif 1075*f763b8ceSMatthias Ringwald } 1076*f763b8ceSMatthias Ringwald 1077*f763b8ceSMatthias Ringwald /** 1078*f763b8ceSMatthias Ringwald * @brief Initializes the Audio Codec audio interface (I2S) 1079*f763b8ceSMatthias Ringwald * @note This function assumes that the I2S input clock (through PLL_R in 1080*f763b8ceSMatthias Ringwald * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y) 1081*f763b8ceSMatthias Ringwald * is already configured and ready to be used. 1082*f763b8ceSMatthias Ringwald * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 1083*f763b8ceSMatthias Ringwald */ 1084*f763b8ceSMatthias Ringwald static uint8_t I2S2_Init(uint32_t AudioFreq) 1085*f763b8ceSMatthias Ringwald { 1086*f763b8ceSMatthias Ringwald /* Initialize the hAudioInI2s Instance parameter */ 1087*f763b8ceSMatthias Ringwald hAudioInI2s.Instance = I2S2; 1088*f763b8ceSMatthias Ringwald 1089*f763b8ceSMatthias Ringwald /* Disable I2S block */ 1090*f763b8ceSMatthias Ringwald __HAL_I2S_DISABLE(&hAudioInI2s); 1091*f763b8ceSMatthias Ringwald 1092*f763b8ceSMatthias Ringwald /* I2S2 peripheral configuration */ 1093*f763b8ceSMatthias Ringwald hAudioInI2s.Init.AudioFreq = 2 * AudioFreq; 1094*f763b8ceSMatthias Ringwald hAudioInI2s.Init.ClockSource = I2S_CLOCK_PLL; 1095*f763b8ceSMatthias Ringwald hAudioInI2s.Init.CPOL = I2S_CPOL_HIGH; 1096*f763b8ceSMatthias Ringwald hAudioInI2s.Init.DataFormat = I2S_DATAFORMAT_16B; 1097*f763b8ceSMatthias Ringwald hAudioInI2s.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; 1098*f763b8ceSMatthias Ringwald hAudioInI2s.Init.Mode = I2S_MODE_MASTER_RX; 1099*f763b8ceSMatthias Ringwald hAudioInI2s.Init.Standard = I2S_STANDARD_LSB; 1100*f763b8ceSMatthias Ringwald 1101*f763b8ceSMatthias Ringwald /* Initialize the I2S peripheral with the structure above */ 1102*f763b8ceSMatthias Ringwald if(HAL_I2S_Init(&hAudioInI2s) != HAL_OK) 1103*f763b8ceSMatthias Ringwald { 1104*f763b8ceSMatthias Ringwald return AUDIO_ERROR; 1105*f763b8ceSMatthias Ringwald } 1106*f763b8ceSMatthias Ringwald else 1107*f763b8ceSMatthias Ringwald { 1108*f763b8ceSMatthias Ringwald return AUDIO_OK; 1109*f763b8ceSMatthias Ringwald } 1110*f763b8ceSMatthias Ringwald } 1111*f763b8ceSMatthias Ringwald 1112*f763b8ceSMatthias Ringwald /** 1113*f763b8ceSMatthias Ringwald * @} 1114*f763b8ceSMatthias Ringwald */ 1115*f763b8ceSMatthias Ringwald 1116*f763b8ceSMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_OUT_Private_Functions STM32F4 DISCOVERY AUDIO IN OUT Private Functions 1117*f763b8ceSMatthias Ringwald * @{ 1118*f763b8ceSMatthias Ringwald */ 1119*f763b8ceSMatthias Ringwald 1120*f763b8ceSMatthias Ringwald /** 1121*f763b8ceSMatthias Ringwald * @brief I2S error callbacks. 1122*f763b8ceSMatthias Ringwald * @param hi2s: I2S handle 1123*f763b8ceSMatthias Ringwald */ 1124*f763b8ceSMatthias Ringwald void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) 1125*f763b8ceSMatthias Ringwald { 1126*f763b8ceSMatthias Ringwald /* Manage the error generated on DMA FIFO: This function 1127*f763b8ceSMatthias Ringwald should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */ 1128*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S3) 1129*f763b8ceSMatthias Ringwald { 1130*f763b8ceSMatthias Ringwald BSP_AUDIO_OUT_Error_CallBack(); 1131*f763b8ceSMatthias Ringwald } 1132*f763b8ceSMatthias Ringwald if(hi2s->Instance == I2S2) 1133*f763b8ceSMatthias Ringwald { 1134*f763b8ceSMatthias Ringwald BSP_AUDIO_IN_Error_Callback(); 1135*f763b8ceSMatthias Ringwald } 1136*f763b8ceSMatthias Ringwald } 1137*f763b8ceSMatthias Ringwald 1138*f763b8ceSMatthias Ringwald /** 1139*f763b8ceSMatthias Ringwald * @} 1140*f763b8ceSMatthias Ringwald */ 1141*f763b8ceSMatthias Ringwald 1142*f763b8ceSMatthias Ringwald /** 1143*f763b8ceSMatthias Ringwald * @} 1144*f763b8ceSMatthias Ringwald */ 1145*f763b8ceSMatthias Ringwald 1146*f763b8ceSMatthias Ringwald /** 1147*f763b8ceSMatthias Ringwald * @} 1148*f763b8ceSMatthias Ringwald */ 1149*f763b8ceSMatthias Ringwald 1150*f763b8ceSMatthias Ringwald /** 1151*f763b8ceSMatthias Ringwald * @} 1152*f763b8ceSMatthias Ringwald */ 1153*f763b8ceSMatthias Ringwald 1154*f763b8ceSMatthias Ringwald /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 1155