xref: /btstack/port/stm32-f4discovery-cc256x/bsp/stm32f4_discovery_audio.c (revision 2d8556b2db643312186f7d316b34bb060fd253a0)
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>&copy; 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