38
|
1 /**
|
|
2 ******************************************************************************
|
|
3 * @file stm32f4xx_hal_sai.c
|
|
4 * @author MCD Application Team
|
|
5 * @version V1.2.0
|
|
6 * @date 26-December-2014
|
|
7 * @brief SAI HAL module driver.
|
|
8 * This file provides firmware functions to manage the following
|
|
9 * functionalities of the Serial Audio Interface (SAI) peripheral:
|
|
10 * + Initialization/de-initialization functions
|
|
11 * + I/O operation functions
|
|
12 * + Peripheral Control functions
|
|
13 * + Peripheral State functions
|
|
14 *
|
|
15 @verbatim
|
|
16 ==============================================================================
|
|
17 ##### How to use this driver #####
|
|
18 ==============================================================================
|
|
19
|
|
20 [..]
|
|
21 The SAI HAL driver can be used as follows:
|
|
22
|
|
23 (#) Declare a SAI_HandleTypeDef handle structure.
|
|
24 (#) Initialize the SAI low level resources by implementing the HAL_SAI_MspInit() API:
|
|
25 (##) Enable the SAI interface clock.
|
|
26 (##) SAI pins configuration:
|
|
27 (+++) Enable the clock for the SAI GPIOs.
|
|
28 (+++) Configure these SAI pins as alternate function pull-up.
|
|
29 (##) NVIC configuration if you need to use interrupt process (HAL_SAI_Transmit_IT()
|
|
30 and HAL_SAI_Receive_IT() APIs):
|
|
31 (+++) Configure the SAI interrupt priority.
|
|
32 (+++) Enable the NVIC SAI IRQ handle.
|
|
33
|
|
34 (##) DMA Configuration if you need to use DMA process (HAL_SAI_Transmit_DMA()
|
|
35 and HAL_SAI_Receive_DMA() APIs):
|
|
36 (+++) Declare a DMA handle structure for the Tx/Rx stream.
|
|
37 (+++) Enable the DMAx interface clock.
|
|
38 (+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
|
|
39 (+++) Configure the DMA Tx/Rx Stream.
|
|
40 (+++) Associate the initialized DMA handle to the SAI DMA Tx/Rx handle.
|
|
41 (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the
|
|
42 DMA Tx/Rx Stream.
|
|
43
|
|
44 (#) Program the SAI Mode, Standard, Data Format, MCLK Output, Audio frequency and Polarity
|
|
45 using HAL_SAI_Init() function.
|
|
46
|
|
47 -@- The specific SAI interrupts (FIFO request and Overrun underrun interrupt)
|
|
48 will be managed using the macros __SAI_ENABLE_IT() and __SAI_DISABLE_IT()
|
|
49 inside the transmit and receive process.
|
|
50
|
|
51 [..]
|
|
52 (@) Make sure that either:
|
|
53 (+@) I2S PLL is configured or
|
|
54 (+@) SAI PLL is configured or
|
|
55 (+@) External clock source is configured after setting correctly
|
|
56 the define constant EXTERNAL_CLOCK_VALUE in the stm32f4xx_hal_conf.h file.
|
|
57
|
|
58 [..]
|
|
59 (@) In master Tx mode: enabling the audio block immediately generates the bit clock
|
|
60 for the external slaves even if there is no data in the FIFO, However FS signal
|
|
61 generation is conditioned by the presence of data in the FIFO.
|
|
62
|
|
63 [..]
|
|
64 (@) In master Rx mode: enabling the audio block immediately generates the bit clock
|
|
65 and FS signal for the external slaves.
|
|
66
|
|
67 [..]
|
|
68 (@) It is mandatory to respect the following conditions in order to avoid bad SAI behavior:
|
|
69 (+@) First bit Offset <= (SLOT size - Data size)
|
|
70 (+@) Data size <= SLOT size
|
|
71 (+@) Number of SLOT x SLOT size = Frame length
|
|
72 (+@) The number of slots should be even when SAI_FS_CHANNEL_IDENTIFICATION is selected.
|
|
73
|
|
74 [..]
|
|
75 Three operation modes are available within this driver :
|
|
76
|
|
77 *** Polling mode IO operation ***
|
|
78 =================================
|
|
79 [..]
|
|
80 (+) Send an amount of data in blocking mode using HAL_SAI_Transmit()
|
|
81 (+) Receive an amount of data in blocking mode using HAL_SAI_Receive()
|
|
82
|
|
83 *** Interrupt mode IO operation ***
|
|
84 ===================================
|
|
85 [..]
|
|
86 (+) Send an amount of data in non blocking mode using HAL_SAI_Transmit_IT()
|
|
87 (+) At transmission end of transfer HAL_SAI_TxCpltCallback is executed and user can
|
|
88 add his own code by customization of function pointer HAL_SAI_TxCpltCallback
|
|
89 (+) Receive an amount of data in non blocking mode using HAL_SAI_Receive_IT()
|
|
90 (+) At reception end of transfer HAL_SAI_RxCpltCallback is executed and user can
|
|
91 add his own code by customization of function pointer HAL_SAI_RxCpltCallback
|
|
92 (+) In case of transfer Error, HAL_SAI_ErrorCallback() function is executed and user can
|
|
93 add his own code by customization of function pointer HAL_SAI_ErrorCallback
|
|
94
|
|
95 *** DMA mode IO operation ***
|
|
96 ==============================
|
|
97 [..]
|
|
98 (+) Send an amount of data in non blocking mode (DMA) using HAL_SAI_Transmit_DMA()
|
|
99 (+) At transmission end of transfer HAL_SAI_TxCpltCallback is executed and user can
|
|
100 add his own code by customization of function pointer HAL_SAI_TxCpltCallback
|
|
101 (+) Receive an amount of data in non blocking mode (DMA) using HAL_SAI_Receive_DMA()
|
|
102 (+) At reception end of transfer HAL_SAI_RxCpltCallback is executed and user can
|
|
103 add his own code by customization of function pointer HAL_SAI_RxCpltCallback
|
|
104 (+) In case of transfer Error, HAL_SAI_ErrorCallback() function is executed and user can
|
|
105 add his own code by customization of function pointer HAL_SAI_ErrorCallback
|
|
106 (+) Pause the DMA Transfer using HAL_SAI_DMAPause()
|
|
107 (+) Resume the DMA Transfer using HAL_SAI_DMAResume()
|
|
108 (+) Stop the DMA Transfer using HAL_SAI_DMAStop()
|
|
109
|
|
110 *** SAI HAL driver macros list ***
|
|
111 =============================================
|
|
112 [..]
|
|
113 Below the list of most used macros in USART HAL driver :
|
|
114
|
|
115 (+) __HAL_SAI_ENABLE: Enable the SAI peripheral
|
|
116 (+) __HAL_SAI_DISABLE: Disable the SAI peripheral
|
|
117 (+) __HAL_SAI_ENABLE_IT : Enable the specified SAI interrupts
|
|
118 (+) __HAL_SAI_DISABLE_IT : Disable the specified SAI interrupts
|
|
119 (+) __HAL_SAI_GET_IT_SOURCE: Check if the specified SAI interrupt source is
|
|
120 enabled or disabled
|
|
121 (+) __HAL_SAI_GET_FLAG: Check whether the specified SAI flag is set or not
|
|
122
|
|
123 @endverbatim
|
|
124 ******************************************************************************
|
|
125 * @attention
|
|
126 *
|
|
127 * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
|
|
128 *
|
|
129 * Redistribution and use in source and binary forms, with or without modification,
|
|
130 * are permitted provided that the following conditions are met:
|
|
131 * 1. Redistributions of source code must retain the above copyright notice,
|
|
132 * this list of conditions and the following disclaimer.
|
|
133 * 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
134 * this list of conditions and the following disclaimer in the documentation
|
|
135 * and/or other materials provided with the distribution.
|
|
136 * 3. Neither the name of STMicroelectronics nor the names of its contributors
|
|
137 * may be used to endorse or promote products derived from this software
|
|
138 * without specific prior written permission.
|
|
139 *
|
|
140 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
141 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
142 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
143 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
144 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
145 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
146 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
147 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
148 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
149 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
150 *
|
|
151 ******************************************************************************
|
|
152 */
|
|
153
|
|
154 /* Includes ------------------------------------------------------------------*/
|
|
155 #include "stm32f4xx_hal.h"
|
|
156
|
|
157 /** @addtogroup STM32F4xx_HAL_Driver
|
|
158 * @{
|
|
159 */
|
|
160
|
|
161 /** @defgroup SAI SAI
|
|
162 * @brief SAI HAL module driver
|
|
163 * @{
|
|
164 */
|
|
165
|
|
166 #ifdef HAL_SAI_MODULE_ENABLED
|
|
167
|
|
168 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
|
|
169
|
|
170 /* Private typedef -----------------------------------------------------------*/
|
|
171 /* Private define ------------------------------------------------------------*/
|
|
172 /* SAI registers Masks */
|
|
173 #define CR1_CLEAR_MASK ((uint32_t)0xFF07C010)
|
|
174 #define FRCR_CLEAR_MASK ((uint32_t)0xFFF88000)
|
|
175 #define SLOTR_CLEAR_MASK ((uint32_t)0x0000F020)
|
|
176
|
|
177 #define SAI_TIMEOUT_VALUE 10
|
|
178 /* Private macro -------------------------------------------------------------*/
|
|
179 /* Private variables ---------------------------------------------------------*/
|
|
180 /* Private function prototypes -----------------------------------------------*/
|
|
181 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma);
|
|
182 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma);
|
|
183 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma);
|
|
184 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma);
|
|
185 static void SAI_DMAError(DMA_HandleTypeDef *hdma);
|
|
186
|
|
187 /* Private functions ---------------------------------------------------------*/
|
|
188
|
|
189 /** @defgroup SAI_Private_Functions SAI Private Functions
|
|
190 * @{
|
|
191 */
|
|
192
|
|
193 /** @defgroup SAI_Exported_Functions_Group1 Initialization and de-initialization functions
|
|
194 * @brief Initialization and Configuration functions
|
|
195 *
|
|
196 @verbatim
|
|
197 ===============================================================================
|
|
198 ##### Initialization and de-initialization functions #####
|
|
199 ===============================================================================
|
|
200 [..] This subsection provides a set of functions allowing to initialize and
|
|
201 de-initialize the SAIx peripheral:
|
|
202
|
|
203 (+) User must implement HAL_SAI_MspInit() function in which he configures
|
|
204 all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC ).
|
|
205
|
|
206 (+) Call the function HAL_SAI_Init() to configure the selected device with
|
|
207 the selected configuration:
|
|
208 (++) Mode (Master/slave TX/RX)
|
|
209 (++) Protocol
|
|
210 (++) Data Size
|
|
211 (++) MCLK Output
|
|
212 (++) Audio frequency
|
|
213 (++) FIFO Threshold
|
|
214 (++) Frame Config
|
|
215 (++) Slot Config
|
|
216
|
|
217 (+) Call the function HAL_SAI_DeInit() to restore the default configuration
|
|
218 of the selected SAI peripheral.
|
|
219
|
|
220 @endverbatim
|
|
221 * @{
|
|
222 */
|
|
223
|
|
224 /**
|
|
225 * @brief Initializes the SAI according to the specified parameters
|
|
226 * in the SAI_InitTypeDef and create the associated handle.
|
|
227 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
228 * the configuration information for SAI module.
|
|
229 * @retval HAL status
|
|
230 */
|
|
231 HAL_StatusTypeDef HAL_SAI_Init(SAI_HandleTypeDef *hsai)
|
|
232 {
|
|
233 uint32_t tmpreg = 0;
|
|
234 uint32_t tmpclock = 0, tmp2clock = 0;
|
|
235 /* This variable used to store the VCO Input (value in Hz) */
|
|
236 uint32_t vcoinput = 0;
|
|
237 /* This variable used to store the SAI_CK_x (value in Hz) */
|
|
238 uint32_t saiclocksource = 0;
|
|
239
|
|
240 /* Check the SAI handle allocation */
|
|
241 if(hsai == NULL)
|
|
242 {
|
|
243 return HAL_ERROR;
|
|
244 }
|
|
245
|
|
246 /* Check the SAI Block parameters */
|
|
247 assert_param(IS_SAI_BLOCK_PROTOCOL(hsai->Init.Protocol));
|
|
248 assert_param(IS_SAI_BLOCK_MODE(hsai->Init.AudioMode));
|
|
249 assert_param(IS_SAI_BLOCK_DATASIZE(hsai->Init.DataSize));
|
|
250 assert_param(IS_SAI_BLOCK_FIRST_BIT(hsai->Init.FirstBit));
|
|
251 assert_param(IS_SAI_BLOCK_CLOCK_STROBING(hsai->Init.ClockStrobing));
|
|
252 assert_param(IS_SAI_BLOCK_SYNCHRO(hsai->Init.Synchro));
|
|
253 assert_param(IS_SAI_BLOCK_OUTPUT_DRIVE(hsai->Init.OutputDrive));
|
|
254 assert_param(IS_SAI_BLOCK_NODIVIDER(hsai->Init.NoDivider));
|
|
255 assert_param(IS_SAI_BLOCK_FIFO_THRESHOLD(hsai->Init.FIFOThreshold));
|
|
256 assert_param(IS_SAI_AUDIO_FREQUENCY(hsai->Init.AudioFrequency));
|
|
257
|
|
258 /* Check the SAI Block Frame parameters */
|
|
259 assert_param(IS_SAI_BLOCK_FRAME_LENGTH(hsai->FrameInit.FrameLength));
|
|
260 assert_param(IS_SAI_BLOCK_ACTIVE_FRAME(hsai->FrameInit.ActiveFrameLength));
|
|
261 assert_param(IS_SAI_BLOCK_FS_DEFINITION(hsai->FrameInit.FSDefinition));
|
|
262 assert_param(IS_SAI_BLOCK_FS_POLARITY(hsai->FrameInit.FSPolarity));
|
|
263 assert_param(IS_SAI_BLOCK_FS_OFFSET(hsai->FrameInit.FSOffset));
|
|
264
|
|
265 /* Check the SAI Block Slot parameters */
|
|
266 assert_param(IS_SAI_BLOCK_FIRSTBIT_OFFSET(hsai->SlotInit.FirstBitOffset));
|
|
267 assert_param(IS_SAI_BLOCK_SLOT_SIZE(hsai->SlotInit.SlotSize));
|
|
268 assert_param(IS_SAI_BLOCK_SLOT_NUMBER(hsai->SlotInit.SlotNumber));
|
|
269 assert_param(IS_SAI_SLOT_ACTIVE(hsai->SlotInit.SlotActive));
|
|
270
|
|
271 if(hsai->State == HAL_SAI_STATE_RESET)
|
|
272 {
|
|
273 /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
|
|
274 HAL_SAI_MspInit(hsai);
|
|
275 }
|
|
276
|
|
277 hsai->State = HAL_SAI_STATE_BUSY;
|
|
278
|
|
279 /* Disable the selected SAI peripheral */
|
|
280 __HAL_SAI_DISABLE(hsai);
|
|
281
|
|
282 /* SAI Block Configuration ------------------------------------------------------------*/
|
|
283 /* SAI Block_x CR1 Configuration */
|
|
284 /* Get the SAI Block_x CR1 value */
|
|
285 tmpreg = hsai->Instance->CR1;
|
|
286 /* Clear MODE, PRTCFG, DS, LSBFIRST, CKSTR, SYNCEN, OUTDRIV, NODIV, and MCKDIV bits */
|
|
287 tmpreg &= CR1_CLEAR_MASK;
|
|
288 /* Configure SAI_Block_x: Audio Protocol, Data Size, first transmitted bit, Clock strobing
|
|
289 edge, Synchronization mode, Output drive, Master Divider and FIFO level */
|
|
290 /* Set PRTCFG bits according to Protocol value */
|
|
291 /* Set DS bits according to DataSize value */
|
|
292 /* Set LSBFIRST bit according to FirstBit value */
|
|
293 /* Set CKSTR bit according to ClockStrobing value */
|
|
294 /* Set SYNCEN bit according to Synchro value */
|
|
295 /* Set OUTDRIV bit according to OutputDrive value */
|
|
296 /* Set NODIV bit according to NoDivider value */
|
|
297 tmpreg |= (uint32_t)(hsai->Init.Protocol |
|
|
298 hsai->Init.AudioMode |
|
|
299 hsai->Init.DataSize |
|
|
300 hsai->Init.FirstBit |
|
|
301 hsai->Init.ClockStrobing |
|
|
302 hsai->Init.Synchro |
|
|
303 hsai->Init.OutputDrive |
|
|
304 hsai->Init.NoDivider);
|
|
305 /* Write to SAI_Block_x CR1 */
|
|
306 hsai->Instance->CR1 = tmpreg;
|
|
307
|
|
308 /* SAI Block_x CR2 Configuration */
|
|
309 /* Get the SAIBlock_x CR2 value */
|
|
310 tmpreg = hsai->Instance->CR2;
|
|
311 /* Clear FTH bits */
|
|
312 tmpreg &= ~(SAI_xCR2_FTH);
|
|
313 /* Configure the FIFO Level */
|
|
314 /* Set FTH bits according to SAI_FIFOThreshold value */
|
|
315 tmpreg |= (uint32_t)(hsai->Init.FIFOThreshold);
|
|
316 /* Write to SAI_Block_x CR2 */
|
|
317 hsai->Instance->CR2 = tmpreg;
|
|
318
|
|
319 /* SAI Block_x Frame Configuration -----------------------------------------*/
|
|
320 /* Get the SAI Block_x FRCR value */
|
|
321 tmpreg = hsai->Instance->FRCR;
|
|
322 /* Clear FRL, FSALL, FSDEF, FSPOL, FSOFF bits */
|
|
323 tmpreg &= FRCR_CLEAR_MASK;
|
|
324 /* Configure SAI_Block_x Frame: Frame Length, Active Frame Length, Frame Synchronization
|
|
325 Definition, Frame Synchronization Polarity and Frame Synchronization Polarity */
|
|
326 /* Set FRL bits according to SAI_FrameLength value */
|
|
327 /* Set FSALL bits according to SAI_ActiveFrameLength value */
|
|
328 /* Set FSDEF bit according to SAI_FSDefinition value */
|
|
329 /* Set FSPOL bit according to SAI_FSPolarity value */
|
|
330 /* Set FSOFF bit according to SAI_FSOffset value */
|
|
331 tmpreg |= (uint32_t)((uint32_t)(hsai->FrameInit.FrameLength - 1) |
|
|
332 hsai->FrameInit.FSOffset |
|
|
333 hsai->FrameInit.FSDefinition |
|
|
334 hsai->FrameInit.FSPolarity |
|
|
335 (uint32_t)((hsai->FrameInit.ActiveFrameLength - 1) << 8));
|
|
336
|
|
337 /* Write to SAI_Block_x FRCR */
|
|
338 hsai->Instance->FRCR = tmpreg;
|
|
339
|
|
340 /* SAI Block_x SLOT Configuration ------------------------------------------*/
|
|
341 /* Get the SAI Block_x SLOTR value */
|
|
342 tmpreg = hsai->Instance->SLOTR;
|
|
343 /* Clear FBOFF, SLOTSZ, NBSLOT, SLOTEN bits */
|
|
344 tmpreg &= SLOTR_CLEAR_MASK;
|
|
345 /* Configure SAI_Block_x Slot: First bit offset, Slot size, Number of Slot in
|
|
346 audio frame and slots activated in audio frame */
|
|
347 /* Set FBOFF bits according to SAI_FirstBitOffset value */
|
|
348 /* Set SLOTSZ bits according to SAI_SlotSize value */
|
|
349 /* Set NBSLOT bits according to SAI_SlotNumber value */
|
|
350 /* Set SLOTEN bits according to SAI_SlotActive value */
|
|
351 tmpreg |= (uint32_t)(hsai->SlotInit.FirstBitOffset |
|
|
352 hsai->SlotInit.SlotSize |
|
|
353 hsai->SlotInit.SlotActive |
|
|
354 (uint32_t)((hsai->SlotInit.SlotNumber - 1) << 8));
|
|
355
|
|
356 /* Write to SAI_Block_x SLOTR */
|
|
357 hsai->Instance->SLOTR = tmpreg;
|
|
358
|
|
359 /* SAI Block_x Clock Configuration -----------------------------------------*/
|
|
360 /* Check the Clock parameters */
|
|
361 assert_param(IS_SAI_CLK_SOURCE(hsai->Init.ClockSource));
|
|
362
|
|
363 /* SAI Block clock source selection */
|
|
364 if(hsai->Instance == SAI1_Block_A)
|
|
365 {
|
|
366 __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(hsai->Init.ClockSource);
|
|
367 }
|
|
368 else
|
|
369 {
|
|
370 __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG((uint32_t)(hsai->Init.ClockSource << 2));
|
|
371 }
|
|
372
|
|
373 /* VCO Input Clock value calculation */
|
|
374 if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI)
|
|
375 {
|
|
376 /* In Case the PLL Source is HSI (Internal Clock) */
|
|
377 vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
|
|
378 }
|
|
379 else
|
|
380 {
|
|
381 /* In Case the PLL Source is HSE (External Clock) */
|
|
382 vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)));
|
|
383 }
|
|
384
|
|
385 /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */
|
|
386 if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLSAI)
|
|
387 {
|
|
388 /* Configure the PLLI2S division factor */
|
|
389 /* PLLSAI_VCO Input = PLL_SOURCE/PLLM */
|
|
390 /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
|
|
391 /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
|
|
392 tmpreg = (RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24;
|
|
393 saiclocksource = (vcoinput * ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> 6))/(tmpreg);
|
|
394
|
|
395 /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
|
|
396 tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8) + 1);
|
|
397 saiclocksource = saiclocksource/(tmpreg);
|
|
398
|
|
399 }
|
|
400 else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S)
|
|
401 {
|
|
402 /* Configure the PLLI2S division factor */
|
|
403 /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */
|
|
404 /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
|
|
405 /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
|
|
406 tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> 24;
|
|
407 saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6))/(tmpreg);
|
|
408
|
|
409 /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
|
|
410 tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1);
|
|
411 saiclocksource = saiclocksource/(tmpreg);
|
|
412 }
|
|
413 else /* sConfig->ClockSource == SAI_CLKSource_Ext */
|
|
414 {
|
|
415 /* Enable the External Clock selection */
|
|
416 __HAL_RCC_I2S_CONFIG(RCC_I2SCLKSOURCE_EXT);
|
|
417
|
|
418 saiclocksource = EXTERNAL_CLOCK_VALUE;
|
|
419 }
|
|
420
|
|
421 /* Configure Master Clock using the following formula :
|
|
422 MCLK_x = SAI_CK_x / (MCKDIV[3:0] * 2) with MCLK_x = 256 * FS
|
|
423 FS = SAI_CK_x / (MCKDIV[3:0] * 2) * 256
|
|
424 MCKDIV[3:0] = SAI_CK_x / FS * 512 */
|
|
425 if(hsai->Init.NoDivider == SAI_MASTERDIVIDER_ENABLE)
|
|
426 {
|
|
427 /* (saiclocksource x 10) to keep Significant digits */
|
|
428 tmpclock = (((saiclocksource * 10) / ((hsai->Init.AudioFrequency) * 512)));
|
|
429
|
|
430 /* Get the result of modulo division */
|
|
431 tmp2clock = (tmpclock % 10);
|
|
432
|
|
433 /* Round result to the nearest integer*/
|
|
434 if (tmp2clock > 8)
|
|
435 {
|
|
436 tmpclock = ((tmpclock / 10) + 1);
|
|
437 }
|
|
438 else
|
|
439 {
|
|
440 tmpclock = (tmpclock / 10);
|
|
441 }
|
|
442 /*Set MCKDIV value in CR1 register*/
|
|
443 hsai->Instance->CR1 |= (tmpclock << 20);
|
|
444
|
|
445 }
|
|
446
|
|
447 /* Initialize the error code */
|
|
448 hsai->ErrorCode = HAL_SAI_ERROR_NONE;
|
|
449
|
|
450 /* Initialize the SAI state */
|
|
451 hsai->State= HAL_SAI_STATE_READY;
|
|
452
|
|
453 return HAL_OK;
|
|
454 }
|
|
455
|
|
456 /**
|
|
457 * @brief DeInitializes the SAI peripheral.
|
|
458 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
459 * the configuration information for SAI module.
|
|
460 * @retval HAL status
|
|
461 */
|
|
462 HAL_StatusTypeDef HAL_SAI_DeInit(SAI_HandleTypeDef *hsai)
|
|
463 {
|
|
464 /* Check the SAI handle allocation */
|
|
465 if(hsai == NULL)
|
|
466 {
|
|
467 return HAL_ERROR;
|
|
468 }
|
|
469
|
|
470 hsai->State = HAL_SAI_STATE_BUSY;
|
|
471
|
|
472 /* DeInit the low level hardware: GPIO, CLOCK, NVIC and DMA */
|
|
473 HAL_SAI_MspDeInit(hsai);
|
|
474
|
|
475 /* Initialize the error code */
|
|
476 hsai->ErrorCode = HAL_SAI_ERROR_NONE;
|
|
477
|
|
478 /* Initialize the SAI state */
|
|
479 hsai->State = HAL_SAI_STATE_RESET;
|
|
480
|
|
481 /* Release Lock */
|
|
482 __HAL_UNLOCK(hsai);
|
|
483
|
|
484 return HAL_OK;
|
|
485 }
|
|
486
|
|
487 /**
|
|
488 * @brief SAI MSP Init.
|
|
489 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
490 * the configuration information for SAI module.
|
|
491 * @retval None
|
|
492 */
|
|
493 __weak void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
|
|
494 {
|
|
495 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
496 the HAL_SAI_MspInit could be implemented in the user file
|
|
497 */
|
|
498 }
|
|
499
|
|
500 /**
|
|
501 * @brief SAI MSP DeInit.
|
|
502 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
503 * the configuration information for SAI module.
|
|
504 * @retval None
|
|
505 */
|
|
506 __weak void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai)
|
|
507 {
|
|
508 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
509 the HAL_SAI_MspDeInit could be implemented in the user file
|
|
510 */
|
|
511 }
|
|
512
|
|
513 /**
|
|
514 * @}
|
|
515 */
|
|
516
|
|
517 /** @defgroup SAI_Exported_Functions_Group2 IO operation functions
|
|
518 * @brief Data transfers functions
|
|
519 *
|
|
520 @verbatim
|
|
521 ===============================================================================
|
|
522 ##### IO operation functions #####
|
|
523 ===============================================================================
|
|
524 [..]
|
|
525 This subsection provides a set of functions allowing to manage the SAI data
|
|
526 transfers.
|
|
527
|
|
528 (+) There are two modes of transfer:
|
|
529 (++) Blocking mode : The communication is performed in the polling mode.
|
|
530 The status of all data processing is returned by the same function
|
|
531 after finishing transfer.
|
|
532 (++) No-Blocking mode : The communication is performed using Interrupts
|
|
533 or DMA. These functions return the status of the transfer startup.
|
|
534 The end of the data processing will be indicated through the
|
|
535 dedicated SAI IRQ when using Interrupt mode or the DMA IRQ when
|
|
536 using DMA mode.
|
|
537
|
|
538 (+) Blocking mode functions are :
|
|
539 (++) HAL_SAI_Transmit()
|
|
540 (++) HAL_SAI_Receive()
|
|
541 (++) HAL_SAI_TransmitReceive()
|
|
542
|
|
543 (+) Non Blocking mode functions with Interrupt are :
|
|
544 (++) HAL_SAI_Transmit_IT()
|
|
545 (++) HAL_SAI_Receive_IT()
|
|
546 (++) HAL_SAI_TransmitReceive_IT()
|
|
547
|
|
548 (+) Non Blocking mode functions with DMA are :
|
|
549 (++) HAL_SAI_Transmit_DMA()
|
|
550 (++) HAL_SAI_Receive_DMA()
|
|
551 (++) HAL_SAI_TransmitReceive_DMA()
|
|
552
|
|
553 (+) A set of Transfer Complete Callbacks are provided in non Blocking mode:
|
|
554 (++) HAL_SAI_TxCpltCallback()
|
|
555 (++) HAL_SAI_RxCpltCallback()
|
|
556 (++) HAL_SAI_ErrorCallback()
|
|
557
|
|
558 @endverbatim
|
|
559 * @{
|
|
560 */
|
|
561
|
|
562 /**
|
|
563 * @brief Transmits an amount of data in blocking mode.
|
|
564 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
565 * the configuration information for SAI module.
|
|
566 * @param pData: Pointer to data buffer
|
|
567 * @param Size: Amount of data to be sent
|
|
568 * @param Timeout: Timeout duration
|
|
569 * @retval HAL status
|
|
570 */
|
|
571 HAL_StatusTypeDef HAL_SAI_Transmit(SAI_HandleTypeDef *hsai, uint16_t* pData, uint16_t Size, uint32_t Timeout)
|
|
572 {
|
|
573 uint32_t tickstart = 0;
|
|
574
|
|
575 if((pData == NULL ) || (Size == 0))
|
|
576 {
|
|
577 return HAL_ERROR;
|
|
578 }
|
|
579
|
|
580 if(hsai->State == HAL_SAI_STATE_READY)
|
|
581 {
|
|
582 /* Process Locked */
|
|
583 __HAL_LOCK(hsai);
|
|
584
|
|
585 hsai->State = HAL_SAI_STATE_BUSY_TX;
|
|
586
|
|
587 /* Check if the SAI is already enabled */
|
|
588 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
|
|
589 {
|
|
590 /* Enable SAI peripheral */
|
|
591 __HAL_SAI_ENABLE(hsai);
|
|
592 }
|
|
593
|
|
594 while(Size > 0)
|
|
595 {
|
|
596 /* Get tick */
|
|
597 tickstart = HAL_GetTick();
|
|
598
|
|
599 /* Wait the FIFO to be empty */
|
|
600 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ) == RESET)
|
|
601 {
|
|
602 /* Check for the Timeout */
|
|
603 if(Timeout != HAL_MAX_DELAY)
|
|
604 {
|
|
605 if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
|
|
606 {
|
|
607 /* Update error code */
|
|
608 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
|
|
609
|
|
610 /* Process Unlocked */
|
|
611 __HAL_UNLOCK(hsai);
|
|
612
|
|
613 /* Change the SAI state */
|
|
614 hsai->State = HAL_SAI_STATE_TIMEOUT;
|
|
615
|
|
616 return HAL_TIMEOUT;
|
|
617 }
|
|
618 }
|
|
619 }
|
|
620 hsai->Instance->DR = (*pData++);
|
|
621 Size--;
|
|
622 }
|
|
623
|
|
624 hsai->State = HAL_SAI_STATE_READY;
|
|
625
|
|
626 /* Process Unlocked */
|
|
627 __HAL_UNLOCK(hsai);
|
|
628
|
|
629 return HAL_OK;
|
|
630 }
|
|
631 else
|
|
632 {
|
|
633 return HAL_BUSY;
|
|
634 }
|
|
635 }
|
|
636
|
|
637 /**
|
|
638 * @brief Receives an amount of data in blocking mode.
|
|
639 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
640 * the configuration information for SAI module.
|
|
641 * @param pData: Pointer to data buffer
|
|
642 * @param Size: Amount of data to be received
|
|
643 * @param Timeout: Timeout duration
|
|
644 * @retval HAL status
|
|
645 */
|
|
646 HAL_StatusTypeDef HAL_SAI_Receive(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size, uint32_t Timeout)
|
|
647 {
|
|
648 uint32_t tickstart = 0;
|
|
649
|
|
650 if((pData == NULL ) || (Size == 0))
|
|
651 {
|
|
652 return HAL_ERROR;
|
|
653 }
|
|
654
|
|
655 if(hsai->State == HAL_SAI_STATE_READY)
|
|
656 {
|
|
657 /* Process Locked */
|
|
658 __HAL_LOCK(hsai);
|
|
659
|
|
660 hsai->State = HAL_SAI_STATE_BUSY_RX;
|
|
661
|
|
662 /* Check if the SAI is already enabled */
|
|
663 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
|
|
664 {
|
|
665 /* Enable SAI peripheral */
|
|
666 __HAL_SAI_ENABLE(hsai);
|
|
667 }
|
|
668
|
|
669 /* Receive data */
|
|
670 while(Size > 0)
|
|
671 {
|
|
672 /* Get tick */
|
|
673 tickstart = HAL_GetTick();
|
|
674
|
|
675 /* Wait until RXNE flag is set */
|
|
676 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ) == RESET)
|
|
677 {
|
|
678 /* Check for the Timeout */
|
|
679 if(Timeout != HAL_MAX_DELAY)
|
|
680 {
|
|
681 if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
|
|
682 {
|
|
683 /* Update error code */
|
|
684 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
|
|
685
|
|
686 /* Process Unlocked */
|
|
687 __HAL_UNLOCK(hsai);
|
|
688
|
|
689 /* Change the SAI state */
|
|
690 hsai->State = HAL_SAI_STATE_TIMEOUT;
|
|
691
|
|
692 return HAL_TIMEOUT;
|
|
693 }
|
|
694 }
|
|
695 }
|
|
696
|
|
697 (*pData++) = hsai->Instance->DR;
|
|
698 Size--;
|
|
699 }
|
|
700
|
|
701 hsai->State = HAL_SAI_STATE_READY;
|
|
702
|
|
703 /* Process Unlocked */
|
|
704 __HAL_UNLOCK(hsai);
|
|
705
|
|
706 return HAL_OK;
|
|
707 }
|
|
708 else
|
|
709 {
|
|
710 return HAL_BUSY;
|
|
711 }
|
|
712 }
|
|
713
|
|
714 /**
|
|
715 * @brief Transmits an amount of data in no-blocking mode with Interrupt.
|
|
716 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
717 * the configuration information for SAI module.
|
|
718 * @param pData: Pointer to data buffer
|
|
719 * @param Size: Amount of data to be sent
|
|
720 * @retval HAL status
|
|
721 */
|
|
722 HAL_StatusTypeDef HAL_SAI_Transmit_IT(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
|
|
723 {
|
|
724 if(hsai->State == HAL_SAI_STATE_READY)
|
|
725 {
|
|
726 if((pData == NULL) || (Size == 0))
|
|
727 {
|
|
728 return HAL_ERROR;
|
|
729 }
|
|
730
|
|
731 hsai->pTxBuffPtr = pData;
|
|
732 hsai->TxXferSize = Size;
|
|
733 hsai->TxXferCount = Size;
|
|
734
|
|
735 /* Process Locked */
|
|
736 __HAL_LOCK(hsai);
|
|
737
|
|
738 hsai->State = HAL_SAI_STATE_BUSY_TX;
|
|
739
|
|
740 /* Transmit data */
|
|
741 hsai->Instance->DR = (*hsai->pTxBuffPtr++);
|
|
742 hsai->TxXferCount--;
|
|
743
|
|
744 /* Process Unlocked */
|
|
745 __HAL_UNLOCK(hsai);
|
|
746
|
|
747 /* Enable FRQ and OVRUDR interrupts */
|
|
748 __HAL_SAI_ENABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
|
|
749
|
|
750 /* Check if the SAI is already enabled */
|
|
751 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
|
|
752 {
|
|
753 /* Enable SAI peripheral */
|
|
754 __HAL_SAI_ENABLE(hsai);
|
|
755 }
|
|
756
|
|
757
|
|
758 return HAL_OK;
|
|
759 }
|
|
760 else if(hsai->State == HAL_SAI_STATE_BUSY_TX)
|
|
761 {
|
|
762 /* Process Locked */
|
|
763 __HAL_LOCK(hsai);
|
|
764
|
|
765 /* Transmit data */
|
|
766 hsai->Instance->DR = (*hsai->pTxBuffPtr++);
|
|
767
|
|
768 hsai->TxXferCount--;
|
|
769
|
|
770 if(hsai->TxXferCount == 0)
|
|
771 {
|
|
772 /* Disable FREQ and OVRUDR interrupts */
|
|
773 __HAL_SAI_DISABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
|
|
774
|
|
775 hsai->State = HAL_SAI_STATE_READY;
|
|
776
|
|
777 HAL_SAI_TxCpltCallback(hsai);
|
|
778 }
|
|
779
|
|
780 /* Process Unlocked */
|
|
781 __HAL_UNLOCK(hsai);
|
|
782
|
|
783 return HAL_OK;
|
|
784 }
|
|
785
|
|
786 else
|
|
787 {
|
|
788 return HAL_BUSY;
|
|
789 }
|
|
790 }
|
|
791
|
|
792 /**
|
|
793 * @brief Receives an amount of data in no-blocking mode with Interrupt.
|
|
794 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
795 * the configuration information for SAI module.
|
|
796 * @param pData: Pointer to data buffer
|
|
797 * @param Size: Amount of data to be received
|
|
798 * @retval HAL status
|
|
799 */
|
|
800 HAL_StatusTypeDef HAL_SAI_Receive_IT(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
|
|
801 {
|
|
802 if(hsai->State == HAL_SAI_STATE_READY)
|
|
803 {
|
|
804 if((pData == NULL) || (Size == 0))
|
|
805 {
|
|
806 return HAL_ERROR;
|
|
807 }
|
|
808
|
|
809 hsai->pRxBuffPtr = pData;
|
|
810 hsai->RxXferSize = Size;
|
|
811 hsai->RxXferCount = Size;
|
|
812
|
|
813 /* Process Locked */
|
|
814 __HAL_LOCK(hsai);
|
|
815
|
|
816 hsai->State = HAL_SAI_STATE_BUSY_RX;
|
|
817
|
|
818 /* Enable TXE and OVRUDR interrupts */
|
|
819 __HAL_SAI_ENABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
|
|
820
|
|
821 /* Check if the SAI is already enabled */
|
|
822 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
|
|
823 {
|
|
824 /* Enable SAI peripheral */
|
|
825 __HAL_SAI_ENABLE(hsai);
|
|
826 }
|
|
827
|
|
828 /* Process Unlocked */
|
|
829 __HAL_UNLOCK(hsai);
|
|
830
|
|
831 return HAL_OK;
|
|
832 }
|
|
833 else if(hsai->State == HAL_SAI_STATE_BUSY_RX)
|
|
834 {
|
|
835 /* Process Locked */
|
|
836 __HAL_LOCK(hsai);
|
|
837
|
|
838 /* Receive data */
|
|
839 (*hsai->pRxBuffPtr++) = hsai->Instance->DR;
|
|
840
|
|
841 hsai->RxXferCount--;
|
|
842
|
|
843 if(hsai->RxXferCount == 0)
|
|
844 {
|
|
845 /* Disable TXE and OVRUDR interrupts */
|
|
846 __HAL_SAI_DISABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
|
|
847
|
|
848 hsai->State = HAL_SAI_STATE_READY;
|
|
849 HAL_SAI_RxCpltCallback(hsai);
|
|
850 }
|
|
851
|
|
852 /* Process Unlocked */
|
|
853 __HAL_UNLOCK(hsai);
|
|
854
|
|
855 return HAL_OK;
|
|
856 }
|
|
857
|
|
858 else
|
|
859 {
|
|
860 return HAL_BUSY;
|
|
861 }
|
|
862 }
|
|
863
|
|
864 /**
|
|
865 * @brief Pauses the audio stream playing from the Media.
|
|
866 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
867 * the configuration information for SAI module.
|
|
868 * @retval HAL status
|
|
869 */
|
|
870 HAL_StatusTypeDef HAL_SAI_DMAPause(SAI_HandleTypeDef *hsai)
|
|
871 {
|
|
872 /* Process Locked */
|
|
873 __HAL_LOCK(hsai);
|
|
874
|
|
875 /* Pause the audio file playing by disabling the SAI DMA requests */
|
|
876 hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
|
|
877
|
|
878
|
|
879 /* Process Unlocked */
|
|
880 __HAL_UNLOCK(hsai);
|
|
881
|
|
882 return HAL_OK;
|
|
883 }
|
|
884
|
|
885 /**
|
|
886 * @brief Resumes the audio stream playing from the Media.
|
|
887 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
888 * the configuration information for SAI module.
|
|
889 * @retval HAL status
|
|
890 */
|
|
891 HAL_StatusTypeDef HAL_SAI_DMAResume(SAI_HandleTypeDef *hsai)
|
|
892 {
|
|
893 /* Process Locked */
|
|
894 __HAL_LOCK(hsai);
|
|
895
|
|
896 /* Enable the SAI DMA requests */
|
|
897 hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
|
|
898
|
|
899
|
|
900 /* If the SAI peripheral is still not enabled, enable it */
|
|
901 if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == 0)
|
|
902 {
|
|
903 /* Enable SAI peripheral */
|
|
904 __HAL_SAI_ENABLE(hsai);
|
|
905 }
|
|
906
|
|
907 /* Process Unlocked */
|
|
908 __HAL_UNLOCK(hsai);
|
|
909
|
|
910 return HAL_OK;
|
|
911 }
|
|
912
|
|
913 /**
|
|
914 * @brief Stops the audio stream playing from the Media.
|
|
915 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
916 * the configuration information for SAI module.
|
|
917 * @retval HAL status
|
|
918 */
|
|
919 HAL_StatusTypeDef HAL_SAI_DMAStop(SAI_HandleTypeDef *hsai)
|
|
920 {
|
|
921 /* Process Locked */
|
|
922 __HAL_LOCK(hsai);
|
|
923
|
|
924 /* Disable the SAI DMA request */
|
|
925 hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
|
|
926
|
|
927 /* Abort the SAI DMA Tx Stream */
|
|
928 if(hsai->hdmatx != NULL)
|
|
929 {
|
|
930 HAL_DMA_Abort(hsai->hdmatx);
|
|
931 }
|
|
932 /* Abort the SAI DMA Rx Stream */
|
|
933 if(hsai->hdmarx != NULL)
|
|
934 {
|
|
935 HAL_DMA_Abort(hsai->hdmarx);
|
|
936 }
|
|
937
|
|
938 /* Disable SAI peripheral */
|
|
939 __HAL_SAI_DISABLE(hsai);
|
|
940
|
|
941 hsai->State = HAL_SAI_STATE_READY;
|
|
942
|
|
943 /* Process Unlocked */
|
|
944 __HAL_UNLOCK(hsai);
|
|
945
|
|
946 return HAL_OK;
|
|
947 }
|
|
948 /**
|
|
949 * @brief Transmits an amount of data in no-blocking mode with DMA.
|
|
950 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
951 * the configuration information for SAI module.
|
|
952 * @param pData: Pointer to data buffer
|
|
953 * @param Size: Amount of data to be sent
|
|
954 * @retval HAL status
|
|
955 */
|
|
956 HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
|
|
957 {
|
|
958 uint32_t *tmp;
|
|
959
|
|
960 if((pData == NULL) || (Size == 0))
|
|
961 {
|
|
962 return HAL_ERROR;
|
|
963 }
|
|
964
|
|
965 if(hsai->State == HAL_SAI_STATE_READY)
|
|
966 {
|
|
967 hsai->pTxBuffPtr = pData;
|
|
968 hsai->TxXferSize = Size;
|
|
969 hsai->TxXferCount = Size;
|
|
970
|
|
971 /* Process Locked */
|
|
972 __HAL_LOCK(hsai);
|
|
973
|
|
974 hsai->State = HAL_SAI_STATE_BUSY_TX;
|
|
975
|
|
976 /* Set the SAI Tx DMA Half transfer complete callback */
|
|
977 hsai->hdmatx->XferHalfCpltCallback = SAI_DMATxHalfCplt;
|
|
978
|
|
979 /* Set the SAI TxDMA transfer complete callback */
|
|
980 hsai->hdmatx->XferCpltCallback = SAI_DMATxCplt;
|
|
981
|
|
982 /* Set the DMA error callback */
|
|
983 hsai->hdmatx->XferErrorCallback = SAI_DMAError;
|
|
984
|
|
985 /* Enable the Tx DMA Stream */
|
|
986 tmp = (uint32_t*)&pData;
|
|
987 HAL_DMA_Start_IT(hsai->hdmatx, *(uint32_t*)tmp, (uint32_t)&hsai->Instance->DR, hsai->TxXferSize);
|
|
988
|
|
989 /* Check if the SAI is already enabled */
|
|
990 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
|
|
991 {
|
|
992 /* Enable SAI peripheral */
|
|
993 __HAL_SAI_ENABLE(hsai);
|
|
994 }
|
|
995
|
|
996 /* Enable SAI Tx DMA Request */
|
|
997 hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
|
|
998
|
|
999 /* Process Unlocked */
|
|
1000 __HAL_UNLOCK(hsai);
|
|
1001
|
|
1002 return HAL_OK;
|
|
1003 }
|
|
1004 else
|
|
1005 {
|
|
1006 return HAL_BUSY;
|
|
1007 }
|
|
1008 }
|
|
1009
|
|
1010 /**
|
|
1011 * @brief Receives an amount of data in no-blocking mode with DMA.
|
|
1012 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1013 * the configuration information for SAI module.
|
|
1014 * @param pData: Pointer to data buffer
|
|
1015 * @param Size: Amount of data to be received
|
|
1016 * @retval HAL status
|
|
1017 */
|
|
1018 HAL_StatusTypeDef HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
|
|
1019 {
|
|
1020 uint32_t *tmp;
|
|
1021
|
|
1022 if((pData == NULL) || (Size == 0))
|
|
1023 {
|
|
1024 return HAL_ERROR;
|
|
1025 }
|
|
1026
|
|
1027 if(hsai->State == HAL_SAI_STATE_READY)
|
|
1028 {
|
|
1029 hsai->pRxBuffPtr = pData;
|
|
1030 hsai->RxXferSize = Size;
|
|
1031 hsai->RxXferCount = Size;
|
|
1032
|
|
1033 /* Process Locked */
|
|
1034 __HAL_LOCK(hsai);
|
|
1035
|
|
1036 hsai->State = HAL_SAI_STATE_BUSY_RX;
|
|
1037
|
|
1038 /* Set the SAI Rx DMA Half transfer complete callback */
|
|
1039 hsai->hdmarx->XferHalfCpltCallback = SAI_DMARxHalfCplt;
|
|
1040
|
|
1041 /* Set the SAI Rx DMA transfer complete callback */
|
|
1042 hsai->hdmarx->XferCpltCallback = SAI_DMARxCplt;
|
|
1043
|
|
1044 /* Set the DMA error callback */
|
|
1045 hsai->hdmarx->XferErrorCallback = SAI_DMAError;
|
|
1046
|
|
1047 /* Enable the Rx DMA Stream */
|
|
1048 tmp = (uint32_t*)&pData;
|
|
1049 HAL_DMA_Start_IT(hsai->hdmarx, (uint32_t)&hsai->Instance->DR, *(uint32_t*)tmp, hsai->RxXferSize);
|
|
1050
|
|
1051 /* Check if the SAI is already enabled */
|
|
1052 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
|
|
1053 {
|
|
1054 /* Enable SAI peripheral */
|
|
1055 __HAL_SAI_ENABLE(hsai);
|
|
1056 }
|
|
1057
|
|
1058 /* Enable SAI Rx DMA Request */
|
|
1059 hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
|
|
1060
|
|
1061 /* Process Unlocked */
|
|
1062 __HAL_UNLOCK(hsai);
|
|
1063
|
|
1064 return HAL_OK;
|
|
1065 }
|
|
1066 else
|
|
1067 {
|
|
1068 return HAL_BUSY;
|
|
1069 }
|
|
1070 }
|
|
1071
|
|
1072 /**
|
|
1073 * @brief This function handles SAI interrupt request.
|
|
1074 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1075 * the configuration information for SAI module.
|
|
1076 * @retval HAL status
|
|
1077 */
|
|
1078 void HAL_SAI_IRQHandler(SAI_HandleTypeDef *hsai)
|
|
1079 {
|
|
1080 uint32_t tmp1 = 0, tmp2 = 0;
|
|
1081
|
|
1082 if(hsai->State == HAL_SAI_STATE_BUSY_RX)
|
|
1083 {
|
|
1084 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ);
|
|
1085 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_FREQ);
|
|
1086 /* SAI in mode Receiver --------------------------------------------------*/
|
|
1087 if((tmp1 != RESET) && (tmp2 != RESET))
|
|
1088 {
|
|
1089 HAL_SAI_Receive_IT(hsai, NULL, 0);
|
|
1090 }
|
|
1091
|
|
1092 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_FLAG_OVRUDR);
|
|
1093 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_OVRUDR);
|
|
1094 /* SAI Overrun error interrupt occurred ----------------------------------*/
|
|
1095 if((tmp1 != RESET) && (tmp2 != RESET))
|
|
1096 {
|
|
1097 /* Change the SAI error code */
|
|
1098 hsai->ErrorCode = HAL_SAI_ERROR_OVR;
|
|
1099
|
|
1100 /* Clear the SAI Overrun flag */
|
|
1101 __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR);
|
|
1102 /* Set the SAI state ready to be able to start again the process */
|
|
1103 hsai->State = HAL_SAI_STATE_READY;
|
|
1104 HAL_SAI_ErrorCallback(hsai);
|
|
1105 }
|
|
1106 }
|
|
1107
|
|
1108 if(hsai->State == HAL_SAI_STATE_BUSY_TX)
|
|
1109 {
|
|
1110 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ);
|
|
1111 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_FREQ);
|
|
1112 /* SAI in mode Transmitter -----------------------------------------------*/
|
|
1113 if((tmp1 != RESET) && (tmp2 != RESET))
|
|
1114 {
|
|
1115 HAL_SAI_Transmit_IT(hsai, NULL, 0);
|
|
1116 }
|
|
1117
|
|
1118 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_FLAG_OVRUDR);
|
|
1119 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_OVRUDR);
|
|
1120 /* SAI Underrun error interrupt occurred ---------------------------------*/
|
|
1121 if((tmp1 != RESET) && (tmp2 != RESET))
|
|
1122 {
|
|
1123 /* Change the SAI error code */
|
|
1124 hsai->ErrorCode = HAL_SAI_ERROR_UDR;
|
|
1125
|
|
1126 /* Clear the SAI Underrun flag */
|
|
1127 __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR);
|
|
1128 /* Set the SAI state ready to be able to start again the process */
|
|
1129 hsai->State = HAL_SAI_STATE_READY;
|
|
1130 HAL_SAI_ErrorCallback(hsai);
|
|
1131 }
|
|
1132 }
|
|
1133 }
|
|
1134
|
|
1135 /**
|
|
1136 * @brief Tx Transfer completed callbacks.
|
|
1137 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1138 * the configuration information for SAI module.
|
|
1139 * @retval None
|
|
1140 */
|
|
1141 __weak void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
|
|
1142 {
|
|
1143 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
1144 the HAL_SAI_TxCpltCallback could be implemented in the user file
|
|
1145 */
|
|
1146 }
|
|
1147
|
|
1148 /**
|
|
1149 * @brief Tx Transfer Half completed callbacks
|
|
1150 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1151 * the configuration information for SAI module.
|
|
1152 * @retval None
|
|
1153 */
|
|
1154 __weak void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
|
1155 {
|
|
1156 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
1157 the HAL_SAI_TxHalfCpltCallback could be implemented in the user file
|
|
1158 */
|
|
1159 }
|
|
1160
|
|
1161 /**
|
|
1162 * @brief Rx Transfer completed callbacks.
|
|
1163 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1164 * the configuration information for SAI module.
|
|
1165 * @retval None
|
|
1166 */
|
|
1167 __weak void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
|
|
1168 {
|
|
1169 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
1170 the HAL_SAI_RxCpltCallback could be implemented in the user file
|
|
1171 */
|
|
1172 }
|
|
1173
|
|
1174 /**
|
|
1175 * @brief Rx Transfer half completed callbacks
|
|
1176 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1177 * the configuration information for SAI module.
|
|
1178 * @retval None
|
|
1179 */
|
|
1180 __weak void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
|
1181 {
|
|
1182 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
1183 the HAL_SAI_RxCpltCallback could be implemented in the user file
|
|
1184 */
|
|
1185 }
|
|
1186
|
|
1187 /**
|
|
1188 * @brief SAI error callbacks.
|
|
1189 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1190 * the configuration information for SAI module.
|
|
1191 * @retval None
|
|
1192 */
|
|
1193 __weak void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
|
|
1194 {
|
|
1195 /* NOTE : This function Should not be modified, when the callback is needed,
|
|
1196 the HAL_SAI_ErrorCallback could be implemented in the user file
|
|
1197 */
|
|
1198 }
|
|
1199
|
|
1200 /**
|
|
1201 * @}
|
|
1202 */
|
|
1203
|
|
1204
|
|
1205 /** @defgroup SAI_Exported_Functions_Group3 Peripheral State functions
|
|
1206 * @brief Peripheral State functions
|
|
1207 *
|
|
1208 @verbatim
|
|
1209 ===============================================================================
|
|
1210 ##### Peripheral State and Errors functions #####
|
|
1211 ===============================================================================
|
|
1212 [..]
|
|
1213 This subsection permits to get in run-time the status of the peripheral
|
|
1214 and the data flow.
|
|
1215
|
|
1216 @endverbatim
|
|
1217 * @{
|
|
1218 */
|
|
1219
|
|
1220 /**
|
|
1221 * @brief Returns the SAI state.
|
|
1222 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
|
|
1223 * the configuration information for SAI module.
|
|
1224 * @retval HAL state
|
|
1225 */
|
|
1226 HAL_SAI_StateTypeDef HAL_SAI_GetState(SAI_HandleTypeDef *hsai)
|
|
1227 {
|
|
1228 return hsai->State;
|
|
1229 }
|
|
1230
|
|
1231 /**
|
|
1232 * @brief Return the SAI error code
|
|
1233 * @param hsai : pointer to a SAI_HandleTypeDef structure that contains
|
|
1234 * the configuration information for the specified SAI Block.
|
|
1235 * @retval SAI Error Code
|
|
1236 */
|
|
1237 uint32_t HAL_SAI_GetError(SAI_HandleTypeDef *hsai)
|
|
1238 {
|
|
1239 return hsai->ErrorCode;
|
|
1240 }
|
|
1241 /**
|
|
1242 * @}
|
|
1243 */
|
|
1244
|
|
1245 /**
|
|
1246 * @brief DMA SAI transmit process complete callback.
|
|
1247 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains
|
|
1248 * the configuration information for the specified DMA module.
|
|
1249 * @retval None
|
|
1250 */
|
|
1251 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma)
|
|
1252 {
|
|
1253 uint32_t tickstart = 0;
|
|
1254
|
|
1255 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef* )hdma)->Parent;
|
|
1256
|
|
1257 if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
|
|
1258 {
|
|
1259 hsai->TxXferCount = 0;
|
|
1260 hsai->RxXferCount = 0;
|
|
1261
|
|
1262 /* Disable SAI Tx DMA Request */
|
|
1263 hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN);
|
|
1264
|
|
1265 /* Get tick */
|
|
1266 tickstart = HAL_GetTick();
|
|
1267
|
|
1268 /* Set timeout: 10 is the max delay to send the remaining data in the SAI FIFO */
|
|
1269 /* Wait until FIFO is empty */
|
|
1270 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FLVL) != RESET)
|
|
1271 {
|
|
1272 /* Check for the Timeout */
|
|
1273 if((HAL_GetTick() - tickstart ) > SAI_TIMEOUT_VALUE)
|
|
1274 {
|
|
1275 /* Update error code */
|
|
1276 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
|
|
1277
|
|
1278 /* Change the SAI state */
|
|
1279 HAL_SAI_ErrorCallback(hsai);
|
|
1280 }
|
|
1281 }
|
|
1282
|
|
1283 hsai->State= HAL_SAI_STATE_READY;
|
|
1284 }
|
|
1285 HAL_SAI_TxCpltCallback(hsai);
|
|
1286 }
|
|
1287
|
|
1288 /**
|
|
1289 * @brief DMA SAI transmit process half complete callback
|
|
1290 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains
|
|
1291 * the configuration information for the specified DMA module.
|
|
1292 * @retval None
|
|
1293 */
|
|
1294 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
|
|
1295 {
|
|
1296 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
|
|
1297
|
|
1298 HAL_SAI_TxHalfCpltCallback(hsai);
|
|
1299 }
|
|
1300
|
|
1301 /**
|
|
1302 * @brief DMA SAI receive process complete callback.
|
|
1303 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains
|
|
1304 * the configuration information for the specified DMA module.
|
|
1305 * @retval None
|
|
1306 */
|
|
1307 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma)
|
|
1308 {
|
|
1309 SAI_HandleTypeDef* hsai = ( SAI_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
|
|
1310 if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
|
|
1311 {
|
|
1312 /* Disable Rx DMA Request */
|
|
1313 hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN);
|
|
1314 hsai->RxXferCount = 0;
|
|
1315
|
|
1316 hsai->State = HAL_SAI_STATE_READY;
|
|
1317 }
|
|
1318 HAL_SAI_RxCpltCallback(hsai);
|
|
1319 }
|
|
1320
|
|
1321 /**
|
|
1322 * @brief DMA SAI receive process half complete callback
|
|
1323 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains
|
|
1324 * the configuration information for the specified DMA module.
|
|
1325 * @retval None
|
|
1326 */
|
|
1327 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
|
|
1328 {
|
|
1329 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
|
|
1330
|
|
1331 HAL_SAI_RxHalfCpltCallback(hsai);
|
|
1332 }
|
|
1333 /**
|
|
1334 * @brief DMA SAI communication error callback.
|
|
1335 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains
|
|
1336 * the configuration information for the specified DMA module.
|
|
1337 * @retval None
|
|
1338 */
|
|
1339 static void SAI_DMAError(DMA_HandleTypeDef *hdma)
|
|
1340 {
|
|
1341 SAI_HandleTypeDef* hsai = ( SAI_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
|
|
1342 /* Set the SAI state ready to be able to start again the process */
|
|
1343 hsai->State= HAL_SAI_STATE_READY;
|
|
1344 HAL_SAI_ErrorCallback(hsai);
|
|
1345
|
|
1346 hsai->TxXferCount = 0;
|
|
1347 hsai->RxXferCount = 0;
|
|
1348 }
|
|
1349
|
|
1350 /**
|
|
1351 * @}
|
|
1352 */
|
|
1353
|
|
1354 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
|
|
1355 #endif /* HAL_SAI_MODULE_ENABLED */
|
|
1356 /**
|
|
1357 * @}
|
|
1358 */
|
|
1359
|
|
1360 /**
|
|
1361 * @}
|
|
1362 */
|
|
1363
|
|
1364 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|