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