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