2 ******************************************************************************
3 * @file stm32f4xx_hal_sai.c
4 * @author MCD Application Team
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
16 ==============================================================================
17 ##### How to use this driver #####
18 ==============================================================================
21 The SAI HAL driver can be used as follows:
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.
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
44 (#) Program the SAI Mode, Standard, Data Format, MCLK Output, Audio frequency and Polarity
45 using HAL_SAI_Init() function.
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.
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.
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.
64 (@) In master Rx mode: enabling the audio block immediately generates the bit clock
65 and FS signal for the external slaves.
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.
75 Three operation modes are available within this driver :
77 *** Polling mode IO operation ***
78 =================================
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()
83 *** Interrupt mode IO operation ***
84 ===================================
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
95 *** DMA mode IO operation ***
96 ==============================
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()
110 *** SAI HAL driver macros list ***
111 =============================================
113 Below the list of most used macros in USART HAL driver :
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
121 (+) __HAL_SAI_GET_FLAG: Check whether the specified SAI flag is set or not
124 ******************************************************************************
127 * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
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.
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.
151 ******************************************************************************
154 /* Includes ------------------------------------------------------------------*/
155 #include "stm32f4xx_hal.h"
157 /** @addtogroup STM32F4xx_HAL_Driver
162 * @brief SAI HAL module driver
166 #ifdef HAL_SAI_MODULE_ENABLED
168 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
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)
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);
187 /* Private functions ---------------------------------------------------------*/
189 /** @defgroup SAI_Private_Functions
193 /** @defgroup SAI_Group1 Initialization and de-initialization functions
194 * @brief Initialization and Configuration functions
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:
203 (+) User must implement HAL_SAI_MspInit() function in which he configures
204 all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC ).
206 (+) Call the function HAL_SAI_Init() to configure the selected device with
207 the selected configuration:
208 (++) Mode (Master/slave TX/RX)
217 (+) Call the function HAL_SAI_DeInit() to restore the default configuration
218 of the selected SAI peripheral.
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.
231 HAL_StatusTypeDef HAL_SAI_Init(SAI_HandleTypeDef *hsai)
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;
240 /* Check the SAI handle allocation */
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));
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));
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));
271 if(hsai->State == HAL_SAI_STATE_RESET)
273 /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
274 HAL_SAI_MspInit(hsai);
277 hsai->State = HAL_SAI_STATE_BUSY;
279 /* Disable the selected SAI peripheral */
280 __HAL_SAI_DISABLE(hsai);
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 |
303 hsai->Init.OutputDrive |
304 hsai->Init.NoDivider);
305 /* Write to SAI_Block_x CR1 */
306 hsai->Instance->CR1 = tmpreg;
308 /* SAI Block_x CR2 Configuration */
309 /* Get the SAIBlock_x CR2 value */
310 tmpreg = hsai->Instance->CR2;
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;
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));
337 /* Write to SAI_Block_x FRCR */
338 hsai->Instance->FRCR = tmpreg;
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));
356 /* Write to SAI_Block_x SLOTR */
357 hsai->Instance->SLOTR = tmpreg;
359 /* SAI Block_x Clock Configuration -----------------------------------------*/
360 /* Check the Clock parameters */
361 assert_param(IS_SAI_CLK_SOURCE(hsai->Init.ClockSource));
363 /* SAI Block clock source selection */
364 if(hsai->Instance == SAI1_Block_A)
366 __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(hsai->Init.ClockSource);
370 __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG((uint32_t)(hsai->Init.ClockSource << 2));
373 /* VCO Input Clock value calculation */
374 if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI)
376 /* In Case the PLL Source is HSI (Internal Clock) */
377 vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
381 /* In Case the PLL Source is HSE (External Clock) */
382 vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)));
385 /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */
386 if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLSAI)
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);
395 /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
396 tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8) + 1);
397 saiclocksource = saiclocksource/(tmpreg);
400 else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S)
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);
409 /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
410 tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1);
411 saiclocksource = saiclocksource/(tmpreg);
413 else /* sConfig->ClockSource == SAI_CLKSource_Ext */
415 /* Enable the External Clock selection */
416 __HAL_RCC_I2SCLK(RCC_I2SCLKSOURCE_EXT);
418 saiclocksource = EXTERNAL_CLOCK_VALUE;
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_ENABLED)
427 /* (saiclocksource x 10) to keep Significant digits */
428 tmpclock = (((saiclocksource * 10) / ((hsai->Init.AudioFrequency) * 512)));
430 /* Get the result of modulo division */
431 tmp2clock = (tmpclock % 10);
433 /* Round result to the nearest integer*/
436 tmpclock = ((tmpclock / 10) + 1);
440 tmpclock = (tmpclock / 10);
442 /*Set MCKDIV value in CR1 register*/
443 hsai->Instance->CR1 |= (tmpclock << 20);
447 /* Initialise the error code */
448 hsai->ErrorCode = HAL_SAI_ERROR_NONE;
450 /* Initialize the SAI state */
451 hsai->State= HAL_SAI_STATE_READY;
457 * @brief DeInitializes the SAI peripheral.
458 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
459 * the configuration information for SAI module.
462 HAL_StatusTypeDef HAL_SAI_DeInit(SAI_HandleTypeDef *hsai)
464 /* Check the SAI handle allocation */
470 hsai->State = HAL_SAI_STATE_BUSY;
472 /* DeInit the low level hardware: GPIO, CLOCK, NVIC and DMA */
473 HAL_SAI_MspDeInit(hsai);
475 /* Initialize the error code */
476 hsai->ErrorCode = HAL_SAI_ERROR_NONE;
478 /* Initialize the SAI state */
479 hsai->State = HAL_SAI_STATE_RESET;
488 * @brief SAI MSP Init.
489 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
490 * the configuration information for SAI module.
493 __weak void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
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
501 * @brief SAI MSP DeInit.
502 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
503 * the configuration information for SAI module.
506 __weak void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai)
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
517 /** @defgroup SAI_Group2 IO operation functions
518 * @brief Data transfers functions
521 ===============================================================================
522 ##### IO operation functions #####
523 ===============================================================================
525 This subsection provides a set of functions allowing to manage the SAI data
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
538 (+) Blocking mode functions are :
539 (++) HAL_SAI_Transmit()
540 (++) HAL_SAI_Receive()
541 (++) HAL_SAI_TransmitReceive()
543 (+) Non Blocking mode functions with Interrupt are :
544 (++) HAL_SAI_Transmit_IT()
545 (++) HAL_SAI_Receive_IT()
546 (++) HAL_SAI_TransmitReceive_IT()
548 (+) Non Blocking mode functions with DMA are :
549 (++) HAL_SAI_Transmit_DMA()
550 (++) HAL_SAI_Receive_DMA()
551 (++) HAL_SAI_TransmitReceive_DMA()
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()
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
571 HAL_StatusTypeDef HAL_SAI_Transmit(SAI_HandleTypeDef *hsai, uint16_t* pData, uint16_t Size, uint32_t Timeout)
573 uint32_t tickstart = 0;
575 if((pData == HAL_NULL ) || (Size == 0))
580 if(hsai->State == HAL_SAI_STATE_READY)
585 hsai->State = HAL_SAI_STATE_BUSY_TX;
587 /* Check if the SAI is already enabled */
588 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
590 /* Enable SAI peripheral */
591 __HAL_SAI_ENABLE(hsai);
597 tickstart = HAL_GetTick();
599 /* Wait the FIFO to be empty */
600 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ) == RESET)
602 /* Check for the Timeout */
603 if(Timeout != HAL_MAX_DELAY)
605 if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
607 /* Update error code */
608 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
610 /* Process Unlocked */
613 /* Change the SAI state */
614 hsai->State = HAL_SAI_STATE_TIMEOUT;
620 hsai->Instance->DR = (*pData++);
624 hsai->State = HAL_SAI_STATE_READY;
626 /* Process Unlocked */
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
646 HAL_StatusTypeDef HAL_SAI_Receive(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size, uint32_t Timeout)
648 uint32_t tickstart = 0;
650 if((pData == HAL_NULL ) || (Size == 0))
655 if(hsai->State == HAL_SAI_STATE_READY)
660 hsai->State = HAL_SAI_STATE_BUSY_RX;
662 /* Check if the SAI is already enabled */
663 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
665 /* Enable SAI peripheral */
666 __HAL_SAI_ENABLE(hsai);
673 tickstart = HAL_GetTick();
675 /* Wait until RXNE flag is set */
676 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ) == RESET)
678 /* Check for the Timeout */
679 if(Timeout != HAL_MAX_DELAY)
681 if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
683 /* Update error code */
684 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
686 /* Process Unlocked */
689 /* Change the SAI state */
690 hsai->State = HAL_SAI_STATE_TIMEOUT;
697 (*pData++) = hsai->Instance->DR;
701 hsai->State = HAL_SAI_STATE_READY;
703 /* Process Unlocked */
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
722 HAL_StatusTypeDef HAL_SAI_Transmit_IT(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
724 if(hsai->State == HAL_SAI_STATE_READY)
726 if((pData == HAL_NULL) || (Size == 0))
731 hsai->pTxBuffPtr = pData;
732 hsai->TxXferSize = Size;
733 hsai->TxXferCount = Size;
738 hsai->State = HAL_SAI_STATE_BUSY_TX;
741 hsai->Instance->DR = (*hsai->pTxBuffPtr++);
744 /* Process Unlocked */
747 /* Enable FRQ and OVRUDR interrupts */
748 __HAL_SAI_ENABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
750 /* Check if the SAI is already enabled */
751 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
753 /* Enable SAI peripheral */
754 __HAL_SAI_ENABLE(hsai);
760 else if(hsai->State == HAL_SAI_STATE_BUSY_TX)
766 hsai->Instance->DR = (*hsai->pTxBuffPtr++);
770 if(hsai->TxXferCount == 0)
772 /* Disable FREQ and OVRUDR interrupts */
773 __HAL_SAI_DISABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
775 hsai->State = HAL_SAI_STATE_READY;
777 HAL_SAI_TxCpltCallback(hsai);
780 /* Process Unlocked */
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
800 HAL_StatusTypeDef HAL_SAI_Receive_IT(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
802 if(hsai->State == HAL_SAI_STATE_READY)
804 if((pData == HAL_NULL) || (Size == 0))
809 hsai->pRxBuffPtr = pData;
810 hsai->RxXferSize = Size;
811 hsai->RxXferCount = Size;
816 hsai->State = HAL_SAI_STATE_BUSY_RX;
818 /* Enable TXE and OVRUDR interrupts */
819 __HAL_SAI_ENABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
821 /* Check if the SAI is already enabled */
822 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
824 /* Enable SAI peripheral */
825 __HAL_SAI_ENABLE(hsai);
828 /* Process Unlocked */
833 else if(hsai->State == HAL_SAI_STATE_BUSY_RX)
839 (*hsai->pRxBuffPtr++) = hsai->Instance->DR;
843 if(hsai->RxXferCount == 0)
845 /* Disable TXE and OVRUDR interrupts */
846 __HAL_SAI_DISABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR));
848 hsai->State = HAL_SAI_STATE_READY;
849 HAL_SAI_RxCpltCallback(hsai);
852 /* Process Unlocked */
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.
870 HAL_StatusTypeDef HAL_SAI_DMAPause(SAI_HandleTypeDef *hsai)
875 /* Pause the audio file playing by disabling the SAI DMA requests */
876 hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
879 /* Process Unlocked */
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.
891 HAL_StatusTypeDef HAL_SAI_DMAResume(SAI_HandleTypeDef *hsai)
896 /* Enable the SAI DMA requests */
897 hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
900 /* If the SAI peripheral is still not enabled, enable it */
901 if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == 0)
903 /* Enable SAI peripheral */
904 __HAL_SAI_ENABLE(hsai);
907 /* Process Unlocked */
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.
919 HAL_StatusTypeDef HAL_SAI_DMAStop(SAI_HandleTypeDef *hsai)
924 /* Disable the SAI DMA request */
925 hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
927 /* Abort the SAI DMA Tx Stream */
928 if(hsai->hdmatx != HAL_NULL)
930 HAL_DMA_Abort(hsai->hdmatx);
932 /* Abort the SAI DMA Rx Stream */
933 if(hsai->hdmarx != HAL_NULL)
935 HAL_DMA_Abort(hsai->hdmarx);
938 /* Disable SAI peripheral */
939 __HAL_SAI_DISABLE(hsai);
941 hsai->State = HAL_SAI_STATE_READY;
943 /* Process Unlocked */
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
956 HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
960 if((pData == HAL_NULL) || (Size == 0))
965 if(hsai->State == HAL_SAI_STATE_READY)
967 hsai->pTxBuffPtr = pData;
968 hsai->TxXferSize = Size;
969 hsai->TxXferCount = Size;
974 hsai->State = HAL_SAI_STATE_BUSY_TX;
976 /* Set the SAI Tx DMA Half transfert complete callback */
977 hsai->hdmatx->XferHalfCpltCallback = SAI_DMATxHalfCplt;
979 /* Set the SAI TxDMA transfer complete callback */
980 hsai->hdmatx->XferCpltCallback = SAI_DMATxCplt;
982 /* Set the DMA error callback */
983 hsai->hdmatx->XferErrorCallback = SAI_DMAError;
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);
989 /* Check if the SAI is already enabled */
990 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
992 /* Enable SAI peripheral */
993 __HAL_SAI_ENABLE(hsai);
996 /* Enable SAI Tx DMA Request */
997 hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
999 /* Process Unlocked */
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
1018 HAL_StatusTypeDef HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size)
1022 if((pData == HAL_NULL) || (Size == 0))
1027 if(hsai->State == HAL_SAI_STATE_READY)
1029 hsai->pRxBuffPtr = pData;
1030 hsai->RxXferSize = Size;
1031 hsai->RxXferCount = Size;
1033 /* Process Locked */
1036 hsai->State = HAL_SAI_STATE_BUSY_RX;
1038 /* Set the SAI Rx DMA Half transfert complete callback */
1039 hsai->hdmarx->XferHalfCpltCallback = SAI_DMARxHalfCplt;
1041 /* Set the SAI Rx DMA transfert complete callback */
1042 hsai->hdmarx->XferCpltCallback = SAI_DMARxCplt;
1044 /* Set the DMA error callback */
1045 hsai->hdmarx->XferErrorCallback = SAI_DMAError;
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);
1051 /* Check if the SAI is already enabled */
1052 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN)
1054 /* Enable SAI peripheral */
1055 __HAL_SAI_ENABLE(hsai);
1058 /* Enable SAI Rx DMA Request */
1059 hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
1061 /* Process Unlocked */
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
1078 void HAL_SAI_IRQHandler(SAI_HandleTypeDef *hsai)
1080 uint32_t tmp1 = 0, tmp2 = 0;
1082 if(hsai->State == HAL_SAI_STATE_BUSY_RX)
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))
1089 HAL_SAI_Receive_IT(hsai, HAL_NULL, 0);
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))
1097 /* Change the SAI error code */
1098 hsai->ErrorCode = HAL_SAI_ERROR_OVR;
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);
1108 if(hsai->State == HAL_SAI_STATE_BUSY_TX)
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))
1115 HAL_SAI_Transmit_IT(hsai, HAL_NULL, 0);
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))
1123 /* Change the SAI error code */
1124 hsai->ErrorCode = HAL_SAI_ERROR_UDR;
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);
1136 * @brief Tx Transfer completed callbacks.
1137 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
1138 * the configuration information for SAI module.
1141 __weak void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
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
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.
1154 __weak void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
1156 /* NOTE : This function Should not be modified, when the callback is needed,
1157 the HAL_SAI_TxHalfCpltCallback could be implenetd in the user file
1162 * @brief Rx Transfer completed callbacks.
1163 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
1164 * the configuration information for SAI module.
1167 __weak void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
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
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.
1180 __weak void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
1182 /* NOTE : This function Should not be modified, when the callback is needed,
1183 the HAL_SAI_RxCpltCallback could be implenetd in the user file
1188 * @brief SAI error callbacks.
1189 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
1190 * the configuration information for SAI module.
1193 __weak void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
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
1205 /** @defgroup SAI_Group3 Peripheral State functions
1206 * @brief Peripheral State functions
1209 ===============================================================================
1210 ##### Peripheral State and Errors functions #####
1211 ===============================================================================
1213 This subsection permits to get in run-time the status of the peripheral
1221 * @brief Returns the SAI state.
1222 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
1223 * the configuration information for SAI module.
1226 HAL_SAI_StateTypeDef HAL_SAI_GetState(SAI_HandleTypeDef *hsai)
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
1237 uint32_t HAL_SAI_GetError(SAI_HandleTypeDef *hsai)
1239 return hsai->ErrorCode;
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.
1251 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma)
1253 uint32_t tickstart = 0;
1255 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef* )hdma)->Parent;
1257 if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
1259 hsai->TxXferCount = 0;
1260 hsai->RxXferCount = 0;
1262 /* Disable SAI Tx DMA Request */
1263 hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN);
1266 tickstart = HAL_GetTick();
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)
1272 /* Check for the Timeout */
1273 if((HAL_GetTick() - tickstart ) > SAI_TIMEOUT_VALUE)
1275 /* Update error code */
1276 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
1278 /* Change the SAI state */
1279 HAL_SAI_ErrorCallback(hsai);
1283 hsai->State= HAL_SAI_STATE_READY;
1285 HAL_SAI_TxCpltCallback(hsai);
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.
1294 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
1296 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
1298 HAL_SAI_TxHalfCpltCallback(hsai);
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.
1307 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma)
1309 SAI_HandleTypeDef* hsai = ( SAI_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
1310 if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0)
1312 /* Disable Rx DMA Request */
1313 hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN);
1314 hsai->RxXferCount = 0;
1316 hsai->State = HAL_SAI_STATE_READY;
1318 HAL_SAI_RxCpltCallback(hsai);
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.
1327 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
1329 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
1331 HAL_SAI_RxHalfCpltCallback(hsai);
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.
1339 static void SAI_DMAError(DMA_HandleTypeDef *hdma)
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);
1346 hsai->TxXferCount = 0;
1347 hsai->RxXferCount = 0;
1354 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
1355 #endif /* HAL_SAI_MODULE_ENABLED */
1364 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/