1225f4ba4SMatthias Ringwald /** 2225f4ba4SMatthias Ringwald ****************************************************************************** 3225f4ba4SMatthias Ringwald * @file stm32f4_discovery_audio.c 4225f4ba4SMatthias Ringwald * @author MCD Application Team 5225f4ba4SMatthias Ringwald * @version V2.1.2 6225f4ba4SMatthias Ringwald * @date 27-January-2017 7225f4ba4SMatthias Ringwald * @brief This file provides the Audio driver for the STM32F4-Discovery 8225f4ba4SMatthias Ringwald * board. 9225f4ba4SMatthias Ringwald ****************************************************************************** 10225f4ba4SMatthias Ringwald * @attention 11225f4ba4SMatthias Ringwald * 12225f4ba4SMatthias Ringwald * <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2> 13225f4ba4SMatthias Ringwald * 14225f4ba4SMatthias Ringwald * Redistribution and use in source and binary forms, with or without modification, 15225f4ba4SMatthias Ringwald * are permitted provided that the following conditions are met: 16225f4ba4SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright notice, 17225f4ba4SMatthias Ringwald * this list of conditions and the following disclaimer. 18225f4ba4SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright notice, 19225f4ba4SMatthias Ringwald * this list of conditions and the following disclaimer in the documentation 20225f4ba4SMatthias Ringwald * and/or other materials provided with the distribution. 21225f4ba4SMatthias Ringwald * 3. Neither the name of STMicroelectronics nor the names of its contributors 22225f4ba4SMatthias Ringwald * may be used to endorse or promote products derived from this software 23225f4ba4SMatthias Ringwald * without specific prior written permission. 24225f4ba4SMatthias Ringwald * 25225f4ba4SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26225f4ba4SMatthias Ringwald * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27225f4ba4SMatthias Ringwald * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28225f4ba4SMatthias Ringwald * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 29225f4ba4SMatthias Ringwald * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30225f4ba4SMatthias Ringwald * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31225f4ba4SMatthias Ringwald * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32225f4ba4SMatthias Ringwald * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33225f4ba4SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34225f4ba4SMatthias Ringwald * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35225f4ba4SMatthias Ringwald * 36225f4ba4SMatthias Ringwald ****************************************************************************** 37225f4ba4SMatthias Ringwald */ 38225f4ba4SMatthias Ringwald 39225f4ba4SMatthias Ringwald /*============================================================================== 40225f4ba4SMatthias Ringwald User NOTES 41225f4ba4SMatthias Ringwald 1. How To use this driver: 42225f4ba4SMatthias Ringwald -------------------------- 43225f4ba4SMatthias Ringwald - This driver supports STM32F4xx devices on STM32F4-Discovery Kit: 44225f4ba4SMatthias Ringwald a) to play an audio file (all functions names start by BSP_AUDIO_OUT_xxx) 45225f4ba4SMatthias Ringwald b) to record an audio file through MP45DT02, ST MEMS (all functions names start by AUDIO_IN_xxx) 46225f4ba4SMatthias Ringwald 47225f4ba4SMatthias Ringwald a) PLAY A FILE: 48225f4ba4SMatthias Ringwald ============== 49225f4ba4SMatthias Ringwald + Call the function BSP_AUDIO_OUT_Init( 50225f4ba4SMatthias Ringwald OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, 51225f4ba4SMatthias Ringwald OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_AUTO or 52225f4ba4SMatthias Ringwald OUTPUT_DEVICE_BOTH) 53225f4ba4SMatthias Ringwald Volume: initial volume to be set (0 is min (mute), 100 is max (100%) 54225f4ba4SMatthias Ringwald AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...) 55225f4ba4SMatthias Ringwald this parameter is relative to the audio file/stream type. 56225f4ba4SMatthias Ringwald ) 57225f4ba4SMatthias Ringwald This function configures all the hardware required for the audio application (codec, I2C, I2S, 58225f4ba4SMatthias Ringwald GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK. 59225f4ba4SMatthias Ringwald If the returned value is different from 0 or the function is stuck then the communication with 60225f4ba4SMatthias Ringwald the codec (try to un-plug the power or reset device in this case). 61225f4ba4SMatthias Ringwald - OUTPUT_DEVICE_SPEAKER: only speaker will be set as output for the audio stream. 62225f4ba4SMatthias Ringwald - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. 63225f4ba4SMatthias Ringwald - OUTPUT_DEVICE_AUTO: Selection of output device is made through external switch (implemented 64225f4ba4SMatthias Ringwald into the audio jack on the discovery board). When the Headphone is connected it is used 65225f4ba4SMatthias Ringwald as output. When the headphone is disconnected from the audio jack, the output is 66225f4ba4SMatthias Ringwald automatically switched to Speaker. 67225f4ba4SMatthias Ringwald - OUTPUT_DEVICE_BOTH: both Speaker and Headphone are used as outputs for the audio stream 68225f4ba4SMatthias Ringwald at the same time. 69225f4ba4SMatthias Ringwald + Call the function BSP_AUDIO_OUT_Play( 70225f4ba4SMatthias Ringwald pBuffer: pointer to the audio data file address 71225f4ba4SMatthias Ringwald Size: size of the buffer to be sent in Bytes 72225f4ba4SMatthias Ringwald ) 73225f4ba4SMatthias Ringwald to start playing (for the first time) from the audio file/stream. 74225f4ba4SMatthias Ringwald + Call the function BSP_AUDIO_OUT_Pause() to pause playing 75225f4ba4SMatthias Ringwald + Call the function BSP_AUDIO_OUT_Resume() to resume playing. 76225f4ba4SMatthias Ringwald Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called 77225f4ba4SMatthias Ringwald for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). 78225f4ba4SMatthias Ringwald Note. This function should be called only when the audio file is played or paused (not stopped). 79225f4ba4SMatthias Ringwald + For each mode, you may need to implement the relative callback functions into your code. 80225f4ba4SMatthias Ringwald The Callback functions are named BSP_AUDIO_OUT_XXXCallBack() and only their prototypes are declared in 81225f4ba4SMatthias Ringwald the stm32f4_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) 82225f4ba4SMatthias Ringwald + To Stop playing, to modify the volume level, the frequency or to mute, use the functions 83225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_Stop(), BSP_AUDIO_OUT_SetVolume(), AUDIO_OUT_SetFrequency() BSP_AUDIO_OUT_SetOutputMode and BSP_AUDIO_OUT_SetMute(). 84225f4ba4SMatthias Ringwald + The driver API and the callback functions are at the end of the stm32f4_discovery_audio.h file. 85225f4ba4SMatthias Ringwald 86225f4ba4SMatthias Ringwald Driver architecture: 87225f4ba4SMatthias Ringwald -------------------- 88225f4ba4SMatthias Ringwald + This driver provide the High Audio Layer: consists of the function API exported in the stm32f4_discovery_audio.h file 89225f4ba4SMatthias Ringwald (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) 90225f4ba4SMatthias Ringwald + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ 91225f4ba4SMatthias Ringwald providing the audio file/stream. These functions are also included as local functions into 92225f4ba4SMatthias Ringwald the stm32f4_discovery_audio.c file (I2S3_Init()...) 93225f4ba4SMatthias Ringwald 94225f4ba4SMatthias Ringwald Known Limitations: 95225f4ba4SMatthias Ringwald ------------------- 96225f4ba4SMatthias Ringwald 1- When using the Speaker, if the audio file quality is not high enough, the speaker output 97225f4ba4SMatthias Ringwald may produce high and uncomfortable noise level. To avoid this issue, to use speaker 98225f4ba4SMatthias Ringwald output properly, try to increase audio file sampling rate (typically higher than 48KHz). 99225f4ba4SMatthias Ringwald This operation will lead to larger file size. 100225f4ba4SMatthias Ringwald 2- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some 101225f4ba4SMatthias Ringwald user interrupt routines (in this case, interrupts could be disabled just before the start of 102225f4ba4SMatthias Ringwald communication then re-enabled when it is over). Note that this communication is only done at 103225f4ba4SMatthias Ringwald the configuration phase (BSP_AUDIO_OUT_Init() or BSP_AUDIO_OUT_Stop()) and when Volume control modification is 104225f4ba4SMatthias Ringwald performed (BSP_AUDIO_OUT_SetVolume() or BSP_AUDIO_OUT_SetMute()or BSP_AUDIO_OUT_SetOutputMode()). 105225f4ba4SMatthias Ringwald When the audio data is played, no communication is required with the audio codec. 106225f4ba4SMatthias Ringwald 3- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, 107225f4ba4SMatthias Ringwald File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. 108225f4ba4SMatthias Ringwald 4- Supports only Stereo audio streaming. To play mono audio streams, each data should be sent twice 109225f4ba4SMatthias Ringwald on the I2S or should be duplicated on the source buffer. Or convert the stream in stereo before playing. 110225f4ba4SMatthias Ringwald 5- Supports only 16-bits audio data size. 111225f4ba4SMatthias Ringwald 112225f4ba4SMatthias Ringwald b) RECORD A FILE: 113225f4ba4SMatthias Ringwald ================ 114225f4ba4SMatthias Ringwald + Call the function BSP_AUDIO_IN_Init( 115225f4ba4SMatthias Ringwald AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...) 116225f4ba4SMatthias Ringwald ) 117225f4ba4SMatthias Ringwald This function configures all the hardware required for the audio application (I2S, 118225f4ba4SMatthias Ringwald GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK. 119225f4ba4SMatthias Ringwald 120225f4ba4SMatthias Ringwald + Call the function BSP_AUDIO_IN_Record( 121225f4ba4SMatthias Ringwald pbuf Main buffer pointer for the recorded data storing 122225f4ba4SMatthias Ringwald size Current size of the recorded buffer 123225f4ba4SMatthias Ringwald ) 124225f4ba4SMatthias Ringwald to start recording from the microphone. 125225f4ba4SMatthias Ringwald 126225f4ba4SMatthias Ringwald + User needs to implement user callbacks to retrieve data saved in the record buffer 127225f4ba4SMatthias Ringwald (AUDIO_IN_RxHalfCpltCallback/BSP_AUDIO_IN_ReceiveComplete_CallBack) 128225f4ba4SMatthias Ringwald 129225f4ba4SMatthias Ringwald + Call the function AUDIO_IN_STOP() to stop recording 130225f4ba4SMatthias Ringwald 131225f4ba4SMatthias Ringwald ==============================================================================*/ 132225f4ba4SMatthias Ringwald 133225f4ba4SMatthias Ringwald /* Includes ------------------------------------------------------------------*/ 134225f4ba4SMatthias Ringwald #include "stm32f4_discovery_audio.h" 135225f4ba4SMatthias Ringwald #include "pdm_filter.h" 136225f4ba4SMatthias Ringwald #include "btstack_config.h" 137225f4ba4SMatthias Ringwald 138225f4ba4SMatthias Ringwald /** @addtogroup BSP 139225f4ba4SMatthias Ringwald * @{ 140225f4ba4SMatthias Ringwald */ 141225f4ba4SMatthias Ringwald 142225f4ba4SMatthias Ringwald /** @addtogroup STM32F4_DISCOVERY 143225f4ba4SMatthias Ringwald * @{ 144225f4ba4SMatthias Ringwald */ 145225f4ba4SMatthias Ringwald 146225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO STM32F4 DISCOVERY AUDIO 147225f4ba4SMatthias Ringwald * @brief This file includes the low layer audio driver available on STM32F4-Discovery 148225f4ba4SMatthias Ringwald * discovery board. 149225f4ba4SMatthias Ringwald * @{ 150225f4ba4SMatthias Ringwald */ 151225f4ba4SMatthias Ringwald 152225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Types STM32F4 DISCOVERY AUDIO Private Types 153225f4ba4SMatthias Ringwald * @{ 154225f4ba4SMatthias Ringwald */ 155225f4ba4SMatthias Ringwald /** 156225f4ba4SMatthias Ringwald * @} 157225f4ba4SMatthias Ringwald */ 158225f4ba4SMatthias Ringwald 159225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Defines STM32F4 DISCOVERY AUDIO Private Defines 160225f4ba4SMatthias Ringwald * @{ 161225f4ba4SMatthias Ringwald */ 162*2d8556b2SDirk Helbig static uint32_t bsp_audio_out_actual_frequency = 0; 163*2d8556b2SDirk Helbig static uint32_t bsp_audio_out_frequency = 0; 164*2d8556b2SDirk Helbig 165*2d8556b2SDirk Helbig typedef struct { 166*2d8556b2SDirk Helbig uint32_t freq; 167*2d8556b2SDirk Helbig uint32_t actual; 168*2d8556b2SDirk Helbig uint16_t r; 169*2d8556b2SDirk Helbig uint16_t n; 170*2d8556b2SDirk Helbig } i2s_pll_entry_t; 171*2d8556b2SDirk Helbig 172*2d8556b2SDirk Helbig // HSE_VALUE = 8000000 173*2d8556b2SDirk Helbig // PLLM = 4 174*2d8556b2SDirk Helbig // MCK on 175*2d8556b2SDirk Helbig static const i2s_pll_entry_t i2s_pll_table[] = { 176*2d8556b2SDirk Helbig { 8000, 8000, 5, 128 }, /* i2sdiv: 12, odd: 1, rate error % (desired vs actual)%: 0.0000 */ 177*2d8556b2SDirk Helbig { 11025, 11024, 2, 127 }, /* i2sdiv: 22, odd: 1, rate error % (desired vs actual)%: 0.0063 */ 178*2d8556b2SDirk Helbig { 12000, 12000, 5, 192 }, /* i2sdiv: 12, odd: 1, rate error % (desired vs actual)%: 0.0000 */ 179*2d8556b2SDirk Helbig { 16000, 16000, 4, 213 }, /* i2sdiv: 13, odd: 0, rate error % (desired vs actual)%: 0.0038 */ 180*2d8556b2SDirk Helbig { 22050, 22048, 5, 127 }, /* i2sdiv: 4, odd: 1, rate error % (desired vs actual)%: 0.0063 */ 181*2d8556b2SDirk Helbig { 24000, 24003, 3, 212 }, /* i2sdiv: 11, odd: 1, rate error % (desired vs actual)%: 0.0151 */ 182*2d8556b2SDirk Helbig { 32000, 32001, 4, 213 }, /* i2sdiv: 6, odd: 1, rate error % (desired vs actual)%: 0.0038 */ 183*2d8556b2SDirk Helbig { 44100, 44084, 2, 79 }, /* i2sdiv: 3, odd: 1, rate error % (desired vs actual)%: 0.0344 */ 184*2d8556b2SDirk Helbig { 48000, 47991, 2, 86 }, /* i2sdiv: 3, odd: 1, rate error % (desired vs actual)%: 0.0186 */ 185*2d8556b2SDirk Helbig { 96000, 95982, 2, 172 }, /* i2sdiv: 3, odd: 1, rate error % (desired vs actual)%: 0.0186 */ 186*2d8556b2SDirk Helbig }; 187*2d8556b2SDirk Helbig 188*2d8556b2SDirk Helbig #define BARRIER do { __asm__ volatile("" ::: "memory"); } while (0) 189*2d8556b2SDirk Helbig #define BINARY(I) do { \ 190*2d8556b2SDirk Helbig base = ((base)[I].freq <= key)?base+I:base; \ 191*2d8556b2SDirk Helbig BARRIER; \ 192*2d8556b2SDirk Helbig } while (0) 193*2d8556b2SDirk Helbig 194*2d8556b2SDirk Helbig static i2s_pll_entry_t const *i2s_find_pll_params( uint32_t key ) { 195*2d8556b2SDirk Helbig i2s_pll_entry_t const* base = i2s_pll_table; 196*2d8556b2SDirk Helbig BINARY(5); 197*2d8556b2SDirk Helbig BINARY(2); 198*2d8556b2SDirk Helbig BINARY(1); 199*2d8556b2SDirk Helbig BINARY(1); 200*2d8556b2SDirk Helbig return base; 201*2d8556b2SDirk Helbig } 202*2d8556b2SDirk Helbig 203225f4ba4SMatthias Ringwald /** 204225f4ba4SMatthias Ringwald * @} 205225f4ba4SMatthias Ringwald */ 206225f4ba4SMatthias Ringwald 207225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Macros STM32F4 DISCOVERY AUDIO Private Macros 208225f4ba4SMatthias Ringwald * @{ 209225f4ba4SMatthias Ringwald */ 210225f4ba4SMatthias Ringwald /** 211225f4ba4SMatthias Ringwald * @} 212225f4ba4SMatthias Ringwald */ 213225f4ba4SMatthias Ringwald 214225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Variables STM32F4 DISCOVERY AUDIO Private Variables 215225f4ba4SMatthias Ringwald * @{ 216225f4ba4SMatthias Ringwald */ 217225f4ba4SMatthias Ringwald /*##### PLAY #####*/ 218225f4ba4SMatthias Ringwald static AUDIO_DrvTypeDef *pAudioDrv; 219225f4ba4SMatthias Ringwald I2S_HandleTypeDef hAudioOutI2s; 220225f4ba4SMatthias Ringwald 221225f4ba4SMatthias Ringwald /*### RECORDER ###*/ 222225f4ba4SMatthias Ringwald I2S_HandleTypeDef hAudioInI2s; 223225f4ba4SMatthias Ringwald 224225f4ba4SMatthias Ringwald static PDMFilter_InitStruct Filter[DEFAULT_AUDIO_IN_CHANNEL_NBR]; 225225f4ba4SMatthias Ringwald __IO uint16_t AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; 226225f4ba4SMatthias Ringwald /** 227225f4ba4SMatthias Ringwald * @} 228225f4ba4SMatthias Ringwald */ 229225f4ba4SMatthias Ringwald 230225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F4 DISCOVERY AUDIO Private Function Prototypes 231225f4ba4SMatthias Ringwald * @{ 232225f4ba4SMatthias Ringwald */ 233225f4ba4SMatthias Ringwald static uint8_t I2S2_Init(uint32_t AudioFreq); 234225f4ba4SMatthias Ringwald static uint8_t I2S3_Init(uint32_t AudioFreq); 235225f4ba4SMatthias Ringwald static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr); 236225f4ba4SMatthias Ringwald 237225f4ba4SMatthias Ringwald /** 238225f4ba4SMatthias Ringwald * @} 239225f4ba4SMatthias Ringwald */ 240225f4ba4SMatthias Ringwald 241225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_OUT_Private_Functions STM32F4 DISCOVERY AUDIO OUT Private Functions 242225f4ba4SMatthias Ringwald * @{ 243225f4ba4SMatthias Ringwald */ 244225f4ba4SMatthias Ringwald 245225f4ba4SMatthias Ringwald /** 246225f4ba4SMatthias Ringwald * @brief Configures the audio peripherals. 247225f4ba4SMatthias Ringwald * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, 248225f4ba4SMatthias Ringwald * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO . 249225f4ba4SMatthias Ringwald * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) 250225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency used to play the audio stream. 251225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 252225f4ba4SMatthias Ringwald */ 253225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) 254225f4ba4SMatthias Ringwald { 255225f4ba4SMatthias Ringwald uint8_t ret = AUDIO_OK; 256225f4ba4SMatthias Ringwald 257225f4ba4SMatthias Ringwald /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 258225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL); 259225f4ba4SMatthias Ringwald 260225f4ba4SMatthias Ringwald /* I2S data transfer preparation: 261225f4ba4SMatthias Ringwald Prepare the Media to be used for the audio transfer from memory to I2S peripheral */ 262225f4ba4SMatthias Ringwald hAudioOutI2s.Instance = I2S3; 263225f4ba4SMatthias Ringwald if(HAL_I2S_GetState(&hAudioOutI2s) == HAL_I2S_STATE_RESET) 264225f4ba4SMatthias Ringwald { 265225f4ba4SMatthias Ringwald /* Init the I2S MSP: this __weak function can be redefined by the application*/ 266225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_MspInit(&hAudioOutI2s, NULL); 267225f4ba4SMatthias Ringwald } 268225f4ba4SMatthias Ringwald 269225f4ba4SMatthias Ringwald /* I2S data transfer preparation: 270225f4ba4SMatthias Ringwald Prepare the Media to be used for the audio transfer from memory to I2S peripheral */ 271225f4ba4SMatthias Ringwald /* Configure the I2S peripheral */ 272225f4ba4SMatthias Ringwald if(I2S3_Init(AudioFreq) != AUDIO_OK) 273225f4ba4SMatthias Ringwald { 274225f4ba4SMatthias Ringwald ret = AUDIO_ERROR; 275225f4ba4SMatthias Ringwald } 276225f4ba4SMatthias Ringwald 277225f4ba4SMatthias Ringwald if(ret == AUDIO_OK) 278225f4ba4SMatthias Ringwald { 279225f4ba4SMatthias Ringwald /* Retieve audio codec identifier */ 280225f4ba4SMatthias Ringwald if(((cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS)) & CS43L22_ID_MASK) == CS43L22_ID) 281225f4ba4SMatthias Ringwald { 282225f4ba4SMatthias Ringwald /* Initialize the audio driver structure */ 283225f4ba4SMatthias Ringwald pAudioDrv = &cs43l22_drv; 284225f4ba4SMatthias Ringwald } 285225f4ba4SMatthias Ringwald else 286225f4ba4SMatthias Ringwald { 287225f4ba4SMatthias Ringwald ret = AUDIO_ERROR; 288225f4ba4SMatthias Ringwald } 289225f4ba4SMatthias Ringwald } 290225f4ba4SMatthias Ringwald 291225f4ba4SMatthias Ringwald if(ret == AUDIO_OK) 292225f4ba4SMatthias Ringwald { 293225f4ba4SMatthias Ringwald pAudioDrv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); 294225f4ba4SMatthias Ringwald } 295225f4ba4SMatthias Ringwald 296225f4ba4SMatthias Ringwald return ret; 297225f4ba4SMatthias Ringwald } 298225f4ba4SMatthias Ringwald 299225f4ba4SMatthias Ringwald /** 300225f4ba4SMatthias Ringwald * @brief Starts playing audio stream from a data buffer for a determined size. 301225f4ba4SMatthias Ringwald * @param pBuffer: Pointer to the buffer 302225f4ba4SMatthias Ringwald * @param Size: Number of audio data BYTES. 303225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 304225f4ba4SMatthias Ringwald */ 305225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) 306225f4ba4SMatthias Ringwald { 307225f4ba4SMatthias Ringwald /* Call the audio Codec Play function */ 308225f4ba4SMatthias Ringwald if(pAudioDrv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) 309225f4ba4SMatthias Ringwald { 310225f4ba4SMatthias Ringwald return AUDIO_ERROR; 311225f4ba4SMatthias Ringwald } 312225f4ba4SMatthias Ringwald else 313225f4ba4SMatthias Ringwald { 314*2d8556b2SDirk Helbig bsp_audio_out_frequency = bsp_audio_out_actual_frequency; 315225f4ba4SMatthias Ringwald /* Update the Media layer and enable it for play */ 316225f4ba4SMatthias Ringwald HAL_I2S_Transmit_DMA(&hAudioOutI2s, pBuffer, DMA_MAX(Size/AUDIODATA_SIZE)); 317225f4ba4SMatthias Ringwald 318225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 319225f4ba4SMatthias Ringwald return AUDIO_OK; 320225f4ba4SMatthias Ringwald } 321225f4ba4SMatthias Ringwald } 322225f4ba4SMatthias Ringwald 323225f4ba4SMatthias Ringwald /** 324225f4ba4SMatthias Ringwald * @brief Sends n-Bytes on the I2S interface. 325225f4ba4SMatthias Ringwald * @param pData: Pointer to data address 326225f4ba4SMatthias Ringwald * @param Size: Number of data to be written 327225f4ba4SMatthias Ringwald */ 328225f4ba4SMatthias Ringwald void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) 329225f4ba4SMatthias Ringwald { 330225f4ba4SMatthias Ringwald HAL_I2S_Transmit_DMA(&hAudioOutI2s, pData, Size); 331225f4ba4SMatthias Ringwald } 332225f4ba4SMatthias Ringwald 333225f4ba4SMatthias Ringwald /** 334225f4ba4SMatthias Ringwald * @brief Pauses the audio file stream. In case of using DMA, the DMA Pause 335225f4ba4SMatthias Ringwald * feature is used. 336225f4ba4SMatthias Ringwald * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only the 337225f4ba4SMatthias Ringwald * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 338225f4ba4SMatthias Ringwald * function for resume could lead to unexpected behavior). 339225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 340225f4ba4SMatthias Ringwald */ 341225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_Pause(void) 342225f4ba4SMatthias Ringwald { 343225f4ba4SMatthias Ringwald /* Call the Audio Codec Pause/Resume function */ 344225f4ba4SMatthias Ringwald if(pAudioDrv->Pause(AUDIO_I2C_ADDRESS) != 0) 345225f4ba4SMatthias Ringwald { 346225f4ba4SMatthias Ringwald return AUDIO_ERROR; 347225f4ba4SMatthias Ringwald } 348225f4ba4SMatthias Ringwald else 349225f4ba4SMatthias Ringwald { 350225f4ba4SMatthias Ringwald /* Call the Media layer pause function */ 351225f4ba4SMatthias Ringwald HAL_I2S_DMAPause(&hAudioOutI2s); 352225f4ba4SMatthias Ringwald 353225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 354225f4ba4SMatthias Ringwald return AUDIO_OK; 355225f4ba4SMatthias Ringwald } 356225f4ba4SMatthias Ringwald } 357225f4ba4SMatthias Ringwald 358225f4ba4SMatthias Ringwald /** 359225f4ba4SMatthias Ringwald * @brief Resumes the audio file streaming. 360225f4ba4SMatthias Ringwald * WARNING: When calling BSP_AUDIO_OUT_Pause() function for pause, only 361225f4ba4SMatthias Ringwald * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() 362225f4ba4SMatthias Ringwald * function for resume could lead to unexpected behavior). 363225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 364225f4ba4SMatthias Ringwald */ 365225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_Resume(void) 366225f4ba4SMatthias Ringwald { 367225f4ba4SMatthias Ringwald /* Call the Audio Codec Pause/Resume function */ 368225f4ba4SMatthias Ringwald if(pAudioDrv->Resume(AUDIO_I2C_ADDRESS) != 0) 369225f4ba4SMatthias Ringwald { 370225f4ba4SMatthias Ringwald return AUDIO_ERROR; 371225f4ba4SMatthias Ringwald } 372225f4ba4SMatthias Ringwald else 373225f4ba4SMatthias Ringwald { 374225f4ba4SMatthias Ringwald /* Call the Media layer resume function */ 375225f4ba4SMatthias Ringwald HAL_I2S_DMAResume(&hAudioOutI2s); 376225f4ba4SMatthias Ringwald 377225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 378225f4ba4SMatthias Ringwald return AUDIO_OK; 379225f4ba4SMatthias Ringwald } 380225f4ba4SMatthias Ringwald } 381225f4ba4SMatthias Ringwald 382225f4ba4SMatthias Ringwald /** 383225f4ba4SMatthias Ringwald * @brief Stops audio playing and Power down the Audio Codec. 384225f4ba4SMatthias Ringwald * @param Option: could be one of the following parameters 385225f4ba4SMatthias Ringwald * - CODEC_PDWN_HW: completely shut down the codec (physically). 386225f4ba4SMatthias Ringwald * Then need to reconfigure the Codec after power on. 387225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 388225f4ba4SMatthias Ringwald */ 389225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) 390225f4ba4SMatthias Ringwald { 391225f4ba4SMatthias Ringwald /* Call DMA Stop to disable DMA stream before stopping codec */ 392225f4ba4SMatthias Ringwald HAL_I2S_DMAStop(&hAudioOutI2s); 393225f4ba4SMatthias Ringwald 394*2d8556b2SDirk Helbig bsp_audio_out_frequency = 0; 395*2d8556b2SDirk Helbig 396225f4ba4SMatthias Ringwald /* Call Audio Codec Stop function */ 397225f4ba4SMatthias Ringwald if(pAudioDrv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) 398225f4ba4SMatthias Ringwald { 399225f4ba4SMatthias Ringwald return AUDIO_ERROR; 400225f4ba4SMatthias Ringwald } 401225f4ba4SMatthias Ringwald else 402225f4ba4SMatthias Ringwald { 403225f4ba4SMatthias Ringwald if(Option == CODEC_PDWN_HW) 404225f4ba4SMatthias Ringwald { 405225f4ba4SMatthias Ringwald /* Wait at least 1ms */ 406225f4ba4SMatthias Ringwald HAL_Delay(1); 407225f4ba4SMatthias Ringwald 408225f4ba4SMatthias Ringwald /* Reset the pin */ 409225f4ba4SMatthias Ringwald HAL_GPIO_WritePin(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, GPIO_PIN_RESET); 410225f4ba4SMatthias Ringwald } 411225f4ba4SMatthias Ringwald 412225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 413225f4ba4SMatthias Ringwald return AUDIO_OK; 414225f4ba4SMatthias Ringwald } 415225f4ba4SMatthias Ringwald } 416225f4ba4SMatthias Ringwald 417225f4ba4SMatthias Ringwald /** 418225f4ba4SMatthias Ringwald * @brief Controls the current audio volume level. 419225f4ba4SMatthias Ringwald * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for 420225f4ba4SMatthias Ringwald * Mute and 100 for Max volume level). 421225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 422225f4ba4SMatthias Ringwald */ 423225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) 424225f4ba4SMatthias Ringwald { 425225f4ba4SMatthias Ringwald /* Call the codec volume control function with converted volume value */ 426225f4ba4SMatthias Ringwald if(pAudioDrv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) 427225f4ba4SMatthias Ringwald { 428225f4ba4SMatthias Ringwald return AUDIO_ERROR; 429225f4ba4SMatthias Ringwald } 430225f4ba4SMatthias Ringwald else 431225f4ba4SMatthias Ringwald { 432225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 433225f4ba4SMatthias Ringwald return AUDIO_OK; 434225f4ba4SMatthias Ringwald } 435225f4ba4SMatthias Ringwald } 436225f4ba4SMatthias Ringwald 437225f4ba4SMatthias Ringwald /** 438225f4ba4SMatthias Ringwald * @brief Enables or disables the MUTE mode by software 439225f4ba4SMatthias Ringwald * @param Cmd: could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to 440225f4ba4SMatthias Ringwald * unmute the codec and restore previous volume level. 441225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 442225f4ba4SMatthias Ringwald */ 443225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) 444225f4ba4SMatthias Ringwald { 445225f4ba4SMatthias Ringwald /* Call the Codec Mute function */ 446225f4ba4SMatthias Ringwald if(pAudioDrv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) 447225f4ba4SMatthias Ringwald { 448225f4ba4SMatthias Ringwald return AUDIO_ERROR; 449225f4ba4SMatthias Ringwald } 450225f4ba4SMatthias Ringwald else 451225f4ba4SMatthias Ringwald { 452225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 453225f4ba4SMatthias Ringwald return AUDIO_OK; 454225f4ba4SMatthias Ringwald } 455225f4ba4SMatthias Ringwald } 456225f4ba4SMatthias Ringwald 457225f4ba4SMatthias Ringwald /** 458225f4ba4SMatthias Ringwald * @brief Switch dynamically (while audio file is played) the output target 459225f4ba4SMatthias Ringwald * (speaker or headphone). 460225f4ba4SMatthias Ringwald * @note This function modifies a global variable of the audio codec driver: OutputDev. 461225f4ba4SMatthias Ringwald * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER, 462225f4ba4SMatthias Ringwald * OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO 463225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 464225f4ba4SMatthias Ringwald */ 465225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) 466225f4ba4SMatthias Ringwald { 467225f4ba4SMatthias Ringwald /* Call the Codec output Device function */ 468225f4ba4SMatthias Ringwald if(pAudioDrv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) 469225f4ba4SMatthias Ringwald { 470225f4ba4SMatthias Ringwald return AUDIO_ERROR; 471225f4ba4SMatthias Ringwald } 472225f4ba4SMatthias Ringwald else 473225f4ba4SMatthias Ringwald { 474225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 475225f4ba4SMatthias Ringwald return AUDIO_OK; 476225f4ba4SMatthias Ringwald } 477225f4ba4SMatthias Ringwald } 478225f4ba4SMatthias Ringwald 479225f4ba4SMatthias Ringwald /** 480225f4ba4SMatthias Ringwald * @brief Update the audio frequency. 481225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency used to play the audio stream. 482225f4ba4SMatthias Ringwald * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the 483225f4ba4SMatthias Ringwald * audio frequency. 484225f4ba4SMatthias Ringwald */ 485225f4ba4SMatthias Ringwald void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) 486225f4ba4SMatthias Ringwald { 487225f4ba4SMatthias Ringwald /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ 488225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_ClockConfig(&hAudioOutI2s, AudioFreq, NULL); 489225f4ba4SMatthias Ringwald 490225f4ba4SMatthias Ringwald /* Update the I2S audio frequency configuration */ 491225f4ba4SMatthias Ringwald I2S3_Init(AudioFreq); 492225f4ba4SMatthias Ringwald } 493225f4ba4SMatthias Ringwald 494225f4ba4SMatthias Ringwald /** 495225f4ba4SMatthias Ringwald * @brief Tx Transfer completed callbacks. 496225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 497225f4ba4SMatthias Ringwald */ 498225f4ba4SMatthias Ringwald void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) 499225f4ba4SMatthias Ringwald { 500225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S3) 501225f4ba4SMatthias Ringwald { 502225f4ba4SMatthias Ringwald /* Call the user function which will manage directly transfer complete */ 503225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_TransferComplete_CallBack(); 504225f4ba4SMatthias Ringwald } 505225f4ba4SMatthias Ringwald } 506225f4ba4SMatthias Ringwald 507225f4ba4SMatthias Ringwald /** 508225f4ba4SMatthias Ringwald * @brief Tx Half Transfer completed callbacks. 509225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 510225f4ba4SMatthias Ringwald */ 511225f4ba4SMatthias Ringwald void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) 512225f4ba4SMatthias Ringwald { 513225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S3) 514225f4ba4SMatthias Ringwald { 515225f4ba4SMatthias Ringwald /* Manage the remaining file size and new address offset: This function should 516225f4ba4SMatthias Ringwald be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */ 517225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_HalfTransfer_CallBack(); 518225f4ba4SMatthias Ringwald } 519225f4ba4SMatthias Ringwald } 520225f4ba4SMatthias Ringwald 521225f4ba4SMatthias Ringwald /** 522225f4ba4SMatthias Ringwald * @brief Clock Config. 523225f4ba4SMatthias Ringwald * @param hi2s: might be required to set audio peripheral predivider if any. 524225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency used to play the audio stream. 525225f4ba4SMatthias Ringwald * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() 526225f4ba4SMatthias Ringwald * Being __weak it can be overwritten by the application 527225f4ba4SMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 528225f4ba4SMatthias Ringwald */ 529225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_OUT_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params) 530225f4ba4SMatthias Ringwald { 531225f4ba4SMatthias Ringwald RCC_PeriphCLKInitTypeDef rccclkinit; 532225f4ba4SMatthias Ringwald 533*2d8556b2SDirk Helbig i2s_pll_entry_t const *pll_params = i2s_find_pll_params( AudioFreq ); 534*2d8556b2SDirk Helbig 535*2d8556b2SDirk Helbig bsp_audio_out_actual_frequency = pll_params->actual; 536*2d8556b2SDirk Helbig 537225f4ba4SMatthias Ringwald /* Enable PLLI2S clock */ 538225f4ba4SMatthias Ringwald HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit); 539*2d8556b2SDirk Helbig /* PLLI2S_VCO Input = HSE_VALUE/PLL_M */ 540225f4ba4SMatthias Ringwald 541225f4ba4SMatthias Ringwald /* I2S clock config 542225f4ba4SMatthias Ringwald PLLI2S_VCO = f(VCO clock) = f(PLLI2S clock input) � (PLLI2SN/PLLM) 543225f4ba4SMatthias Ringwald I2SCLK = f(PLLI2S clock output) = f(VCO clock) / PLLI2SR */ 544225f4ba4SMatthias Ringwald rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S; 545*2d8556b2SDirk Helbig rccclkinit.PLLI2S.PLLI2SN = pll_params->n; 546*2d8556b2SDirk Helbig rccclkinit.PLLI2S.PLLI2SR = pll_params->r; 547225f4ba4SMatthias Ringwald HAL_RCCEx_PeriphCLKConfig(&rccclkinit); 548225f4ba4SMatthias Ringwald } 549225f4ba4SMatthias Ringwald 550225f4ba4SMatthias Ringwald /** 551225f4ba4SMatthias Ringwald * @brief AUDIO OUT I2S MSP Init. 552225f4ba4SMatthias Ringwald * @param hi2s: might be required to set audio peripheral predivider if any. 553225f4ba4SMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 554225f4ba4SMatthias Ringwald */ 555225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_OUT_MspInit(I2S_HandleTypeDef *hi2s, void *Params) 556225f4ba4SMatthias Ringwald { 557225f4ba4SMatthias Ringwald static DMA_HandleTypeDef hdma_i2sTx; 558225f4ba4SMatthias Ringwald GPIO_InitTypeDef GPIO_InitStruct; 559225f4ba4SMatthias Ringwald 560225f4ba4SMatthias Ringwald /* Enable I2S3 clock */ 561225f4ba4SMatthias Ringwald I2S3_CLK_ENABLE(); 562225f4ba4SMatthias Ringwald 563225f4ba4SMatthias Ringwald /*** Configure the GPIOs ***/ 564225f4ba4SMatthias Ringwald /* Enable I2S GPIO clocks */ 565225f4ba4SMatthias Ringwald I2S3_SCK_SD_CLK_ENABLE(); 566225f4ba4SMatthias Ringwald I2S3_WS_CLK_ENABLE(); 567225f4ba4SMatthias Ringwald 568225f4ba4SMatthias Ringwald /* I2S3 pins configuration: WS, SCK and SD pins ----------------------------*/ 569225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S3_SCK_PIN | I2S3_SD_PIN; 570225f4ba4SMatthias Ringwald GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 571225f4ba4SMatthias Ringwald GPIO_InitStruct.Pull = GPIO_NOPULL; 572225f4ba4SMatthias Ringwald GPIO_InitStruct.Speed = GPIO_SPEED_FAST; 573225f4ba4SMatthias Ringwald GPIO_InitStruct.Alternate = I2S3_SCK_SD_WS_AF; 574225f4ba4SMatthias Ringwald HAL_GPIO_Init(I2S3_SCK_SD_GPIO_PORT, &GPIO_InitStruct); 575225f4ba4SMatthias Ringwald 576225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S3_WS_PIN ; 577225f4ba4SMatthias Ringwald HAL_GPIO_Init(I2S3_WS_GPIO_PORT, &GPIO_InitStruct); 578225f4ba4SMatthias Ringwald 579225f4ba4SMatthias Ringwald /* I2S3 pins configuration: MCK pin */ 580225f4ba4SMatthias Ringwald I2S3_MCK_CLK_ENABLE(); 581225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S3_MCK_PIN; 582225f4ba4SMatthias Ringwald HAL_GPIO_Init(I2S3_MCK_GPIO_PORT, &GPIO_InitStruct); 583225f4ba4SMatthias Ringwald 584225f4ba4SMatthias Ringwald /* Enable the I2S DMA clock */ 585225f4ba4SMatthias Ringwald I2S3_DMAx_CLK_ENABLE(); 586225f4ba4SMatthias Ringwald 587225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S3) 588225f4ba4SMatthias Ringwald { 589225f4ba4SMatthias Ringwald /* Configure the hdma_i2sTx handle parameters */ 590225f4ba4SMatthias Ringwald hdma_i2sTx.Init.Channel = I2S3_DMAx_CHANNEL; 591225f4ba4SMatthias Ringwald hdma_i2sTx.Init.Direction = DMA_MEMORY_TO_PERIPH; 592225f4ba4SMatthias Ringwald hdma_i2sTx.Init.PeriphInc = DMA_PINC_DISABLE; 593225f4ba4SMatthias Ringwald hdma_i2sTx.Init.MemInc = DMA_MINC_ENABLE; 594225f4ba4SMatthias Ringwald hdma_i2sTx.Init.PeriphDataAlignment = I2S3_DMAx_PERIPH_DATA_SIZE; 595225f4ba4SMatthias Ringwald hdma_i2sTx.Init.MemDataAlignment = I2S3_DMAx_MEM_DATA_SIZE; 596225f4ba4SMatthias Ringwald hdma_i2sTx.Init.Mode = DMA_NORMAL; 597225f4ba4SMatthias Ringwald 598225f4ba4SMatthias Ringwald // BK: use circular DMA for hal_audio.h 599225f4ba4SMatthias Ringwald #ifdef HAVE_HAL_AUDIO 600225f4ba4SMatthias Ringwald hdma_i2sTx.Init.Mode = DMA_CIRCULAR; 601225f4ba4SMatthias Ringwald #endif 602225f4ba4SMatthias Ringwald // BK: use circular DMA (end) 603225f4ba4SMatthias Ringwald 604225f4ba4SMatthias Ringwald hdma_i2sTx.Init.Priority = DMA_PRIORITY_HIGH; 605225f4ba4SMatthias Ringwald hdma_i2sTx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; 606225f4ba4SMatthias Ringwald hdma_i2sTx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; 607225f4ba4SMatthias Ringwald hdma_i2sTx.Init.MemBurst = DMA_MBURST_SINGLE; 608225f4ba4SMatthias Ringwald hdma_i2sTx.Init.PeriphBurst = DMA_PBURST_SINGLE; 609225f4ba4SMatthias Ringwald 610225f4ba4SMatthias Ringwald hdma_i2sTx.Instance = I2S3_DMAx_STREAM; 611225f4ba4SMatthias Ringwald 612225f4ba4SMatthias Ringwald /* Associate the DMA handle */ 613225f4ba4SMatthias Ringwald __HAL_LINKDMA(hi2s, hdmatx, hdma_i2sTx); 614225f4ba4SMatthias Ringwald 615225f4ba4SMatthias Ringwald /* Deinitialize the Stream for new transfer */ 616225f4ba4SMatthias Ringwald HAL_DMA_DeInit(&hdma_i2sTx); 617225f4ba4SMatthias Ringwald 618225f4ba4SMatthias Ringwald /* Configure the DMA Stream */ 619225f4ba4SMatthias Ringwald HAL_DMA_Init(&hdma_i2sTx); 620225f4ba4SMatthias Ringwald } 621225f4ba4SMatthias Ringwald 622225f4ba4SMatthias Ringwald /* I2S DMA IRQ Channel configuration */ 623225f4ba4SMatthias Ringwald HAL_NVIC_SetPriority(I2S3_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); 624225f4ba4SMatthias Ringwald HAL_NVIC_EnableIRQ(I2S3_DMAx_IRQ); 625225f4ba4SMatthias Ringwald } 626225f4ba4SMatthias Ringwald 627225f4ba4SMatthias Ringwald /** 628225f4ba4SMatthias Ringwald * @brief De-Initializes BSP_AUDIO_OUT MSP. 629225f4ba4SMatthias Ringwald * @param hi2s: might be required to set audio peripheral predivider if any. 630225f4ba4SMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 631225f4ba4SMatthias Ringwald */ 632225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_OUT_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params) 633225f4ba4SMatthias Ringwald { 634225f4ba4SMatthias Ringwald GPIO_InitTypeDef GPIO_InitStruct; 635225f4ba4SMatthias Ringwald 636225f4ba4SMatthias Ringwald /* I2S DMA IRQ Channel deactivation */ 637225f4ba4SMatthias Ringwald HAL_NVIC_DisableIRQ(I2S3_DMAx_IRQ); 638225f4ba4SMatthias Ringwald 639225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S3) 640225f4ba4SMatthias Ringwald { 641225f4ba4SMatthias Ringwald /* Deinitialize the Stream for new transfer */ 642225f4ba4SMatthias Ringwald HAL_DMA_DeInit(hi2s->hdmatx); 643225f4ba4SMatthias Ringwald } 644225f4ba4SMatthias Ringwald 645225f4ba4SMatthias Ringwald /* Disable I2S block */ 646225f4ba4SMatthias Ringwald __HAL_I2S_DISABLE(hi2s); 647225f4ba4SMatthias Ringwald 648225f4ba4SMatthias Ringwald /* CODEC_I2S pins configuration: SCK and SD pins */ 649225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S3_SCK_PIN | I2S3_SD_PIN; 650225f4ba4SMatthias Ringwald HAL_GPIO_DeInit(I2S3_SCK_SD_GPIO_PORT, GPIO_InitStruct.Pin); 651225f4ba4SMatthias Ringwald 652225f4ba4SMatthias Ringwald /* CODEC_I2S pins configuration: WS pin */ 653225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S3_WS_PIN; 654225f4ba4SMatthias Ringwald HAL_GPIO_DeInit(I2S3_WS_GPIO_PORT, GPIO_InitStruct.Pin); 655225f4ba4SMatthias Ringwald 656225f4ba4SMatthias Ringwald /* CODEC_I2S pins configuration: MCK pin */ 657225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S3_MCK_PIN; 658225f4ba4SMatthias Ringwald HAL_GPIO_DeInit(I2S3_MCK_GPIO_PORT, GPIO_InitStruct.Pin); 659225f4ba4SMatthias Ringwald 660225f4ba4SMatthias Ringwald /* Disable I2S clock */ 661225f4ba4SMatthias Ringwald I2S3_CLK_DISABLE(); 662225f4ba4SMatthias Ringwald 663225f4ba4SMatthias Ringwald /* GPIO pins clock and DMA clock can be shut down in the applic 664225f4ba4SMatthias Ringwald by surcgarging this __weak function */ 665225f4ba4SMatthias Ringwald } 666225f4ba4SMatthias Ringwald 667225f4ba4SMatthias Ringwald /** 668225f4ba4SMatthias Ringwald * @brief Manages the DMA full Transfer complete event. 669225f4ba4SMatthias Ringwald */ 670225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) 671225f4ba4SMatthias Ringwald { 672225f4ba4SMatthias Ringwald } 673225f4ba4SMatthias Ringwald 674225f4ba4SMatthias Ringwald /** 675225f4ba4SMatthias Ringwald * @brief Manages the DMA Half Transfer complete event. 676225f4ba4SMatthias Ringwald */ 677225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) 678225f4ba4SMatthias Ringwald { 679225f4ba4SMatthias Ringwald } 680225f4ba4SMatthias Ringwald 681225f4ba4SMatthias Ringwald /** 682225f4ba4SMatthias Ringwald * @brief Manages the DMA FIFO error event. 683225f4ba4SMatthias Ringwald */ 684225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_OUT_Error_CallBack(void) 685225f4ba4SMatthias Ringwald { 686225f4ba4SMatthias Ringwald } 687225f4ba4SMatthias Ringwald 688225f4ba4SMatthias Ringwald /******************************************************************************* 689225f4ba4SMatthias Ringwald Static Functions 690225f4ba4SMatthias Ringwald *******************************************************************************/ 691225f4ba4SMatthias Ringwald 692225f4ba4SMatthias Ringwald /** 693225f4ba4SMatthias Ringwald * @brief Initializes the Audio Codec audio interface (I2S). 694225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 695225f4ba4SMatthias Ringwald */ 696225f4ba4SMatthias Ringwald static uint8_t I2S3_Init(uint32_t AudioFreq) 697225f4ba4SMatthias Ringwald { 698225f4ba4SMatthias Ringwald /* Initialize the hAudioOutI2s Instance parameter */ 699225f4ba4SMatthias Ringwald hAudioOutI2s.Instance = I2S3; 700225f4ba4SMatthias Ringwald 701225f4ba4SMatthias Ringwald /* Disable I2S block */ 702225f4ba4SMatthias Ringwald __HAL_I2S_DISABLE(&hAudioOutI2s); 703225f4ba4SMatthias Ringwald 704225f4ba4SMatthias Ringwald /* I2S3 peripheral configuration */ 705225f4ba4SMatthias Ringwald hAudioOutI2s.Init.AudioFreq = AudioFreq; 706225f4ba4SMatthias Ringwald hAudioOutI2s.Init.ClockSource = I2S_CLOCK_PLL; 707225f4ba4SMatthias Ringwald hAudioOutI2s.Init.CPOL = I2S_CPOL_LOW; 708225f4ba4SMatthias Ringwald hAudioOutI2s.Init.DataFormat = I2S_DATAFORMAT_16B; 709225f4ba4SMatthias Ringwald hAudioOutI2s.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; 710225f4ba4SMatthias Ringwald hAudioOutI2s.Init.Mode = I2S_MODE_MASTER_TX; 711225f4ba4SMatthias Ringwald hAudioOutI2s.Init.Standard = I2S_STANDARD; 712225f4ba4SMatthias Ringwald /* Initialize the I2S peripheral with the structure above */ 713225f4ba4SMatthias Ringwald if(HAL_I2S_Init(&hAudioOutI2s) != HAL_OK) 714225f4ba4SMatthias Ringwald { 715225f4ba4SMatthias Ringwald return AUDIO_ERROR; 716225f4ba4SMatthias Ringwald } 717225f4ba4SMatthias Ringwald else 718225f4ba4SMatthias Ringwald { 719225f4ba4SMatthias Ringwald return AUDIO_OK; 720225f4ba4SMatthias Ringwald } 721225f4ba4SMatthias Ringwald } 722225f4ba4SMatthias Ringwald 723225f4ba4SMatthias Ringwald /** 724225f4ba4SMatthias Ringwald * @} 725225f4ba4SMatthias Ringwald */ 726225f4ba4SMatthias Ringwald 727225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_Private_Functions STM32F4 DISCOVERY AUDIO IN Private Functions 728225f4ba4SMatthias Ringwald * @{ 729225f4ba4SMatthias Ringwald */ 730225f4ba4SMatthias Ringwald 731225f4ba4SMatthias Ringwald /** 732225f4ba4SMatthias Ringwald * @brief Initializes wave recording. 733225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 734225f4ba4SMatthias Ringwald * @param BitRes: Audio frequency to be configured for the I2S peripheral. 735225f4ba4SMatthias Ringwald * @param ChnlNbr: Audio frequency to be configured for the I2S peripheral. 736225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 737225f4ba4SMatthias Ringwald */ 738225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) 739225f4ba4SMatthias Ringwald { 740225f4ba4SMatthias Ringwald 741225f4ba4SMatthias Ringwald #if 0 742225f4ba4SMatthias Ringwald // BK: only do PLL clock configuration in sink 743225f4ba4SMatthias Ringwald /* Configure PLL clock */ 744225f4ba4SMatthias Ringwald BSP_AUDIO_IN_ClockConfig(&hAudioInI2s, AudioFreq, NULL); 745225f4ba4SMatthias Ringwald #endif 746225f4ba4SMatthias Ringwald 747225f4ba4SMatthias Ringwald /* Configure the PDM library */ 748225f4ba4SMatthias Ringwald PDMDecoder_Init(AudioFreq, ChnlNbr); 749225f4ba4SMatthias Ringwald 750225f4ba4SMatthias Ringwald /* Configure the I2S peripheral */ 751225f4ba4SMatthias Ringwald hAudioInI2s.Instance = I2S2; 752225f4ba4SMatthias Ringwald if(HAL_I2S_GetState(&hAudioInI2s) == HAL_I2S_STATE_RESET) 753225f4ba4SMatthias Ringwald { 754225f4ba4SMatthias Ringwald /* Initialize the I2S Msp: this __weak function can be rewritten by the application */ 755225f4ba4SMatthias Ringwald BSP_AUDIO_IN_MspInit(&hAudioInI2s, NULL); 756225f4ba4SMatthias Ringwald } 757225f4ba4SMatthias Ringwald 758225f4ba4SMatthias Ringwald /* Configure the I2S2 */ 759225f4ba4SMatthias Ringwald I2S2_Init(AudioFreq); 760225f4ba4SMatthias Ringwald 761225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 762225f4ba4SMatthias Ringwald return AUDIO_OK; 763225f4ba4SMatthias Ringwald } 764225f4ba4SMatthias Ringwald 765225f4ba4SMatthias Ringwald /** 766225f4ba4SMatthias Ringwald * @brief Starts audio recording. 767225f4ba4SMatthias Ringwald * @param pbuf: Main buffer pointer for the recorded data storing 768225f4ba4SMatthias Ringwald * @param size: Current size of the recorded buffer 769225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 770225f4ba4SMatthias Ringwald */ 771225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) 772225f4ba4SMatthias Ringwald { 773225f4ba4SMatthias Ringwald uint32_t ret = AUDIO_ERROR; 774225f4ba4SMatthias Ringwald 775225f4ba4SMatthias Ringwald /* Start the process receive DMA */ 776225f4ba4SMatthias Ringwald HAL_I2S_Receive_DMA(&hAudioInI2s, pbuf, size); 777225f4ba4SMatthias Ringwald 778225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 779225f4ba4SMatthias Ringwald ret = AUDIO_OK; 780225f4ba4SMatthias Ringwald 781225f4ba4SMatthias Ringwald return ret; 782225f4ba4SMatthias Ringwald } 783225f4ba4SMatthias Ringwald 784225f4ba4SMatthias Ringwald /** 785225f4ba4SMatthias Ringwald * @brief Stops audio recording. 786225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 787225f4ba4SMatthias Ringwald */ 788225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_Stop(void) 789225f4ba4SMatthias Ringwald { 790225f4ba4SMatthias Ringwald uint32_t ret = AUDIO_ERROR; 791225f4ba4SMatthias Ringwald 792225f4ba4SMatthias Ringwald /* Call the Media layer pause function */ 793225f4ba4SMatthias Ringwald HAL_I2S_DMAStop(&hAudioInI2s); 794225f4ba4SMatthias Ringwald 795225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 796225f4ba4SMatthias Ringwald ret = AUDIO_OK; 797225f4ba4SMatthias Ringwald 798225f4ba4SMatthias Ringwald return ret; 799225f4ba4SMatthias Ringwald } 800225f4ba4SMatthias Ringwald 801225f4ba4SMatthias Ringwald /** 802225f4ba4SMatthias Ringwald * @brief Pauses the audio file stream. 803225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 804225f4ba4SMatthias Ringwald */ 805225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_Pause(void) 806225f4ba4SMatthias Ringwald { 807225f4ba4SMatthias Ringwald /* Call the Media layer pause function */ 808225f4ba4SMatthias Ringwald HAL_I2S_DMAPause(&hAudioInI2s); 809225f4ba4SMatthias Ringwald 810225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 811225f4ba4SMatthias Ringwald return AUDIO_OK; 812225f4ba4SMatthias Ringwald } 813225f4ba4SMatthias Ringwald 814225f4ba4SMatthias Ringwald /** 815225f4ba4SMatthias Ringwald * @brief Resumes the audio file stream. 816225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 817225f4ba4SMatthias Ringwald */ 818225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_Resume(void) 819225f4ba4SMatthias Ringwald { 820225f4ba4SMatthias Ringwald /* Call the Media layer pause/resume function */ 821225f4ba4SMatthias Ringwald HAL_I2S_DMAResume(&hAudioInI2s); 822225f4ba4SMatthias Ringwald 823225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 824225f4ba4SMatthias Ringwald return AUDIO_OK; 825225f4ba4SMatthias Ringwald } 826225f4ba4SMatthias Ringwald 827225f4ba4SMatthias Ringwald /** 828225f4ba4SMatthias Ringwald * @brief Controls the audio in volume level. 829225f4ba4SMatthias Ringwald * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for 830225f4ba4SMatthias Ringwald * Mute and 100 for Max volume level). 831225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 832225f4ba4SMatthias Ringwald */ 833225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) 834225f4ba4SMatthias Ringwald { 835225f4ba4SMatthias Ringwald /* Set the Global variable AudioInVolume */ 836225f4ba4SMatthias Ringwald AudioInVolume = Volume; 837225f4ba4SMatthias Ringwald 838225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 839225f4ba4SMatthias Ringwald return AUDIO_OK; 840225f4ba4SMatthias Ringwald } 841225f4ba4SMatthias Ringwald 842225f4ba4SMatthias Ringwald /** 843225f4ba4SMatthias Ringwald * @brief Converts audio format from PDM to PCM. 844225f4ba4SMatthias Ringwald * @param PDMBuf: Pointer to data PDM buffer 845225f4ba4SMatthias Ringwald * @param PCMBuf: Pointer to data PCM buffer 846225f4ba4SMatthias Ringwald * @retval AUDIO_OK if correct communication, else wrong communication 847225f4ba4SMatthias Ringwald */ 848225f4ba4SMatthias Ringwald uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t *PDMBuf, uint16_t *PCMBuf) 849225f4ba4SMatthias Ringwald { 850225f4ba4SMatthias Ringwald uint16_t AppPDM[INTERNAL_BUFF_SIZE/2]; 851225f4ba4SMatthias Ringwald uint32_t index = 0; 852225f4ba4SMatthias Ringwald 853225f4ba4SMatthias Ringwald /* PDM Demux */ 854225f4ba4SMatthias Ringwald for(index = 0; index<INTERNAL_BUFF_SIZE/2; index++) 855225f4ba4SMatthias Ringwald { 856225f4ba4SMatthias Ringwald AppPDM[index] = HTONS(PDMBuf[index]); 857225f4ba4SMatthias Ringwald } 858225f4ba4SMatthias Ringwald 859225f4ba4SMatthias Ringwald for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++) 860225f4ba4SMatthias Ringwald { 861225f4ba4SMatthias Ringwald /* PDM to PCM filter */ 862225f4ba4SMatthias Ringwald PDM_Filter_64_LSB((uint8_t*)&AppPDM[index], (uint16_t*)&(PCMBuf[index]), AudioInVolume , (PDMFilter_InitStruct *)&Filter[index]); 863225f4ba4SMatthias Ringwald } 864225f4ba4SMatthias Ringwald #if 0 865225f4ba4SMatthias Ringwald // BK - generate mono output 866225f4ba4SMatthias Ringwald 867225f4ba4SMatthias Ringwald /* Duplicate samples since a single microphone in mounted on STM32F4-Discovery */ 868225f4ba4SMatthias Ringwald for(index = 0; index < PCM_OUT_SIZE; index++) 869225f4ba4SMatthias Ringwald { 870225f4ba4SMatthias Ringwald PCMBuf[(index<<1)+1] = PCMBuf[index<<1]; 871225f4ba4SMatthias Ringwald } 872225f4ba4SMatthias Ringwald #endif 873225f4ba4SMatthias Ringwald 874225f4ba4SMatthias Ringwald /* Return AUDIO_OK when all operations are correctly done */ 875225f4ba4SMatthias Ringwald return AUDIO_OK; 876225f4ba4SMatthias Ringwald } 877225f4ba4SMatthias Ringwald 878225f4ba4SMatthias Ringwald /** 879225f4ba4SMatthias Ringwald * @brief Rx Transfer completed callbacks 880225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 881225f4ba4SMatthias Ringwald */ 882225f4ba4SMatthias Ringwald void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) 883225f4ba4SMatthias Ringwald { 884225f4ba4SMatthias Ringwald /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ 885225f4ba4SMatthias Ringwald BSP_AUDIO_IN_TransferComplete_CallBack(); 886225f4ba4SMatthias Ringwald } 887225f4ba4SMatthias Ringwald 888225f4ba4SMatthias Ringwald /** 889225f4ba4SMatthias Ringwald * @brief Rx Half Transfer completed callbacks. 890225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 891225f4ba4SMatthias Ringwald */ 892225f4ba4SMatthias Ringwald void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) 893225f4ba4SMatthias Ringwald { 894225f4ba4SMatthias Ringwald /* Manage the remaining file size and new address offset: This function 895225f4ba4SMatthias Ringwald should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */ 896225f4ba4SMatthias Ringwald BSP_AUDIO_IN_HalfTransfer_CallBack(); 897225f4ba4SMatthias Ringwald } 898225f4ba4SMatthias Ringwald 899225f4ba4SMatthias Ringwald /** 900*2d8556b2SDirk Helbig * @brief Retrive the audio frequency. 901*2d8556b2SDirk Helbig * @ret AudioFreq: Audio frequency used to play the audio stream. 902*2d8556b2SDirk Helbig * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the 903*2d8556b2SDirk Helbig * audio frequency. 904*2d8556b2SDirk Helbig */ 905*2d8556b2SDirk Helbig uint32_t BSP_AUDIO_OUT_GetFrequency(uint32_t AudioFreq) 906*2d8556b2SDirk Helbig { 907*2d8556b2SDirk Helbig return bsp_audio_out_frequency; 908*2d8556b2SDirk Helbig } 909*2d8556b2SDirk Helbig 910*2d8556b2SDirk Helbig /** 911225f4ba4SMatthias Ringwald * @brief Audio In Clock Config. 912225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 913225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency used to record the audio stream. 914225f4ba4SMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 915225f4ba4SMatthias Ringwald * @note This API is called by BSP_AUDIO_IN_Init() 916225f4ba4SMatthias Ringwald * Being __weak it can be overwritten by the application 917225f4ba4SMatthias Ringwald */ 918225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params) 919225f4ba4SMatthias Ringwald { 920225f4ba4SMatthias Ringwald RCC_PeriphCLKInitTypeDef rccclkinit; 921225f4ba4SMatthias Ringwald 922225f4ba4SMatthias Ringwald /*Enable PLLI2S clock*/ 923225f4ba4SMatthias Ringwald HAL_RCCEx_GetPeriphCLKConfig(&rccclkinit); 924*2d8556b2SDirk Helbig 925*2d8556b2SDirk Helbig i2s_pll_entry_t const *pll_params = i2s_find_pll_params( AudioFreq ); 926*2d8556b2SDirk Helbig 927225f4ba4SMatthias Ringwald rccclkinit.PeriphClockSelection = RCC_PERIPHCLK_I2S; 928*2d8556b2SDirk Helbig rccclkinit.PLLI2S.PLLI2SN = pll_params->n; 929*2d8556b2SDirk Helbig rccclkinit.PLLI2S.PLLI2SR = pll_params->r; 930225f4ba4SMatthias Ringwald HAL_RCCEx_PeriphCLKConfig(&rccclkinit); 931225f4ba4SMatthias Ringwald } 932225f4ba4SMatthias Ringwald 933225f4ba4SMatthias Ringwald /** 934225f4ba4SMatthias Ringwald * @brief BSP AUDIO IN MSP Init. 935225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 936225f4ba4SMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 937225f4ba4SMatthias Ringwald */ 938225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params) 939225f4ba4SMatthias Ringwald { 940225f4ba4SMatthias Ringwald static DMA_HandleTypeDef hdma_i2sRx; 941225f4ba4SMatthias Ringwald GPIO_InitTypeDef GPIO_InitStruct; 942225f4ba4SMatthias Ringwald 943225f4ba4SMatthias Ringwald /* Enable the I2S2 peripheral clock */ 944225f4ba4SMatthias Ringwald I2S2_CLK_ENABLE(); 945225f4ba4SMatthias Ringwald 946225f4ba4SMatthias Ringwald /* Enable I2S GPIO clocks */ 947225f4ba4SMatthias Ringwald I2S2_SCK_GPIO_CLK_ENABLE(); 948225f4ba4SMatthias Ringwald I2S2_MOSI_GPIO_CLK_ENABLE(); 949225f4ba4SMatthias Ringwald 950225f4ba4SMatthias Ringwald /* I2S2 pins configuration: SCK and MOSI pins ------------------------------*/ 951225f4ba4SMatthias Ringwald GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 952225f4ba4SMatthias Ringwald GPIO_InitStruct.Pull = GPIO_NOPULL; 953225f4ba4SMatthias Ringwald GPIO_InitStruct.Speed = GPIO_SPEED_FAST; 954225f4ba4SMatthias Ringwald 955225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S2_SCK_PIN; 956225f4ba4SMatthias Ringwald GPIO_InitStruct.Alternate = I2S2_SCK_AF; 957225f4ba4SMatthias Ringwald HAL_GPIO_Init(I2S2_SCK_GPIO_PORT, &GPIO_InitStruct); 958225f4ba4SMatthias Ringwald 959225f4ba4SMatthias Ringwald GPIO_InitStruct.Pin = I2S2_MOSI_PIN ; 960225f4ba4SMatthias Ringwald GPIO_InitStruct.Alternate = I2S2_MOSI_AF; 961225f4ba4SMatthias Ringwald HAL_GPIO_Init(I2S2_MOSI_GPIO_PORT, &GPIO_InitStruct); 962225f4ba4SMatthias Ringwald 963225f4ba4SMatthias Ringwald /* Enable the DMA clock */ 964225f4ba4SMatthias Ringwald I2S2_DMAx_CLK_ENABLE(); 965225f4ba4SMatthias Ringwald 966225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S2) 967225f4ba4SMatthias Ringwald { 968225f4ba4SMatthias Ringwald /* Configure the hdma_i2sRx handle parameters */ 969225f4ba4SMatthias Ringwald hdma_i2sRx.Init.Channel = I2S2_DMAx_CHANNEL; 970225f4ba4SMatthias Ringwald hdma_i2sRx.Init.Direction = DMA_PERIPH_TO_MEMORY; 971225f4ba4SMatthias Ringwald hdma_i2sRx.Init.PeriphInc = DMA_PINC_DISABLE; 972225f4ba4SMatthias Ringwald hdma_i2sRx.Init.MemInc = DMA_MINC_ENABLE; 973225f4ba4SMatthias Ringwald hdma_i2sRx.Init.PeriphDataAlignment = I2S2_DMAx_PERIPH_DATA_SIZE; 974225f4ba4SMatthias Ringwald hdma_i2sRx.Init.MemDataAlignment = I2S2_DMAx_MEM_DATA_SIZE; 975225f4ba4SMatthias Ringwald hdma_i2sRx.Init.Mode = DMA_CIRCULAR; 976225f4ba4SMatthias Ringwald hdma_i2sRx.Init.Priority = DMA_PRIORITY_HIGH; 977225f4ba4SMatthias Ringwald hdma_i2sRx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 978225f4ba4SMatthias Ringwald hdma_i2sRx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; 979225f4ba4SMatthias Ringwald hdma_i2sRx.Init.MemBurst = DMA_MBURST_SINGLE; 980225f4ba4SMatthias Ringwald hdma_i2sRx.Init.PeriphBurst = DMA_MBURST_SINGLE; 981225f4ba4SMatthias Ringwald 982225f4ba4SMatthias Ringwald hdma_i2sRx.Instance = I2S2_DMAx_STREAM; 983225f4ba4SMatthias Ringwald 984225f4ba4SMatthias Ringwald /* Associate the DMA handle */ 985225f4ba4SMatthias Ringwald __HAL_LINKDMA(hi2s, hdmarx, hdma_i2sRx); 986225f4ba4SMatthias Ringwald 987225f4ba4SMatthias Ringwald /* Deinitialize the Stream for new transfer */ 988225f4ba4SMatthias Ringwald HAL_DMA_DeInit(&hdma_i2sRx); 989225f4ba4SMatthias Ringwald 990225f4ba4SMatthias Ringwald /* Configure the DMA Stream */ 991225f4ba4SMatthias Ringwald HAL_DMA_Init(&hdma_i2sRx); 992225f4ba4SMatthias Ringwald } 993225f4ba4SMatthias Ringwald 994225f4ba4SMatthias Ringwald /* I2S DMA IRQ Channel configuration */ 995225f4ba4SMatthias Ringwald HAL_NVIC_SetPriority(I2S2_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); 996225f4ba4SMatthias Ringwald HAL_NVIC_EnableIRQ(I2S2_DMAx_IRQ); 997225f4ba4SMatthias Ringwald } 998225f4ba4SMatthias Ringwald 999225f4ba4SMatthias Ringwald /** 1000225f4ba4SMatthias Ringwald * @brief DeInitializes BSP_AUDIO_IN MSP. 1001225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 1002225f4ba4SMatthias Ringwald * @param Params : pointer on additional configuration parameters, can be NULL. 1003225f4ba4SMatthias Ringwald */ 1004225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params) 1005225f4ba4SMatthias Ringwald { 1006225f4ba4SMatthias Ringwald GPIO_InitTypeDef gpio_init_structure; 1007225f4ba4SMatthias Ringwald 1008225f4ba4SMatthias Ringwald /* I2S DMA IRQ Channel deactivation */ 1009225f4ba4SMatthias Ringwald HAL_NVIC_DisableIRQ(I2S2_DMAx_IRQ); 1010225f4ba4SMatthias Ringwald 1011225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S2) 1012225f4ba4SMatthias Ringwald { 1013225f4ba4SMatthias Ringwald /* Deinitialize the Stream for new transfer */ 1014225f4ba4SMatthias Ringwald HAL_DMA_DeInit(hi2s->hdmarx); 1015225f4ba4SMatthias Ringwald } 1016225f4ba4SMatthias Ringwald 1017225f4ba4SMatthias Ringwald /* Disable I2S block */ 1018225f4ba4SMatthias Ringwald __HAL_I2S_DISABLE(hi2s); 1019225f4ba4SMatthias Ringwald 1020225f4ba4SMatthias Ringwald /* Disable pins: SCK and SD pins */ 1021225f4ba4SMatthias Ringwald gpio_init_structure.Pin = I2S2_SCK_PIN; 1022225f4ba4SMatthias Ringwald HAL_GPIO_DeInit(I2S2_SCK_GPIO_PORT, gpio_init_structure.Pin); 1023225f4ba4SMatthias Ringwald gpio_init_structure.Pin = I2S2_MOSI_PIN; 1024225f4ba4SMatthias Ringwald HAL_GPIO_DeInit(I2S2_MOSI_GPIO_PORT, gpio_init_structure.Pin); 1025225f4ba4SMatthias Ringwald 1026225f4ba4SMatthias Ringwald /* Disable I2S clock */ 1027225f4ba4SMatthias Ringwald I2S2_CLK_DISABLE(); 1028225f4ba4SMatthias Ringwald 1029225f4ba4SMatthias Ringwald /* GPIO pins clock and DMA clock can be shut down in the applic 1030225f4ba4SMatthias Ringwald by surcgarging this __weak function */ 1031225f4ba4SMatthias Ringwald } 1032225f4ba4SMatthias Ringwald 1033225f4ba4SMatthias Ringwald /** 1034225f4ba4SMatthias Ringwald * @brief User callback when record buffer is filled. 1035225f4ba4SMatthias Ringwald */ 1036225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) 1037225f4ba4SMatthias Ringwald { 1038225f4ba4SMatthias Ringwald /* This function should be implemented by the user application. 1039225f4ba4SMatthias Ringwald It is called into this driver when the current buffer is filled 1040225f4ba4SMatthias Ringwald to prepare the next buffer pointer and its size. */ 1041225f4ba4SMatthias Ringwald } 1042225f4ba4SMatthias Ringwald 1043225f4ba4SMatthias Ringwald /** 1044225f4ba4SMatthias Ringwald * @brief Manages the DMA Half Transfer complete event. 1045225f4ba4SMatthias Ringwald */ 1046225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) 1047225f4ba4SMatthias Ringwald { 1048225f4ba4SMatthias Ringwald /* This function should be implemented by the user application. 1049225f4ba4SMatthias Ringwald It is called into this driver when the current buffer is filled 1050225f4ba4SMatthias Ringwald to prepare the next buffer pointer and its size. */ 1051225f4ba4SMatthias Ringwald } 1052225f4ba4SMatthias Ringwald 1053225f4ba4SMatthias Ringwald /** 1054225f4ba4SMatthias Ringwald * @brief Audio IN Error callback function. 1055225f4ba4SMatthias Ringwald */ 1056225f4ba4SMatthias Ringwald __weak void BSP_AUDIO_IN_Error_Callback(void) 1057225f4ba4SMatthias Ringwald { 1058225f4ba4SMatthias Ringwald /* This function is called when an Interrupt due to transfer error on or peripheral 1059225f4ba4SMatthias Ringwald error occurs. */ 1060225f4ba4SMatthias Ringwald } 1061225f4ba4SMatthias Ringwald 1062225f4ba4SMatthias Ringwald /******************************************************************************* 1063225f4ba4SMatthias Ringwald Static Functions 1064225f4ba4SMatthias Ringwald *******************************************************************************/ 1065225f4ba4SMatthias Ringwald 1066225f4ba4SMatthias Ringwald /** 1067225f4ba4SMatthias Ringwald * @brief Initialize the PDM library. 1068225f4ba4SMatthias Ringwald * @param AudioFreq: Audio sampling frequency 1069225f4ba4SMatthias Ringwald * @param ChnlNbr: Number of audio channels (1: mono; 2: stereo) 1070225f4ba4SMatthias Ringwald */ 1071225f4ba4SMatthias Ringwald static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbr) 1072225f4ba4SMatthias Ringwald { 1073225f4ba4SMatthias Ringwald #if 1 1074225f4ba4SMatthias Ringwald uint32_t i = 0; 1075225f4ba4SMatthias Ringwald 1076225f4ba4SMatthias Ringwald /* Enable CRC peripheral to unlock the PDM library */ 1077225f4ba4SMatthias Ringwald __CRC_CLK_ENABLE(); 1078225f4ba4SMatthias Ringwald 1079225f4ba4SMatthias Ringwald for(i = 0; i < ChnlNbr; i++) 1080225f4ba4SMatthias Ringwald { 1081225f4ba4SMatthias Ringwald /* Filter LP and HP Init */ 1082225f4ba4SMatthias Ringwald Filter[i].LP_HZ = AudioFreq / 2; 1083225f4ba4SMatthias Ringwald Filter[i].HP_HZ = 10; 1084225f4ba4SMatthias Ringwald Filter[i].Fs = AudioFreq; 1085225f4ba4SMatthias Ringwald /* On STM32F4-Discovery a single microphone is mounted, samples are duplicated 1086225f4ba4SMatthias Ringwald to make stereo audio streams */ 1087225f4ba4SMatthias Ringwald // BK - generate mono output 1088225f4ba4SMatthias Ringwald // Filter[i].Out_MicChannels = 2; 1089225f4ba4SMatthias Ringwald Filter[i].Out_MicChannels = 1; 1090225f4ba4SMatthias Ringwald Filter[i].In_MicChannels = ChnlNbr; 1091225f4ba4SMatthias Ringwald PDM_Filter_Init((PDMFilter_InitStruct *)&Filter[i]); 1092225f4ba4SMatthias Ringwald } 1093225f4ba4SMatthias Ringwald #endif 1094225f4ba4SMatthias Ringwald } 1095225f4ba4SMatthias Ringwald 1096225f4ba4SMatthias Ringwald /** 1097225f4ba4SMatthias Ringwald * @brief Initializes the Audio Codec audio interface (I2S) 1098225f4ba4SMatthias Ringwald * @note This function assumes that the I2S input clock (through PLL_R in 1099225f4ba4SMatthias Ringwald * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y) 1100225f4ba4SMatthias Ringwald * is already configured and ready to be used. 1101225f4ba4SMatthias Ringwald * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. 1102225f4ba4SMatthias Ringwald */ 1103225f4ba4SMatthias Ringwald static uint8_t I2S2_Init(uint32_t AudioFreq) 1104225f4ba4SMatthias Ringwald { 1105225f4ba4SMatthias Ringwald /* Initialize the hAudioInI2s Instance parameter */ 1106225f4ba4SMatthias Ringwald hAudioInI2s.Instance = I2S2; 1107225f4ba4SMatthias Ringwald 1108225f4ba4SMatthias Ringwald /* Disable I2S block */ 1109225f4ba4SMatthias Ringwald __HAL_I2S_DISABLE(&hAudioInI2s); 1110225f4ba4SMatthias Ringwald 1111225f4ba4SMatthias Ringwald /* I2S2 peripheral configuration */ 1112225f4ba4SMatthias Ringwald hAudioInI2s.Init.AudioFreq = 2 * AudioFreq; 1113225f4ba4SMatthias Ringwald hAudioInI2s.Init.ClockSource = I2S_CLOCK_PLL; 1114225f4ba4SMatthias Ringwald hAudioInI2s.Init.CPOL = I2S_CPOL_HIGH; 1115225f4ba4SMatthias Ringwald hAudioInI2s.Init.DataFormat = I2S_DATAFORMAT_16B; 1116225f4ba4SMatthias Ringwald hAudioInI2s.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; 1117225f4ba4SMatthias Ringwald hAudioInI2s.Init.Mode = I2S_MODE_MASTER_RX; 1118225f4ba4SMatthias Ringwald hAudioInI2s.Init.Standard = I2S_STANDARD_LSB; 1119225f4ba4SMatthias Ringwald 1120225f4ba4SMatthias Ringwald /* Initialize the I2S peripheral with the structure above */ 1121225f4ba4SMatthias Ringwald if(HAL_I2S_Init(&hAudioInI2s) != HAL_OK) 1122225f4ba4SMatthias Ringwald { 1123225f4ba4SMatthias Ringwald return AUDIO_ERROR; 1124225f4ba4SMatthias Ringwald } 1125225f4ba4SMatthias Ringwald else 1126225f4ba4SMatthias Ringwald { 1127225f4ba4SMatthias Ringwald return AUDIO_OK; 1128225f4ba4SMatthias Ringwald } 1129225f4ba4SMatthias Ringwald } 1130225f4ba4SMatthias Ringwald 1131225f4ba4SMatthias Ringwald /** 1132225f4ba4SMatthias Ringwald * @} 1133225f4ba4SMatthias Ringwald */ 1134225f4ba4SMatthias Ringwald 1135225f4ba4SMatthias Ringwald /** @defgroup STM32F4_DISCOVERY_AUDIO_IN_OUT_Private_Functions STM32F4 DISCOVERY AUDIO IN OUT Private Functions 1136225f4ba4SMatthias Ringwald * @{ 1137225f4ba4SMatthias Ringwald */ 1138225f4ba4SMatthias Ringwald 1139225f4ba4SMatthias Ringwald /** 1140225f4ba4SMatthias Ringwald * @brief I2S error callbacks. 1141225f4ba4SMatthias Ringwald * @param hi2s: I2S handle 1142225f4ba4SMatthias Ringwald */ 1143225f4ba4SMatthias Ringwald void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) 1144225f4ba4SMatthias Ringwald { 1145225f4ba4SMatthias Ringwald /* Manage the error generated on DMA FIFO: This function 1146225f4ba4SMatthias Ringwald should be coded by user (its prototype is already declared in stm32f4_discovery_audio.h) */ 1147225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S3) 1148225f4ba4SMatthias Ringwald { 1149225f4ba4SMatthias Ringwald BSP_AUDIO_OUT_Error_CallBack(); 1150225f4ba4SMatthias Ringwald } 1151225f4ba4SMatthias Ringwald if(hi2s->Instance == I2S2) 1152225f4ba4SMatthias Ringwald { 1153225f4ba4SMatthias Ringwald BSP_AUDIO_IN_Error_Callback(); 1154225f4ba4SMatthias Ringwald } 1155225f4ba4SMatthias Ringwald } 1156225f4ba4SMatthias Ringwald 1157225f4ba4SMatthias Ringwald /** 1158225f4ba4SMatthias Ringwald * @} 1159225f4ba4SMatthias Ringwald */ 1160225f4ba4SMatthias Ringwald 1161225f4ba4SMatthias Ringwald /** 1162225f4ba4SMatthias Ringwald * @} 1163225f4ba4SMatthias Ringwald */ 1164225f4ba4SMatthias Ringwald 1165225f4ba4SMatthias Ringwald /** 1166225f4ba4SMatthias Ringwald * @} 1167225f4ba4SMatthias Ringwald */ 1168225f4ba4SMatthias Ringwald 1169225f4ba4SMatthias Ringwald /** 1170225f4ba4SMatthias Ringwald * @} 1171225f4ba4SMatthias Ringwald */ 1172225f4ba4SMatthias Ringwald 1173225f4ba4SMatthias Ringwald /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 1174