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