1 /**
2   ******************************************************************************
3   * @file    stm32f4xx_hal_sai.c
4   * @author  MCD Application Team
5   * @brief   SAI HAL module driver.
6   *          This file provides firmware functions to manage the following
7   *          functionalities of the Serial Audio Interface (SAI) peripheral:
8   *           + Initialization/de-initialization functions
9   *           + I/O operation functions
10   *           + Peripheral Control functions
11   *           + Peripheral State functions
12   *
13   ******************************************************************************
14   * @attention
15   *
16   * Copyright (c) 2017 STMicroelectronics.
17   * All rights reserved.
18   *
19   * This software is licensed under terms that can be found in the LICENSE file
20   * in the root directory of this software component.
21   * If no LICENSE file comes with this software, it is provided AS-IS.
22   *
23   ******************************************************************************
24   @verbatim
25   ==============================================================================
26                   ##### How to use this driver #####
27   ==============================================================================
28 
29   [..]
30     The SAI HAL driver can be used as follows:
31 
32     (#) Declare a SAI_HandleTypeDef handle structure (eg. SAI_HandleTypeDef hsai).
33     (#) Initialize the SAI low level resources by implementing the HAL_SAI_MspInit() API:
34         (##) Enable the SAI interface clock.
35         (##) SAI pins configuration:
36             (+++) Enable the clock for the SAI GPIOs.
37             (+++) Configure these SAI pins as alternate function pull-up.
38         (##) NVIC configuration if you need to use interrupt process (HAL_SAI_Transmit_IT()
39              and HAL_SAI_Receive_IT() APIs):
40             (+++) Configure the SAI interrupt priority.
41             (+++) Enable the NVIC SAI IRQ handle.
42 
43         (##) DMA Configuration if you need to use DMA process (HAL_SAI_Transmit_DMA()
44              and HAL_SAI_Receive_DMA() APIs):
45             (+++) Declare a DMA handle structure for the Tx/Rx stream.
46             (+++) Enable the DMAx interface clock.
47             (+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
48             (+++) Configure the DMA Tx/Rx Stream.
49             (+++) Associate the initialized DMA handle to the SAI DMA Tx/Rx handle.
50             (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the
51                 DMA Tx/Rx Stream.
52 
53     (#) The initialization can be done by two ways
54         (##) Expert mode : Initialize the structures Init, FrameInit and SlotInit and call HAL_SAI_Init().
55         (##) Simplified mode : Initialize the high part of Init Structure and call HAL_SAI_InitProtocol().
56 
57   [..]
58     (@) The specific SAI interrupts (FIFO request and Overrun underrun interrupt)
59         will be managed using the macros __HAL_SAI_ENABLE_IT() and __HAL_SAI_DISABLE_IT()
60         inside the transmit and receive process.
61 
62   [..]
63    (@) SAI Clock Source configuration is managed differently depending on the selected
64        STM32F4 devices :
65        (+@) For STM32F446xx devices, the configuration is managed through RCCEx_PeriphCLKConfig()
66             function in the HAL RCC drivers
67        (+@) For STM32F439xx/STM32F437xx/STM32F429xx/STM32F427xx devices, the configuration
68             is managed within HAL SAI drivers through HAL_SAI_Init() function using
69             ClockSource field of SAI_InitTypeDef structure.
70   [..]
71    (@) Make sure that either:
72        (+@) I2S PLL is configured or
73        (+@) SAI PLL is configured or
74        (+@) External clock source is configured after setting correctly
75             the define constant EXTERNAL_CLOCK_VALUE in the stm32f4xx_hal_conf.h file.
76   [..]
77     (@) In master Tx mode: enabling the audio block immediately generates the bit clock
78         for the external slaves even if there is no data in the FIFO, However FS signal
79         generation is conditioned by the presence of data in the FIFO.
80 
81   [..]
82     (@) In master Rx mode: enabling the audio block immediately generates the bit clock
83         and FS signal for the external slaves.
84 
85   [..]
86     (@) It is mandatory to respect the following conditions in order to avoid bad SAI behavior:
87         (+@) First bit Offset <= (SLOT size - Data size)
88         (+@) Data size <= SLOT size
89         (+@) Number of SLOT x SLOT size = Frame length
90         (+@) The number of slots should be even when SAI_FS_CHANNEL_IDENTIFICATION is selected.
91 
92   [..]
93     Three operation modes are available within this driver :
94 
95     *** Polling mode IO operation ***
96     =================================
97     [..]
98       (+) Send an amount of data in blocking mode using HAL_SAI_Transmit()
99       (+) Receive an amount of data in blocking mode using HAL_SAI_Receive()
100 
101     *** Interrupt mode IO operation ***
102     ===================================
103     [..]
104       (+) Send an amount of data in non-blocking mode using HAL_SAI_Transmit_IT()
105       (+) At transmission end of transfer HAL_SAI_TxCpltCallback() is executed and user can
106           add his own code by customization of function pointer HAL_SAI_TxCpltCallback()
107       (+) Receive an amount of data in non-blocking mode using HAL_SAI_Receive_IT()
108       (+) At reception end of transfer HAL_SAI_RxCpltCallback() is executed and user can
109           add his own code by customization of function pointer HAL_SAI_RxCpltCallback()
110       (+) In case of flag error, HAL_SAI_ErrorCallback() function is executed and user can
111           add his own code by customization of function pointer HAL_SAI_ErrorCallback()
112 
113     *** DMA mode IO operation ***
114     =============================
115     [..]
116       (+) Send an amount of data in non-blocking mode (DMA) using HAL_SAI_Transmit_DMA()
117       (+) At transmission end of transfer HAL_SAI_TxCpltCallback() is executed and user can
118           add his own code by customization of function pointer HAL_SAI_TxCpltCallback()
119       (+) Receive an amount of data in non-blocking mode (DMA) using HAL_SAI_Receive_DMA()
120       (+) At reception end of transfer HAL_SAI_RxCpltCallback() is executed and user can
121           add his own code by customization of function pointer HAL_SAI_RxCpltCallback()
122       (+) In case of flag error, HAL_SAI_ErrorCallback() function is executed and user can
123           add his own code by customization of function pointer HAL_SAI_ErrorCallback()
124       (+) Pause the DMA Transfer using HAL_SAI_DMAPause()
125       (+) Resume the DMA Transfer using HAL_SAI_DMAResume()
126       (+) Stop the DMA Transfer using HAL_SAI_DMAStop()
127 
128     *** SAI HAL driver additional function list ***
129     ===============================================
130     [..]
131       Below the list the others API available SAI HAL driver :
132 
133       (+) HAL_SAI_EnableTxMuteMode(): Enable the mute in tx mode
134       (+) HAL_SAI_DisableTxMuteMode(): Disable the mute in tx mode
135       (+) HAL_SAI_EnableRxMuteMode(): Enable the mute in Rx mode
136       (+) HAL_SAI_DisableRxMuteMode(): Disable the mute in Rx mode
137       (+) HAL_SAI_FlushRxFifo(): Flush the rx fifo.
138       (+) HAL_SAI_Abort(): Abort the current transfer
139 
140     *** SAI HAL driver macros list ***
141     ==================================
142     [..]
143       Below the list of most used macros in SAI HAL driver :
144 
145       (+) __HAL_SAI_ENABLE(): Enable the SAI peripheral
146       (+) __HAL_SAI_DISABLE(): Disable the SAI peripheral
147       (+) __HAL_SAI_ENABLE_IT(): Enable the specified SAI interrupts
148       (+) __HAL_SAI_DISABLE_IT(): Disable the specified SAI interrupts
149       (+) __HAL_SAI_GET_IT_SOURCE(): Check if the specified SAI interrupt source is
150           enabled or disabled
151       (+) __HAL_SAI_GET_FLAG(): Check whether the specified SAI flag is set or not
152 
153     *** Callback registration ***
154     =============================
155     [..]
156     The compilation define USE_HAL_SAI_REGISTER_CALLBACKS when set to 1
157     allows the user to configure dynamically the driver callbacks.
158     Use functions HAL_SAI_RegisterCallback() to register a user callback.
159 
160     [..]
161     Function HAL_SAI_RegisterCallback() allows to register following callbacks:
162       (+) RxCpltCallback     : SAI receive complete.
163       (+) RxHalfCpltCallback : SAI receive half complete.
164       (+) TxCpltCallback     : SAI transmit complete.
165       (+) TxHalfCpltCallback : SAI transmit half complete.
166       (+) ErrorCallback      : SAI error.
167       (+) MspInitCallback    : SAI MspInit.
168       (+) MspDeInitCallback  : SAI MspDeInit.
169     [..]
170     This function takes as parameters the HAL peripheral handle, the callback ID
171     and a pointer to the user callback function.
172 
173     [..]
174     Use function HAL_SAI_UnRegisterCallback() to reset a callback to the default
175     weak (surcharged) function.
176     HAL_SAI_UnRegisterCallback() takes as parameters the HAL peripheral handle,
177     and the callback ID.
178     [..]
179     This function allows to reset following callbacks:
180       (+) RxCpltCallback     : SAI receive complete.
181       (+) RxHalfCpltCallback : SAI receive half complete.
182       (+) TxCpltCallback     : SAI transmit complete.
183       (+) TxHalfCpltCallback : SAI transmit half complete.
184       (+) ErrorCallback      : SAI error.
185       (+) MspInitCallback    : SAI MspInit.
186       (+) MspDeInitCallback  : SAI MspDeInit.
187 
188     [..]
189     By default, after the HAL_SAI_Init and if the state is HAL_SAI_STATE_RESET
190     all callbacks are reset to the corresponding legacy weak (surcharged) functions:
191     examples HAL_SAI_RxCpltCallback(), HAL_SAI_ErrorCallback().
192     Exception done for MspInit and MspDeInit callbacks that are respectively
193     reset to the legacy weak (surcharged) functions in the HAL_SAI_Init
194     and HAL_SAI_DeInit only when these callbacks are null (not registered beforehand).
195     If not, MspInit or MspDeInit are not null, the HAL_SAI_Init and HAL_SAI_DeInit
196     keep and use the user MspInit/MspDeInit callbacks (registered beforehand).
197 
198     [..]
199     Callbacks can be registered/unregistered in READY state only.
200     Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered
201     in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used
202     during the Init/DeInit.
203     In that case first register the MspInit/MspDeInit user callbacks
204     using HAL_SAI_RegisterCallback before calling HAL_SAI_DeInit
205     or HAL_SAI_Init function.
206 
207     [..]
208     When the compilation define USE_HAL_SAI_REGISTER_CALLBACKS is set to 0 or
209     not defined, the callback registering feature is not available
210     and weak (surcharged) callbacks are used.
211 
212   @endverbatim
213   */
214 
215 /* Includes ------------------------------------------------------------------*/
216 #include "stm32f4xx_hal.h"
217 
218 /** @addtogroup STM32F4xx_HAL_Driver
219   * @{
220   */
221 
222 /** @defgroup SAI SAI
223   * @brief SAI HAL module driver
224   * @{
225   */
226 
227 #ifdef HAL_SAI_MODULE_ENABLED
228 
229 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\
230     defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) ||\
231     defined(STM32F423xx)
232 
233 /** @defgroup SAI_Private_Typedefs  SAI Private Typedefs
234   * @{
235   */
236 typedef enum
237 {
238   SAI_MODE_DMA,
239   SAI_MODE_IT
240 } SAI_ModeTypedef;
241 /**
242   * @}
243   */
244 
245 /* Private define ------------------------------------------------------------*/
246 
247 /** @defgroup SAI_Private_Constants  SAI Private Constants
248   * @{
249   */
250 #define SAI_DEFAULT_TIMEOUT   4U /* 4ms */
251 #define SAI_LONG_TIMEOUT      1000U /* 1s */
252 /**
253   * @}
254   */
255 
256 /* Private macro -------------------------------------------------------------*/
257 /* Private variables ---------------------------------------------------------*/
258 /* Private function prototypes -----------------------------------------------*/
259 /** @defgroup SAI_Private_Functions  SAI Private Functions
260   * @{
261   */
262 static void SAI_FillFifo(SAI_HandleTypeDef *hsai);
263 static uint32_t SAI_InterruptFlag(SAI_HandleTypeDef *hsai, uint32_t mode);
264 static HAL_StatusTypeDef SAI_InitI2S(SAI_HandleTypeDef *hsai, uint32_t protocol, uint32_t datasize, uint32_t nbslot);
265 static HAL_StatusTypeDef SAI_InitPCM(SAI_HandleTypeDef *hsai, uint32_t protocol, uint32_t datasize, uint32_t nbslot);
266 
267 static HAL_StatusTypeDef SAI_Disable(SAI_HandleTypeDef *hsai);
268 static void SAI_Transmit_IT8Bit(SAI_HandleTypeDef *hsai);
269 static void SAI_Transmit_IT16Bit(SAI_HandleTypeDef *hsai);
270 static void SAI_Transmit_IT32Bit(SAI_HandleTypeDef *hsai);
271 static void SAI_Receive_IT8Bit(SAI_HandleTypeDef *hsai);
272 static void SAI_Receive_IT16Bit(SAI_HandleTypeDef *hsai);
273 static void SAI_Receive_IT32Bit(SAI_HandleTypeDef *hsai);
274 
275 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma);
276 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma);
277 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma);
278 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma);
279 static void SAI_DMAError(DMA_HandleTypeDef *hdma);
280 static void SAI_DMAAbort(DMA_HandleTypeDef *hdma);
281 /**
282   * @}
283   */
284 
285 /* Exported functions ---------------------------------------------------------*/
286 /** @defgroup SAI_Exported_Functions SAI Exported Functions
287   * @{
288   */
289 
290 /** @defgroup SAI_Exported_Functions_Group1 Initialization and de-initialization functions
291   * @brief    Initialization and Configuration functions
292   *
293 @verbatim
294  ===============================================================================
295             ##### Initialization and de-initialization functions #####
296  ===============================================================================
297   [..]  This subsection provides a set of functions allowing to initialize and
298         de-initialize the SAIx peripheral:
299 
300       (+) User must implement HAL_SAI_MspInit() function in which he configures
301           all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC ).
302 
303       (+) Call the function HAL_SAI_Init() to configure the selected device with
304           the selected configuration:
305         (++) Mode (Master/slave TX/RX)
306         (++) Protocol
307         (++) Data Size
308         (++) MCLK Output
309         (++) Audio frequency
310         (++) FIFO Threshold
311         (++) Frame Config
312         (++) Slot Config
313 
314       (+) Call the function HAL_SAI_DeInit() to restore the default configuration
315           of the selected SAI peripheral.
316 
317 @endverbatim
318   * @{
319   */
320 
321 /**
322   * @brief  Initialize the structure FrameInit, SlotInit and the low part of
323   *         Init according to the specified parameters and call the function
324   *         HAL_SAI_Init to initialize the SAI block.
325   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
326   *               the configuration information for SAI module.
327   * @param  protocol one of the supported protocol @ref SAI_Protocol
328   * @param  datasize one of the supported datasize @ref SAI_Protocol_DataSize
329   *                   the configuration information for SAI module.
330   * @param  nbslot Number of slot.
331   * @retval HAL status
332   */
HAL_SAI_InitProtocol(SAI_HandleTypeDef * hsai,uint32_t protocol,uint32_t datasize,uint32_t nbslot)333 HAL_StatusTypeDef HAL_SAI_InitProtocol(SAI_HandleTypeDef *hsai, uint32_t protocol, uint32_t datasize, uint32_t nbslot)
334 {
335   HAL_StatusTypeDef status = HAL_OK;
336 
337   /* Check the parameters */
338   assert_param(IS_SAI_SUPPORTED_PROTOCOL(protocol));
339   assert_param(IS_SAI_PROTOCOL_DATASIZE(datasize));
340 
341   switch (protocol)
342   {
343     case SAI_I2S_STANDARD :
344     case SAI_I2S_MSBJUSTIFIED :
345     case SAI_I2S_LSBJUSTIFIED :
346       status = SAI_InitI2S(hsai, protocol, datasize, nbslot);
347       break;
348     case SAI_PCM_LONG :
349     case SAI_PCM_SHORT :
350       status = SAI_InitPCM(hsai, protocol, datasize, nbslot);
351       break;
352     default :
353       status = HAL_ERROR;
354       break;
355   }
356 
357   if (status == HAL_OK)
358   {
359     status = HAL_SAI_Init(hsai);
360   }
361 
362   return status;
363 }
364 
365 /**
366   * @brief  Initialize the SAI according to the specified parameters.
367   *         in the SAI_InitTypeDef structure and initialize the associated handle.
368   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
369   *               the configuration information for SAI module.
370   * @retval HAL status
371   */
HAL_SAI_Init(SAI_HandleTypeDef * hsai)372 HAL_StatusTypeDef HAL_SAI_Init(SAI_HandleTypeDef *hsai)
373 {
374   uint32_t tmpregisterGCR = 0U;
375 
376   /* This variable used to store the SAI_CK_x (value in Hz) */
377   uint32_t freq = 0U;
378 
379   /* This variable is used to compute CKSTR bits of SAI CR1 according to
380      ClockStrobing and AudioMode fields */
381   uint32_t ckstr_bits = 0U;
382   uint32_t syncen_bits = 0U;
383 
384   /* Check the SAI handle allocation */
385   if (hsai == NULL)
386   {
387     return HAL_ERROR;
388   }
389 
390   /* check the instance */
391   assert_param(IS_SAI_ALL_INSTANCE(hsai->Instance));
392 
393   /* Check the SAI Block parameters */
394   assert_param(IS_SAI_AUDIO_FREQUENCY(hsai->Init.AudioFrequency));
395   assert_param(IS_SAI_BLOCK_PROTOCOL(hsai->Init.Protocol));
396   assert_param(IS_SAI_BLOCK_MODE(hsai->Init.AudioMode));
397   assert_param(IS_SAI_BLOCK_SYNCEXT(hsai->Init.SynchroExt));
398   assert_param(IS_SAI_BLOCK_DATASIZE(hsai->Init.DataSize));
399   assert_param(IS_SAI_BLOCK_FIRST_BIT(hsai->Init.FirstBit));
400   assert_param(IS_SAI_BLOCK_CLOCK_STROBING(hsai->Init.ClockStrobing));
401   assert_param(IS_SAI_BLOCK_SYNCHRO(hsai->Init.Synchro));
402   assert_param(IS_SAI_BLOCK_OUTPUT_DRIVE(hsai->Init.OutputDrive));
403   assert_param(IS_SAI_BLOCK_NODIVIDER(hsai->Init.NoDivider));
404   assert_param(IS_SAI_BLOCK_FIFO_THRESHOLD(hsai->Init.FIFOThreshold));
405   assert_param(IS_SAI_MONO_STEREO_MODE(hsai->Init.MonoStereoMode));
406   assert_param(IS_SAI_BLOCK_COMPANDING_MODE(hsai->Init.CompandingMode));
407   assert_param(IS_SAI_BLOCK_TRISTATE_MANAGEMENT(hsai->Init.TriState));
408 
409   /* Check the SAI Block Frame parameters */
410   assert_param(IS_SAI_BLOCK_FRAME_LENGTH(hsai->FrameInit.FrameLength));
411   assert_param(IS_SAI_BLOCK_ACTIVE_FRAME(hsai->FrameInit.ActiveFrameLength));
412   assert_param(IS_SAI_BLOCK_FS_DEFINITION(hsai->FrameInit.FSDefinition));
413   assert_param(IS_SAI_BLOCK_FS_POLARITY(hsai->FrameInit.FSPolarity));
414   assert_param(IS_SAI_BLOCK_FS_OFFSET(hsai->FrameInit.FSOffset));
415 
416   /* Check the SAI Block Slot parameters */
417   assert_param(IS_SAI_BLOCK_FIRSTBIT_OFFSET(hsai->SlotInit.FirstBitOffset));
418   assert_param(IS_SAI_BLOCK_SLOT_SIZE(hsai->SlotInit.SlotSize));
419   assert_param(IS_SAI_BLOCK_SLOT_NUMBER(hsai->SlotInit.SlotNumber));
420   assert_param(IS_SAI_SLOT_ACTIVE(hsai->SlotInit.SlotActive));
421 
422   if (hsai->State == HAL_SAI_STATE_RESET)
423   {
424     /* Allocate lock resource and initialize it */
425     hsai->Lock = HAL_UNLOCKED;
426 
427 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
428     /* Reset callback pointers to the weak predefined callbacks */
429     hsai->RxCpltCallback     = HAL_SAI_RxCpltCallback;
430     hsai->RxHalfCpltCallback = HAL_SAI_RxHalfCpltCallback;
431     hsai->TxCpltCallback     = HAL_SAI_TxCpltCallback;
432     hsai->TxHalfCpltCallback = HAL_SAI_TxHalfCpltCallback;
433     hsai->ErrorCallback      = HAL_SAI_ErrorCallback;
434 
435     /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
436     if (hsai->MspInitCallback == NULL)
437     {
438       hsai->MspInitCallback = HAL_SAI_MspInit;
439     }
440     hsai->MspInitCallback(hsai);
441 #else
442     /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
443     HAL_SAI_MspInit(hsai);
444 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
445   }
446 
447   hsai->State = HAL_SAI_STATE_BUSY;
448 
449   /* Disable the selected SAI peripheral */
450   SAI_Disable(hsai);
451 
452   /* SAI Block Synchro Configuration -----------------------------------------*/
453   SAI_BlockSynchroConfig(hsai);
454 
455   /* Configure Master Clock using the following formula :
456      MCLK_x = SAI_CK_x / (MCKDIV[3:0] * 2) with MCLK_x = 256 * FS
457      FS = SAI_CK_x / (MCKDIV[3:0] * 2) * 256
458      MCKDIV[3:0] = SAI_CK_x / FS * 512 */
459   if (hsai->Init.AudioFrequency != SAI_AUDIO_FREQUENCY_MCKDIV)
460   {
461     /* Get SAI clock source based on Source clock selection from RCC */
462     freq = SAI_GetInputClock(hsai);
463 
464     /* (saiclocksource x 10) to keep Significant digits */
465     tmpregisterGCR = (((freq * 10U) / ((hsai->Init.AudioFrequency) * 512U)));
466 
467     hsai->Init.Mckdiv = tmpregisterGCR / 10U;
468 
469     /* Round result to the nearest integer */
470     if ((tmpregisterGCR % 10U) > 8U)
471     {
472       hsai->Init.Mckdiv += 1U;
473     }
474 
475     /* For SPDIF protocol, SAI shall provide a bit clock twice faster the symbol-rate */
476     if (hsai->Init.Protocol == SAI_SPDIF_PROTOCOL)
477     {
478       hsai->Init.Mckdiv = hsai->Init.Mckdiv >> 1;
479     }
480   }
481 
482   /* Check the SAI Block master clock divider parameter */
483   assert_param(IS_SAI_BLOCK_MASTER_DIVIDER(hsai->Init.Mckdiv));
484 
485   /* Compute CKSTR bits of SAI CR1 according to ClockStrobing and AudioMode */
486   if ((hsai->Init.AudioMode == SAI_MODEMASTER_TX) || (hsai->Init.AudioMode == SAI_MODESLAVE_TX))
487   {
488     ckstr_bits = (hsai->Init.ClockStrobing == SAI_CLOCKSTROBING_RISINGEDGE) ? 0U : SAI_xCR1_CKSTR;
489   }
490   else
491   {
492     ckstr_bits = (hsai->Init.ClockStrobing == SAI_CLOCKSTROBING_RISINGEDGE) ? SAI_xCR1_CKSTR : 0U;
493   }
494 
495   /* SAI Block Configuration -------------------------------------------------*/
496   switch (hsai->Init.Synchro)
497   {
498     case SAI_ASYNCHRONOUS :
499     {
500       syncen_bits = 0U;
501     }
502     break;
503     case SAI_SYNCHRONOUS :
504     {
505       syncen_bits = SAI_xCR1_SYNCEN_0;
506     }
507     break;
508     case SAI_SYNCHRONOUS_EXT_SAI1 :
509     case SAI_SYNCHRONOUS_EXT_SAI2 :
510     {
511       syncen_bits = SAI_xCR1_SYNCEN_1;
512     }
513     break;
514     default:
515       break;
516   }
517 
518   /* SAI CR1 Configuration */
519   hsai->Instance->CR1 &= ~(SAI_xCR1_MODE | SAI_xCR1_PRTCFG |  SAI_xCR1_DS |      \
520                            SAI_xCR1_LSBFIRST | SAI_xCR1_CKSTR | SAI_xCR1_SYNCEN | \
521                            SAI_xCR1_MONO | SAI_xCR1_OUTDRIV  | SAI_xCR1_DMAEN |  \
522                            SAI_xCR1_NODIV | SAI_xCR1_MCKDIV);
523 
524   hsai->Instance->CR1 |= (hsai->Init.AudioMode | hsai->Init.Protocol |           \
525                           hsai->Init.DataSize | hsai->Init.FirstBit  |           \
526                           ckstr_bits | syncen_bits |                             \
527                           hsai->Init.MonoStereoMode | hsai->Init.OutputDrive |   \
528                           hsai->Init.NoDivider | (hsai->Init.Mckdiv << 20U));
529 
530   /* SAI CR2 Configuration */
531   hsai->Instance->CR2 &= ~(SAI_xCR2_FTH | SAI_xCR2_FFLUSH | SAI_xCR2_COMP | SAI_xCR2_CPL);
532   hsai->Instance->CR2 |= (hsai->Init.FIFOThreshold | hsai->Init.CompandingMode | hsai->Init.TriState);
533 
534   /* SAI Frame Configuration -----------------------------------------*/
535   hsai->Instance->FRCR &= (~(SAI_xFRCR_FRL | SAI_xFRCR_FSALL | SAI_xFRCR_FSDEF | \
536                              SAI_xFRCR_FSPOL | SAI_xFRCR_FSOFF));
537   hsai->Instance->FRCR |= ((hsai->FrameInit.FrameLength - 1U) |
538                            hsai->FrameInit.FSOffset     |
539                            hsai->FrameInit.FSDefinition |
540                            hsai->FrameInit.FSPolarity   |
541                            ((hsai->FrameInit.ActiveFrameLength - 1U) << 8U));
542 
543   /* SAI Block_x SLOT Configuration ------------------------------------------*/
544   /* This register has no meaning in AC 97 and SPDIF audio protocol */
545   hsai->Instance->SLOTR &= ~(SAI_xSLOTR_FBOFF | SAI_xSLOTR_SLOTSZ | \
546                              SAI_xSLOTR_NBSLOT | SAI_xSLOTR_SLOTEN);
547 
548   hsai->Instance->SLOTR |=  hsai->SlotInit.FirstBitOffset |  hsai->SlotInit.SlotSize  | \
549                             (hsai->SlotInit.SlotActive << 16U) | ((hsai->SlotInit.SlotNumber - 1U) <<  8U);
550 
551   /* Initialize the error code */
552   hsai->ErrorCode = HAL_SAI_ERROR_NONE;
553 
554   /* Initialize the SAI state */
555   hsai->State = HAL_SAI_STATE_READY;
556 
557   /* Release Lock */
558   __HAL_UNLOCK(hsai);
559 
560   return HAL_OK;
561 }
562 
563 /**
564   * @brief  DeInitialize the SAI peripheral.
565   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
566   *               the configuration information for SAI module.
567   * @retval HAL status
568   */
HAL_SAI_DeInit(SAI_HandleTypeDef * hsai)569 HAL_StatusTypeDef HAL_SAI_DeInit(SAI_HandleTypeDef *hsai)
570 {
571   /* Check the SAI handle allocation */
572   if (hsai == NULL)
573   {
574     return HAL_ERROR;
575   }
576 
577   hsai->State = HAL_SAI_STATE_BUSY;
578 
579   /* Disabled All interrupt and clear all the flag */
580   hsai->Instance->IMR = 0U;
581   hsai->Instance->CLRFR = 0xFFFFFFFFU;
582 
583   /* Disable the SAI */
584   SAI_Disable(hsai);
585 
586   /* Flush the fifo */
587   SET_BIT(hsai->Instance->CR2, SAI_xCR2_FFLUSH);
588 
589   /* DeInit the low level hardware: GPIO, CLOCK, NVIC and DMA */
590 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
591   if (hsai->MspDeInitCallback == NULL)
592   {
593     hsai->MspDeInitCallback = HAL_SAI_MspDeInit;
594   }
595   hsai->MspDeInitCallback(hsai);
596 #else
597   HAL_SAI_MspDeInit(hsai);
598 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
599 
600   /* Initialize the error code */
601   hsai->ErrorCode = HAL_SAI_ERROR_NONE;
602 
603   /* Initialize the SAI state */
604   hsai->State = HAL_SAI_STATE_RESET;
605 
606   /* Release Lock */
607   __HAL_UNLOCK(hsai);
608 
609   return HAL_OK;
610 }
611 
612 /**
613   * @brief Initialize the SAI MSP.
614   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
615   *               the configuration information for SAI module.
616   * @retval None
617   */
HAL_SAI_MspInit(SAI_HandleTypeDef * hsai)618 __weak void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai)
619 {
620   /* Prevent unused argument(s) compilation warning */
621   UNUSED(hsai);
622 
623   /* NOTE : This function should not be modified, when the callback is needed,
624             the HAL_SAI_MspInit could be implemented in the user file
625    */
626 }
627 
628 /**
629   * @brief DeInitialize the SAI MSP.
630   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
631   *               the configuration information for SAI module.
632   * @retval None
633   */
HAL_SAI_MspDeInit(SAI_HandleTypeDef * hsai)634 __weak void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai)
635 {
636   /* Prevent unused argument(s) compilation warning */
637   UNUSED(hsai);
638 
639   /* NOTE : This function should not be modified, when the callback is needed,
640             the HAL_SAI_MspDeInit could be implemented in the user file
641    */
642 }
643 
644 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
645 /**
646   * @brief  Register a user SAI callback
647   *         to be used instead of the weak predefined callback.
648   * @param  hsai SAI handle.
649   * @param  CallbackID ID of the callback to be registered.
650   *         This parameter can be one of the following values:
651   *           @arg @ref HAL_SAI_RX_COMPLETE_CB_ID receive complete callback ID.
652   *           @arg @ref HAL_SAI_RX_HALFCOMPLETE_CB_ID receive half complete callback ID.
653   *           @arg @ref HAL_SAI_TX_COMPLETE_CB_ID transmit complete callback ID.
654   *           @arg @ref HAL_SAI_TX_HALFCOMPLETE_CB_ID transmit half complete callback ID.
655   *           @arg @ref HAL_SAI_ERROR_CB_ID error callback ID.
656   *           @arg @ref HAL_SAI_MSPINIT_CB_ID MSP init callback ID.
657   *           @arg @ref HAL_SAI_MSPDEINIT_CB_ID MSP de-init callback ID.
658   * @param  pCallback pointer to the callback function.
659   * @retval HAL status.
660   */
HAL_SAI_RegisterCallback(SAI_HandleTypeDef * hsai,HAL_SAI_CallbackIDTypeDef CallbackID,pSAI_CallbackTypeDef pCallback)661 HAL_StatusTypeDef HAL_SAI_RegisterCallback(SAI_HandleTypeDef        *hsai,
662                                            HAL_SAI_CallbackIDTypeDef CallbackID,
663                                            pSAI_CallbackTypeDef      pCallback)
664 {
665   HAL_StatusTypeDef status = HAL_OK;
666 
667   if (pCallback == NULL)
668   {
669     /* update the error code */
670     hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
671     /* update return status */
672     status = HAL_ERROR;
673   }
674   else
675   {
676     if (HAL_SAI_STATE_READY == hsai->State)
677     {
678       switch (CallbackID)
679       {
680         case HAL_SAI_RX_COMPLETE_CB_ID :
681           hsai->RxCpltCallback = pCallback;
682           break;
683         case HAL_SAI_RX_HALFCOMPLETE_CB_ID :
684           hsai->RxHalfCpltCallback = pCallback;
685           break;
686         case HAL_SAI_TX_COMPLETE_CB_ID :
687           hsai->TxCpltCallback = pCallback;
688           break;
689         case HAL_SAI_TX_HALFCOMPLETE_CB_ID :
690           hsai->TxHalfCpltCallback = pCallback;
691           break;
692         case HAL_SAI_ERROR_CB_ID :
693           hsai->ErrorCallback = pCallback;
694           break;
695         case HAL_SAI_MSPINIT_CB_ID :
696           hsai->MspInitCallback = pCallback;
697           break;
698         case HAL_SAI_MSPDEINIT_CB_ID :
699           hsai->MspDeInitCallback = pCallback;
700           break;
701         default :
702           /* update the error code */
703           hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
704           /* update return status */
705           status = HAL_ERROR;
706           break;
707       }
708     }
709     else if (HAL_SAI_STATE_RESET == hsai->State)
710     {
711       switch (CallbackID)
712       {
713         case HAL_SAI_MSPINIT_CB_ID :
714           hsai->MspInitCallback = pCallback;
715           break;
716         case HAL_SAI_MSPDEINIT_CB_ID :
717           hsai->MspDeInitCallback = pCallback;
718           break;
719         default :
720           /* update the error code */
721           hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
722           /* update return status */
723           status = HAL_ERROR;
724           break;
725       }
726     }
727     else
728     {
729       /* update the error code */
730       hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
731       /* update return status */
732       status = HAL_ERROR;
733     }
734   }
735   return status;
736 }
737 
738 /**
739   * @brief  Unregister a user SAI callback.
740   *         SAI callback is redirected to the weak predefined callback.
741   * @param  hsai SAI handle.
742   * @param  CallbackID ID of the callback to be unregistered.
743   *         This parameter can be one of the following values:
744   *           @arg @ref HAL_SAI_RX_COMPLETE_CB_ID receive complete callback ID.
745   *           @arg @ref HAL_SAI_RX_HALFCOMPLETE_CB_ID receive half complete callback ID.
746   *           @arg @ref HAL_SAI_TX_COMPLETE_CB_ID transmit complete callback ID.
747   *           @arg @ref HAL_SAI_TX_HALFCOMPLETE_CB_ID transmit half complete callback ID.
748   *           @arg @ref HAL_SAI_ERROR_CB_ID error callback ID.
749   *           @arg @ref HAL_SAI_MSPINIT_CB_ID MSP init callback ID.
750   *           @arg @ref HAL_SAI_MSPDEINIT_CB_ID MSP de-init callback ID.
751   * @retval HAL status.
752   */
HAL_SAI_UnRegisterCallback(SAI_HandleTypeDef * hsai,HAL_SAI_CallbackIDTypeDef CallbackID)753 HAL_StatusTypeDef HAL_SAI_UnRegisterCallback(SAI_HandleTypeDef        *hsai,
754                                              HAL_SAI_CallbackIDTypeDef CallbackID)
755 {
756   HAL_StatusTypeDef status = HAL_OK;
757 
758   if (HAL_SAI_STATE_READY == hsai->State)
759   {
760     switch (CallbackID)
761     {
762       case HAL_SAI_RX_COMPLETE_CB_ID :
763         hsai->RxCpltCallback = HAL_SAI_RxCpltCallback;
764         break;
765       case HAL_SAI_RX_HALFCOMPLETE_CB_ID :
766         hsai->RxHalfCpltCallback = HAL_SAI_RxHalfCpltCallback;
767         break;
768       case HAL_SAI_TX_COMPLETE_CB_ID :
769         hsai->TxCpltCallback = HAL_SAI_TxCpltCallback;
770         break;
771       case HAL_SAI_TX_HALFCOMPLETE_CB_ID :
772         hsai->TxHalfCpltCallback = HAL_SAI_TxHalfCpltCallback;
773         break;
774       case HAL_SAI_ERROR_CB_ID :
775         hsai->ErrorCallback = HAL_SAI_ErrorCallback;
776         break;
777       case HAL_SAI_MSPINIT_CB_ID :
778         hsai->MspInitCallback = HAL_SAI_MspInit;
779         break;
780       case HAL_SAI_MSPDEINIT_CB_ID :
781         hsai->MspDeInitCallback = HAL_SAI_MspDeInit;
782         break;
783       default :
784         /* update the error code */
785         hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
786         /* update return status */
787         status = HAL_ERROR;
788         break;
789     }
790   }
791   else if (HAL_SAI_STATE_RESET == hsai->State)
792   {
793     switch (CallbackID)
794     {
795       case HAL_SAI_MSPINIT_CB_ID :
796         hsai->MspInitCallback = HAL_SAI_MspInit;
797         break;
798       case HAL_SAI_MSPDEINIT_CB_ID :
799         hsai->MspDeInitCallback = HAL_SAI_MspDeInit;
800         break;
801       default :
802         /* update the error code */
803         hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
804         /* update return status */
805         status = HAL_ERROR;
806         break;
807     }
808   }
809   else
810   {
811     /* update the error code */
812     hsai->ErrorCode |= HAL_SAI_ERROR_INVALID_CALLBACK;
813     /* update return status */
814     status = HAL_ERROR;
815   }
816   return status;
817 }
818 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
819 
820 /**
821   * @}
822   */
823 
824 /** @defgroup SAI_Exported_Functions_Group2 IO operation functions
825   * @brief    Data transfers functions
826   *
827 @verbatim
828   ==============================================================================
829                       ##### IO operation functions #####
830   ==============================================================================
831   [..]
832     This subsection provides a set of functions allowing to manage the SAI data
833     transfers.
834 
835     (+) There are two modes of transfer:
836       (++) Blocking mode : The communication is performed in the polling mode.
837            The status of all data processing is returned by the same function
838            after finishing transfer.
839       (++) No-Blocking mode : The communication is performed using Interrupts
840            or DMA. These functions return the status of the transfer startup.
841            The end of the data processing will be indicated through the
842            dedicated SAI IRQ when using Interrupt mode or the DMA IRQ when
843            using DMA mode.
844 
845     (+) Blocking mode functions are :
846       (++) HAL_SAI_Transmit()
847       (++) HAL_SAI_Receive()
848 
849     (+) Non Blocking mode functions with Interrupt are :
850       (++) HAL_SAI_Transmit_IT()
851       (++) HAL_SAI_Receive_IT()
852 
853     (+) Non Blocking mode functions with DMA are :
854       (++) HAL_SAI_Transmit_DMA()
855       (++) HAL_SAI_Receive_DMA()
856 
857     (+) A set of Transfer Complete Callbacks are provided in non Blocking mode:
858       (++) HAL_SAI_TxCpltCallback()
859       (++) HAL_SAI_RxCpltCallback()
860       (++) HAL_SAI_ErrorCallback()
861 
862 @endverbatim
863   * @{
864   */
865 
866 /**
867   * @brief  Transmit an amount of data in blocking mode.
868   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
869   *               the configuration information for SAI module.
870   * @param  pData Pointer to data buffer
871   * @param  Size Amount of data to be sent
872   * @param  Timeout Timeout duration
873   * @retval HAL status
874   */
HAL_SAI_Transmit(SAI_HandleTypeDef * hsai,uint8_t * pData,uint16_t Size,uint32_t Timeout)875 HAL_StatusTypeDef HAL_SAI_Transmit(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size, uint32_t Timeout)
876 {
877   uint32_t tickstart = HAL_GetTick();
878 
879   if ((pData == NULL) || (Size == 0))
880   {
881     return  HAL_ERROR;
882   }
883 
884   if (hsai->State == HAL_SAI_STATE_READY)
885   {
886     /* Process Locked */
887     __HAL_LOCK(hsai);
888 
889     hsai->XferSize = Size;
890     hsai->XferCount = Size;
891     hsai->pBuffPtr = pData;
892     hsai->State = HAL_SAI_STATE_BUSY_TX;
893     hsai->ErrorCode = HAL_SAI_ERROR_NONE;
894 
895     /* Check if the SAI is already enabled */
896     if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
897     {
898       /* fill the fifo with data before to enabled the SAI */
899       SAI_FillFifo(hsai);
900       /* Enable SAI peripheral */
901       __HAL_SAI_ENABLE(hsai);
902     }
903 
904     while (hsai->XferCount > 0U)
905     {
906       /* Write data if the FIFO is not full */
907       if ((hsai->Instance->SR & SAI_xSR_FLVL) != SAI_FIFOSTATUS_FULL)
908       {
909         if ((hsai->Init.DataSize == SAI_DATASIZE_8) && (hsai->Init.CompandingMode == SAI_NOCOMPANDING))
910         {
911           hsai->Instance->DR = (*hsai->pBuffPtr++);
912         }
913         else if (hsai->Init.DataSize <= SAI_DATASIZE_16)
914         {
915           hsai->Instance->DR = *((uint16_t *)hsai->pBuffPtr);
916           hsai->pBuffPtr += 2U;
917         }
918         else
919         {
920           hsai->Instance->DR = *((uint32_t *)hsai->pBuffPtr);
921           hsai->pBuffPtr += 4U;
922         }
923         hsai->XferCount--;
924       }
925       else
926       {
927         /* Check for the Timeout */
928         if ((Timeout != HAL_MAX_DELAY) && ((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout)))
929         {
930           /* Update error code */
931           hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
932 
933           /* Clear all the flags */
934           hsai->Instance->CLRFR = 0xFFFFFFFFU;
935 
936           /* Disable SAI peripheral */
937           SAI_Disable(hsai);
938 
939           /* Flush the fifo */
940           SET_BIT(hsai->Instance->CR2, SAI_xCR2_FFLUSH);
941 
942           /* Change the SAI state */
943           hsai->State = HAL_SAI_STATE_READY;
944 
945           /* Process Unlocked */
946           __HAL_UNLOCK(hsai);
947 
948           return HAL_ERROR;
949         }
950       }
951     }
952 
953     hsai->State = HAL_SAI_STATE_READY;
954 
955     /* Process Unlocked */
956     __HAL_UNLOCK(hsai);
957 
958     return HAL_OK;
959   }
960   else
961   {
962     return HAL_BUSY;
963   }
964 }
965 
966 /**
967   * @brief  Receive an amount of data in blocking mode.
968   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
969   *               the configuration information for SAI module.
970   * @param  pData Pointer to data buffer
971   * @param  Size Amount of data to be received
972   * @param  Timeout Timeout duration
973   * @retval HAL status
974   */
HAL_SAI_Receive(SAI_HandleTypeDef * hsai,uint8_t * pData,uint16_t Size,uint32_t Timeout)975 HAL_StatusTypeDef HAL_SAI_Receive(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size, uint32_t Timeout)
976 {
977   uint32_t tickstart = HAL_GetTick();
978 
979   if ((pData == NULL) || (Size == 0))
980   {
981     return  HAL_ERROR;
982   }
983 
984   if (hsai->State == HAL_SAI_STATE_READY)
985   {
986     /* Process Locked */
987     __HAL_LOCK(hsai);
988 
989     hsai->pBuffPtr = pData;
990     hsai->XferSize = Size;
991     hsai->XferCount = Size;
992     hsai->State = HAL_SAI_STATE_BUSY_RX;
993     hsai->ErrorCode = HAL_SAI_ERROR_NONE;
994 
995     /* Check if the SAI is already enabled */
996     if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
997     {
998       /* Enable SAI peripheral */
999       __HAL_SAI_ENABLE(hsai);
1000     }
1001 
1002     /* Receive data */
1003     while (hsai->XferCount > 0U)
1004     {
1005       if ((hsai->Instance->SR & SAI_xSR_FLVL) != SAI_FIFOSTATUS_EMPTY)
1006       {
1007         if ((hsai->Init.DataSize == SAI_DATASIZE_8) && (hsai->Init.CompandingMode == SAI_NOCOMPANDING))
1008         {
1009           (*hsai->pBuffPtr++) = hsai->Instance->DR;
1010         }
1011         else if (hsai->Init.DataSize <= SAI_DATASIZE_16)
1012         {
1013           *((uint16_t *)hsai->pBuffPtr) = hsai->Instance->DR;
1014           hsai->pBuffPtr += 2U;
1015         }
1016         else
1017         {
1018           *((uint32_t *)hsai->pBuffPtr) = hsai->Instance->DR;
1019           hsai->pBuffPtr += 4U;
1020         }
1021         hsai->XferCount--;
1022       }
1023       else
1024       {
1025         /* Check for the Timeout */
1026         if ((Timeout != HAL_MAX_DELAY) && ((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout)))
1027         {
1028           /* Update error code */
1029           hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
1030 
1031           /* Clear all the flags */
1032           hsai->Instance->CLRFR = 0xFFFFFFFFU;
1033 
1034           /* Disable SAI peripheral */
1035           SAI_Disable(hsai);
1036 
1037           /* Flush the fifo */
1038           SET_BIT(hsai->Instance->CR2, SAI_xCR2_FFLUSH);
1039 
1040           /* Change the SAI state */
1041           hsai->State = HAL_SAI_STATE_READY;
1042 
1043           /* Process Unlocked */
1044           __HAL_UNLOCK(hsai);
1045 
1046           return HAL_ERROR;
1047         }
1048       }
1049     }
1050 
1051     hsai->State = HAL_SAI_STATE_READY;
1052 
1053     /* Process Unlocked */
1054     __HAL_UNLOCK(hsai);
1055 
1056     return HAL_OK;
1057   }
1058   else
1059   {
1060     return HAL_BUSY;
1061   }
1062 }
1063 
1064 /**
1065   * @brief  Transmit an amount of data in non-blocking mode with Interrupt.
1066   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1067   *               the configuration information for SAI module.
1068   * @param  pData Pointer to data buffer
1069   * @param  Size Amount of data to be sent
1070   * @retval HAL status
1071   */
HAL_SAI_Transmit_IT(SAI_HandleTypeDef * hsai,uint8_t * pData,uint16_t Size)1072 HAL_StatusTypeDef HAL_SAI_Transmit_IT(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
1073 {
1074   if ((pData == NULL) || (Size == 0))
1075   {
1076     return  HAL_ERROR;
1077   }
1078 
1079   if (hsai->State == HAL_SAI_STATE_READY)
1080   {
1081     /* Process Locked */
1082     __HAL_LOCK(hsai);
1083 
1084     hsai->pBuffPtr = pData;
1085     hsai->XferSize = Size;
1086     hsai->XferCount = Size;
1087     hsai->ErrorCode = HAL_SAI_ERROR_NONE;
1088     hsai->State = HAL_SAI_STATE_BUSY_TX;
1089 
1090     if ((hsai->Init.DataSize == SAI_DATASIZE_8) && (hsai->Init.CompandingMode == SAI_NOCOMPANDING))
1091     {
1092       hsai->InterruptServiceRoutine = SAI_Transmit_IT8Bit;
1093     }
1094     else if (hsai->Init.DataSize <= SAI_DATASIZE_16)
1095     {
1096       hsai->InterruptServiceRoutine = SAI_Transmit_IT16Bit;
1097     }
1098     else
1099     {
1100       hsai->InterruptServiceRoutine = SAI_Transmit_IT32Bit;
1101     }
1102 
1103     /* Fill the fifo before starting the communication */
1104     SAI_FillFifo(hsai);
1105 
1106     /* Enable FRQ and OVRUDR interrupts */
1107     __HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
1108 
1109     /* Check if the SAI is already enabled */
1110     if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
1111     {
1112       /* Enable SAI peripheral */
1113       __HAL_SAI_ENABLE(hsai);
1114     }
1115     /* Process Unlocked */
1116     __HAL_UNLOCK(hsai);
1117 
1118     return HAL_OK;
1119   }
1120   else
1121   {
1122     return HAL_BUSY;
1123   }
1124 }
1125 
1126 /**
1127   * @brief  Receive an amount of data in non-blocking mode with Interrupt.
1128   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1129   *               the configuration information for SAI module.
1130   * @param  pData Pointer to data buffer
1131   * @param  Size Amount of data to be received
1132   * @retval HAL status
1133   */
HAL_SAI_Receive_IT(SAI_HandleTypeDef * hsai,uint8_t * pData,uint16_t Size)1134 HAL_StatusTypeDef HAL_SAI_Receive_IT(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
1135 {
1136   if ((pData == NULL) || (Size == 0))
1137   {
1138     return  HAL_ERROR;
1139   }
1140 
1141   if (hsai->State == HAL_SAI_STATE_READY)
1142   {
1143     /* Process Locked */
1144     __HAL_LOCK(hsai);
1145 
1146     hsai->pBuffPtr = pData;
1147     hsai->XferSize = Size;
1148     hsai->XferCount = Size;
1149     hsai->ErrorCode = HAL_SAI_ERROR_NONE;
1150     hsai->State = HAL_SAI_STATE_BUSY_RX;
1151 
1152     if ((hsai->Init.DataSize == SAI_DATASIZE_8) && (hsai->Init.CompandingMode == SAI_NOCOMPANDING))
1153     {
1154       hsai->InterruptServiceRoutine = SAI_Receive_IT8Bit;
1155     }
1156     else if (hsai->Init.DataSize <= SAI_DATASIZE_16)
1157     {
1158       hsai->InterruptServiceRoutine = SAI_Receive_IT16Bit;
1159     }
1160     else
1161     {
1162       hsai->InterruptServiceRoutine = SAI_Receive_IT32Bit;
1163     }
1164 
1165     /* Enable TXE and OVRUDR interrupts */
1166     __HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
1167 
1168     /* Check if the SAI is already enabled */
1169     if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
1170     {
1171       /* Enable SAI peripheral */
1172       __HAL_SAI_ENABLE(hsai);
1173     }
1174 
1175     /* Process Unlocked */
1176     __HAL_UNLOCK(hsai);
1177 
1178     return HAL_OK;
1179   }
1180   else
1181   {
1182     return HAL_BUSY;
1183   }
1184 }
1185 
1186 /**
1187   * @brief Pause the audio stream playing from the Media.
1188   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1189   *               the configuration information for SAI module.
1190   * @retval HAL status
1191   */
HAL_SAI_DMAPause(SAI_HandleTypeDef * hsai)1192 HAL_StatusTypeDef HAL_SAI_DMAPause(SAI_HandleTypeDef *hsai)
1193 {
1194   /* Process Locked */
1195   __HAL_LOCK(hsai);
1196 
1197   /* Pause the audio file playing by disabling the SAI DMA requests */
1198   hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
1199 
1200   /* Process Unlocked */
1201   __HAL_UNLOCK(hsai);
1202 
1203   return HAL_OK;
1204 }
1205 
1206 /**
1207   * @brief Resume the audio stream playing from the Media.
1208   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1209   *               the configuration information for SAI module.
1210   * @retval HAL status
1211   */
HAL_SAI_DMAResume(SAI_HandleTypeDef * hsai)1212 HAL_StatusTypeDef HAL_SAI_DMAResume(SAI_HandleTypeDef *hsai)
1213 {
1214   /* Process Locked */
1215   __HAL_LOCK(hsai);
1216 
1217   /* Enable the SAI DMA requests */
1218   hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
1219 
1220   /* If the SAI peripheral is still not enabled, enable it */
1221   if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
1222   {
1223     /* Enable SAI peripheral */
1224     __HAL_SAI_ENABLE(hsai);
1225   }
1226 
1227   /* Process Unlocked */
1228   __HAL_UNLOCK(hsai);
1229 
1230   return HAL_OK;
1231 }
1232 
1233 /**
1234   * @brief Stop the audio stream playing from the Media.
1235   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1236   *               the configuration information for SAI module.
1237   * @retval HAL status
1238   */
HAL_SAI_DMAStop(SAI_HandleTypeDef * hsai)1239 HAL_StatusTypeDef HAL_SAI_DMAStop(SAI_HandleTypeDef *hsai)
1240 {
1241   HAL_StatusTypeDef status = HAL_OK;
1242 
1243   /* Process Locked */
1244   __HAL_LOCK(hsai);
1245 
1246   /* Disable the SAI DMA request */
1247   hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
1248 
1249   /* Abort the SAI Tx DMA Stream */
1250   if ((hsai->hdmatx != NULL) && (hsai->State == HAL_SAI_STATE_BUSY_TX))
1251   {
1252     if (HAL_DMA_Abort(hsai->hdmatx) != HAL_OK)
1253     {
1254       /* If the DMA Tx errorCode is different from DMA No Transfer then return Error */
1255       if (hsai->hdmatx->ErrorCode != HAL_DMA_ERROR_NO_XFER)
1256       {
1257         status = HAL_ERROR;
1258         hsai->ErrorCode |= HAL_SAI_ERROR_DMA;
1259       }
1260     }
1261   }
1262 
1263   /* Abort the SAI Rx DMA Stream */
1264   if ((hsai->hdmarx != NULL) && (hsai->State == HAL_SAI_STATE_BUSY_RX))
1265   {
1266     if (HAL_DMA_Abort(hsai->hdmarx) != HAL_OK)
1267     {
1268       /* If the DMA Rx errorCode is different from DMA No Transfer then return Error */
1269       if (hsai->hdmarx->ErrorCode != HAL_DMA_ERROR_NO_XFER)
1270       {
1271         status = HAL_ERROR;
1272         hsai->ErrorCode |= HAL_SAI_ERROR_DMA;
1273       }
1274     }
1275   }
1276 
1277   /* Disable SAI peripheral */
1278   SAI_Disable(hsai);
1279 
1280   /* Flush the fifo */
1281   SET_BIT(hsai->Instance->CR2, SAI_xCR2_FFLUSH);
1282 
1283   /* Set hsai state to ready */
1284   hsai->State = HAL_SAI_STATE_READY;
1285 
1286   /* Process Unlocked */
1287   __HAL_UNLOCK(hsai);
1288 
1289   return status;
1290 }
1291 
1292 /**
1293   * @brief Abort the current transfer and disable the SAI.
1294   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1295   *               the configuration information for SAI module.
1296   * @retval HAL status
1297   */
HAL_SAI_Abort(SAI_HandleTypeDef * hsai)1298 HAL_StatusTypeDef HAL_SAI_Abort(SAI_HandleTypeDef *hsai)
1299 {
1300   HAL_StatusTypeDef status = HAL_OK;
1301 
1302   /* Process Locked */
1303   __HAL_LOCK(hsai);
1304 
1305   /* Check SAI DMA is enabled or not */
1306   if ((hsai->Instance->CR1 & SAI_xCR1_DMAEN) == SAI_xCR1_DMAEN)
1307   {
1308     /* Disable the SAI DMA request */
1309     hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
1310 
1311     /* Abort the SAI Tx DMA Stream */
1312     if ((hsai->hdmatx != NULL) && (hsai->State == HAL_SAI_STATE_BUSY_TX))
1313     {
1314       if (HAL_DMA_Abort(hsai->hdmatx) != HAL_OK)
1315       {
1316         /* If the DMA Tx errorCode is different from DMA No Transfer then return Error */
1317         if (hsai->hdmatx->ErrorCode != HAL_DMA_ERROR_NO_XFER)
1318         {
1319           status = HAL_ERROR;
1320           hsai->ErrorCode |= HAL_SAI_ERROR_DMA;
1321         }
1322       }
1323     }
1324 
1325     /* Abort the SAI Rx DMA Stream */
1326     if ((hsai->hdmarx != NULL) && (hsai->State == HAL_SAI_STATE_BUSY_RX))
1327     {
1328       if (HAL_DMA_Abort(hsai->hdmarx) != HAL_OK)
1329       {
1330         /* If the DMA Rx errorCode is different from DMA No Transfer then return Error */
1331         if (hsai->hdmarx->ErrorCode != HAL_DMA_ERROR_NO_XFER)
1332         {
1333           status = HAL_ERROR;
1334           hsai->ErrorCode |= HAL_SAI_ERROR_DMA;
1335         }
1336       }
1337     }
1338   }
1339 
1340   /* Disabled All interrupt and clear all the flag */
1341   hsai->Instance->IMR = 0U;
1342   hsai->Instance->CLRFR = 0xFFFFFFFFU;
1343 
1344   /* Disable SAI peripheral */
1345   SAI_Disable(hsai);
1346 
1347   /* Flush the fifo */
1348   SET_BIT(hsai->Instance->CR2, SAI_xCR2_FFLUSH);
1349 
1350   /* Set hsai state to ready */
1351   hsai->State = HAL_SAI_STATE_READY;
1352 
1353   /* Process Unlocked */
1354   __HAL_UNLOCK(hsai);
1355 
1356   return status;
1357 }
1358 
1359 /**
1360   * @brief  Transmit an amount of data in non-blocking mode with DMA.
1361   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1362   *               the configuration information for SAI module.
1363   * @param  pData Pointer to data buffer
1364   * @param  Size Amount of data to be sent
1365   * @retval HAL status
1366   */
HAL_SAI_Transmit_DMA(SAI_HandleTypeDef * hsai,uint8_t * pData,uint16_t Size)1367 HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
1368 {
1369   uint32_t tickstart = HAL_GetTick();
1370 
1371   if ((pData == NULL) || (Size == 0))
1372   {
1373     return  HAL_ERROR;
1374   }
1375 
1376   if (hsai->State == HAL_SAI_STATE_READY)
1377   {
1378     /* Process Locked */
1379     __HAL_LOCK(hsai);
1380 
1381     hsai->pBuffPtr = pData;
1382     hsai->XferSize = Size;
1383     hsai->XferCount = Size;
1384     hsai->ErrorCode = HAL_SAI_ERROR_NONE;
1385     hsai->State = HAL_SAI_STATE_BUSY_TX;
1386 
1387     /* Set the SAI Tx DMA Half transfer complete callback */
1388     hsai->hdmatx->XferHalfCpltCallback = SAI_DMATxHalfCplt;
1389 
1390     /* Set the SAI TxDMA transfer complete callback */
1391     hsai->hdmatx->XferCpltCallback = SAI_DMATxCplt;
1392 
1393     /* Set the DMA error callback */
1394     hsai->hdmatx->XferErrorCallback = SAI_DMAError;
1395 
1396     /* Set the DMA Tx abort callback */
1397     hsai->hdmatx->XferAbortCallback = NULL;
1398 
1399     /* Enable the Tx DMA Stream */
1400     if (HAL_DMA_Start_IT(hsai->hdmatx, (uint32_t)hsai->pBuffPtr, (uint32_t)&hsai->Instance->DR, hsai->XferSize) != HAL_OK)
1401     {
1402       __HAL_UNLOCK(hsai);
1403       return  HAL_ERROR;
1404     }
1405 
1406     /* Enable the interrupts for error handling */
1407     __HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
1408 
1409     /* Enable SAI Tx DMA Request */
1410     hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
1411 
1412     /* Wait until FIFO is not empty */
1413     while ((hsai->Instance->SR & SAI_xSR_FLVL) == SAI_FIFOSTATUS_EMPTY)
1414     {
1415       /* Check for the Timeout */
1416       if ((HAL_GetTick() - tickstart) > SAI_LONG_TIMEOUT)
1417       {
1418         /* Update error code */
1419         hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
1420 
1421         /* Process Unlocked */
1422         __HAL_UNLOCK(hsai);
1423 
1424         return HAL_TIMEOUT;
1425       }
1426     }
1427 
1428     /* Check if the SAI is already enabled */
1429     if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == 0U)
1430     {
1431       /* Enable SAI peripheral */
1432       __HAL_SAI_ENABLE(hsai);
1433     }
1434 
1435     /* Process Unlocked */
1436     __HAL_UNLOCK(hsai);
1437 
1438     return HAL_OK;
1439   }
1440   else
1441   {
1442     return HAL_BUSY;
1443   }
1444 }
1445 
1446 /**
1447   * @brief  Receive an amount of data in non-blocking mode with DMA.
1448   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1449   *               the configuration information for SAI module.
1450   * @param  pData Pointer to data buffer
1451   * @param  Size Amount of data to be received
1452   * @retval HAL status
1453   */
HAL_SAI_Receive_DMA(SAI_HandleTypeDef * hsai,uint8_t * pData,uint16_t Size)1454 HAL_StatusTypeDef HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
1455 {
1456   if ((pData == NULL) || (Size == 0))
1457   {
1458     return  HAL_ERROR;
1459   }
1460 
1461   if (hsai->State == HAL_SAI_STATE_READY)
1462   {
1463     /* Process Locked */
1464     __HAL_LOCK(hsai);
1465 
1466     hsai->pBuffPtr = pData;
1467     hsai->XferSize = Size;
1468     hsai->XferCount = Size;
1469     hsai->ErrorCode = HAL_SAI_ERROR_NONE;
1470     hsai->State = HAL_SAI_STATE_BUSY_RX;
1471 
1472     /* Set the SAI Rx DMA Half transfer complete callback */
1473     hsai->hdmarx->XferHalfCpltCallback = SAI_DMARxHalfCplt;
1474 
1475     /* Set the SAI Rx DMA transfer complete callback */
1476     hsai->hdmarx->XferCpltCallback = SAI_DMARxCplt;
1477 
1478     /* Set the DMA error callback */
1479     hsai->hdmarx->XferErrorCallback = SAI_DMAError;
1480 
1481     /* Set the DMA Rx abort callback */
1482     hsai->hdmarx->XferAbortCallback = NULL;
1483 
1484     /* Enable the Rx DMA Stream */
1485     if (HAL_DMA_Start_IT(hsai->hdmarx, (uint32_t)&hsai->Instance->DR, (uint32_t)hsai->pBuffPtr, hsai->XferSize) != HAL_OK)
1486     {
1487       __HAL_UNLOCK(hsai);
1488       return  HAL_ERROR;
1489     }
1490 
1491     /* Enable the interrupts for error handling */
1492     __HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
1493 
1494     /* Enable SAI Rx DMA Request */
1495     hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
1496 
1497     /* Check if the SAI is already enabled */
1498     if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
1499     {
1500       /* Enable SAI peripheral */
1501       __HAL_SAI_ENABLE(hsai);
1502     }
1503 
1504     /* Process Unlocked */
1505     __HAL_UNLOCK(hsai);
1506 
1507     return HAL_OK;
1508   }
1509   else
1510   {
1511     return HAL_BUSY;
1512   }
1513 }
1514 
1515 /**
1516   * @brief  Enable the Tx mute mode.
1517   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1518   *               the configuration information for SAI module.
1519   * @param  val  value sent during the mute @ref SAI_Block_Mute_Value
1520   * @retval HAL status
1521   */
HAL_SAI_EnableTxMuteMode(SAI_HandleTypeDef * hsai,uint16_t val)1522 HAL_StatusTypeDef HAL_SAI_EnableTxMuteMode(SAI_HandleTypeDef *hsai, uint16_t val)
1523 {
1524   assert_param(IS_SAI_BLOCK_MUTE_VALUE(val));
1525 
1526   if (hsai->State != HAL_SAI_STATE_RESET)
1527   {
1528     CLEAR_BIT(hsai->Instance->CR2, SAI_xCR2_MUTEVAL | SAI_xCR2_MUTE);
1529     SET_BIT(hsai->Instance->CR2, SAI_xCR2_MUTE | val);
1530     return HAL_OK;
1531   }
1532   return HAL_ERROR;
1533 }
1534 
1535 /**
1536   * @brief  Disable the Tx mute mode.
1537   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1538   *               the configuration information for SAI module.
1539   * @retval HAL status
1540   */
HAL_SAI_DisableTxMuteMode(SAI_HandleTypeDef * hsai)1541 HAL_StatusTypeDef HAL_SAI_DisableTxMuteMode(SAI_HandleTypeDef *hsai)
1542 {
1543   if (hsai->State != HAL_SAI_STATE_RESET)
1544   {
1545     CLEAR_BIT(hsai->Instance->CR2, SAI_xCR2_MUTEVAL | SAI_xCR2_MUTE);
1546     return HAL_OK;
1547   }
1548   return HAL_ERROR;
1549 }
1550 
1551 /**
1552   * @brief  Enable the Rx mute detection.
1553   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1554   *               the configuration information for SAI module.
1555   * @param  callback function called when the mute is detected.
1556   * @param  counter number a data before mute detection max 63.
1557   * @retval HAL status
1558   */
HAL_SAI_EnableRxMuteMode(SAI_HandleTypeDef * hsai,SAIcallback callback,uint16_t counter)1559 HAL_StatusTypeDef HAL_SAI_EnableRxMuteMode(SAI_HandleTypeDef *hsai, SAIcallback callback, uint16_t counter)
1560 {
1561   assert_param(IS_SAI_BLOCK_MUTE_COUNTER(counter));
1562 
1563   if (hsai->State != HAL_SAI_STATE_RESET)
1564   {
1565     /* set the mute counter */
1566     CLEAR_BIT(hsai->Instance->CR2, SAI_xCR2_MUTECNT);
1567     SET_BIT(hsai->Instance->CR2, (uint32_t)((uint32_t)counter << SAI_xCR2_MUTECNT_Pos));
1568     hsai->mutecallback = callback;
1569     /* enable the IT interrupt */
1570     __HAL_SAI_ENABLE_IT(hsai, SAI_IT_MUTEDET);
1571     return HAL_OK;
1572   }
1573   return HAL_ERROR;
1574 }
1575 
1576 /**
1577   * @brief  Disable the Rx mute detection.
1578   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1579   *               the configuration information for SAI module.
1580   * @retval HAL status
1581   */
HAL_SAI_DisableRxMuteMode(SAI_HandleTypeDef * hsai)1582 HAL_StatusTypeDef HAL_SAI_DisableRxMuteMode(SAI_HandleTypeDef *hsai)
1583 {
1584   if (hsai->State != HAL_SAI_STATE_RESET)
1585   {
1586     /* set the mutecallback to NULL */
1587     hsai->mutecallback = (SAIcallback)NULL;
1588     /* enable the IT interrupt */
1589     __HAL_SAI_DISABLE_IT(hsai, SAI_IT_MUTEDET);
1590     return HAL_OK;
1591   }
1592   return HAL_ERROR;
1593 }
1594 
1595 /**
1596   * @brief  Handle SAI interrupt request.
1597   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1598   *               the configuration information for SAI module.
1599   * @retval None
1600   */
HAL_SAI_IRQHandler(SAI_HandleTypeDef * hsai)1601 void HAL_SAI_IRQHandler(SAI_HandleTypeDef *hsai)
1602 {
1603   if (hsai->State != HAL_SAI_STATE_RESET)
1604   {
1605     uint32_t itflags = hsai->Instance->SR;
1606     uint32_t itsources = hsai->Instance->IMR;
1607     uint32_t cr1config = hsai->Instance->CR1;
1608     uint32_t tmperror;
1609 
1610     /* SAI Fifo request interrupt occurred ------------------------------------*/
1611     if (((itflags & SAI_xSR_FREQ) == SAI_xSR_FREQ) && ((itsources & SAI_IT_FREQ) == SAI_IT_FREQ))
1612     {
1613       hsai->InterruptServiceRoutine(hsai);
1614     }
1615     /* SAI Overrun error interrupt occurred ----------------------------------*/
1616     else if (((itflags & SAI_FLAG_OVRUDR) == SAI_FLAG_OVRUDR) && ((itsources & SAI_IT_OVRUDR) == SAI_IT_OVRUDR))
1617     {
1618       /* Clear the SAI Overrun flag */
1619       __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR);
1620 
1621       /* Get the SAI error code */
1622       tmperror = ((hsai->State == HAL_SAI_STATE_BUSY_RX) ? HAL_SAI_ERROR_OVR : HAL_SAI_ERROR_UDR);
1623 
1624       /* Change the SAI error code */
1625       hsai->ErrorCode |= tmperror;
1626 
1627       /* the transfer is not stopped, we will forward the information to the user and we let the user decide what needs to be done */
1628 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
1629       hsai->ErrorCallback(hsai);
1630 #else
1631       HAL_SAI_ErrorCallback(hsai);
1632 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
1633     }
1634     /* SAI mutedet interrupt occurred ----------------------------------*/
1635     else if (((itflags & SAI_FLAG_MUTEDET) == SAI_FLAG_MUTEDET) && ((itsources & SAI_IT_MUTEDET) == SAI_IT_MUTEDET))
1636     {
1637       /* Clear the SAI mutedet flag */
1638       __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_MUTEDET);
1639 
1640       /* call the call back function */
1641       if (hsai->mutecallback != (SAIcallback)NULL)
1642       {
1643         /* inform the user that an RX mute event has been detected */
1644         hsai->mutecallback();
1645       }
1646     }
1647     /* SAI AFSDET interrupt occurred ----------------------------------*/
1648     else if (((itflags & SAI_FLAG_AFSDET) == SAI_FLAG_AFSDET) && ((itsources & SAI_IT_AFSDET) == SAI_IT_AFSDET))
1649     {
1650       /* Clear the SAI AFSDET flag */
1651       __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_AFSDET);
1652 
1653       /* Change the SAI error code */
1654       hsai->ErrorCode |= HAL_SAI_ERROR_AFSDET;
1655 
1656       /* Check SAI DMA is enabled or not */
1657       if ((cr1config & SAI_xCR1_DMAEN) == SAI_xCR1_DMAEN)
1658       {
1659         /* Abort the SAI DMA Streams */
1660         if (hsai->hdmatx != NULL)
1661         {
1662           /* Set the DMA Tx abort callback */
1663           hsai->hdmatx->XferAbortCallback = SAI_DMAAbort;
1664 
1665           /* Abort DMA in IT mode */
1666           HAL_DMA_Abort_IT(hsai->hdmatx);
1667         }
1668         else if (hsai->hdmarx != NULL)
1669         {
1670           /* Set the DMA Rx abort callback */
1671           hsai->hdmarx->XferAbortCallback = SAI_DMAAbort;
1672 
1673           /* Abort DMA in IT mode */
1674           HAL_DMA_Abort_IT(hsai->hdmarx);
1675         }
1676       }
1677       else
1678       {
1679         /* Abort SAI */
1680         HAL_SAI_Abort(hsai);
1681 
1682         /* Set error callback */
1683 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
1684         hsai->ErrorCallback(hsai);
1685 #else
1686         HAL_SAI_ErrorCallback(hsai);
1687 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
1688       }
1689     }
1690     /* SAI LFSDET interrupt occurred ----------------------------------*/
1691     else if (((itflags & SAI_FLAG_LFSDET) == SAI_FLAG_LFSDET) && ((itsources & SAI_IT_LFSDET) == SAI_IT_LFSDET))
1692     {
1693       /* Clear the SAI LFSDET flag */
1694       __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_LFSDET);
1695 
1696       /* Change the SAI error code */
1697       hsai->ErrorCode |= HAL_SAI_ERROR_LFSDET;
1698 
1699       /* Check SAI DMA is enabled or not */
1700       if ((cr1config & SAI_xCR1_DMAEN) == SAI_xCR1_DMAEN)
1701       {
1702         /* Abort the SAI DMA Streams */
1703         if (hsai->hdmatx != NULL)
1704         {
1705           /* Set the DMA Tx abort callback */
1706           hsai->hdmatx->XferAbortCallback = SAI_DMAAbort;
1707 
1708           /* Abort DMA in IT mode */
1709           HAL_DMA_Abort_IT(hsai->hdmatx);
1710         }
1711         else if (hsai->hdmarx != NULL)
1712         {
1713           /* Set the DMA Rx abort callback */
1714           hsai->hdmarx->XferAbortCallback = SAI_DMAAbort;
1715 
1716           /* Abort DMA in IT mode */
1717           HAL_DMA_Abort_IT(hsai->hdmarx);
1718         }
1719       }
1720       else
1721       {
1722         /* Abort SAI */
1723         HAL_SAI_Abort(hsai);
1724 
1725         /* Set error callback */
1726 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
1727         hsai->ErrorCallback(hsai);
1728 #else
1729         HAL_SAI_ErrorCallback(hsai);
1730 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
1731       }
1732     }
1733     /* SAI WCKCFG interrupt occurred ----------------------------------*/
1734     else if (((itflags & SAI_FLAG_WCKCFG) == SAI_FLAG_WCKCFG) && ((itsources & SAI_IT_WCKCFG) == SAI_IT_WCKCFG))
1735     {
1736       /* Clear the SAI WCKCFG flag */
1737       __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_WCKCFG);
1738 
1739       /* Change the SAI error code */
1740       hsai->ErrorCode |= HAL_SAI_ERROR_WCKCFG;
1741 
1742       /* Check SAI DMA is enabled or not */
1743       if ((cr1config & SAI_xCR1_DMAEN) == SAI_xCR1_DMAEN)
1744       {
1745         /* Abort the SAI DMA Streams */
1746         if (hsai->hdmatx != NULL)
1747         {
1748           /* Set the DMA Tx abort callback */
1749           hsai->hdmatx->XferAbortCallback = SAI_DMAAbort;
1750 
1751           /* Abort DMA in IT mode */
1752           HAL_DMA_Abort_IT(hsai->hdmatx);
1753         }
1754         else if (hsai->hdmarx != NULL)
1755         {
1756           /* Set the DMA Rx abort callback */
1757           hsai->hdmarx->XferAbortCallback = SAI_DMAAbort;
1758 
1759           /* Abort DMA in IT mode */
1760           HAL_DMA_Abort_IT(hsai->hdmarx);
1761         }
1762       }
1763       else
1764       {
1765         /* If WCKCFG occurs, SAI audio block is automatically disabled */
1766         /* Disable all interrupts and clear all flags */
1767         hsai->Instance->IMR = 0U;
1768         hsai->Instance->CLRFR = 0xFFFFFFFFU;
1769 
1770         /* Set the SAI state to ready to be able to start again the process */
1771         hsai->State = HAL_SAI_STATE_READY;
1772 
1773         /* Initialize XferCount */
1774         hsai->XferCount = 0U;
1775 
1776         /* SAI error Callback */
1777 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
1778         hsai->ErrorCallback(hsai);
1779 #else
1780         HAL_SAI_ErrorCallback(hsai);
1781 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
1782       }
1783     }
1784     /* SAI CNRDY interrupt occurred ----------------------------------*/
1785     else if (((itflags & SAI_FLAG_CNRDY) == SAI_FLAG_CNRDY) && ((itsources & SAI_IT_CNRDY) == SAI_IT_CNRDY))
1786     {
1787       /* Clear the SAI CNRDY flag */
1788       __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_CNRDY);
1789 
1790       /* Change the SAI error code */
1791       hsai->ErrorCode |= HAL_SAI_ERROR_CNREADY;
1792 
1793       /* the transfer is not stopped, we will forward the information to the user and we let the user decide what needs to be done */
1794 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
1795       hsai->ErrorCallback(hsai);
1796 #else
1797       HAL_SAI_ErrorCallback(hsai);
1798 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
1799     }
1800     else
1801     {
1802       /* Nothing to do */
1803     }
1804   }
1805 }
1806 
1807 /**
1808   * @brief Tx Transfer completed callback.
1809   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1810   *                the configuration information for SAI module.
1811   * @retval None
1812   */
HAL_SAI_TxCpltCallback(SAI_HandleTypeDef * hsai)1813 __weak void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
1814 {
1815   /* Prevent unused argument(s) compilation warning */
1816   UNUSED(hsai);
1817 
1818   /* NOTE : This function should not be modified, when the callback is needed,
1819             the HAL_SAI_TxCpltCallback could be implemented in the user file
1820    */
1821 }
1822 
1823 /**
1824   * @brief Tx Transfer Half completed callback.
1825   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1826   *               the configuration information for SAI module.
1827   * @retval None
1828   */
HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef * hsai)1829 __weak void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
1830 {
1831   /* Prevent unused argument(s) compilation warning */
1832   UNUSED(hsai);
1833 
1834   /* NOTE : This function should not be modified, when the callback is needed,
1835             the HAL_SAI_TxHalfCpltCallback could be implemented in the user file
1836    */
1837 }
1838 
1839 /**
1840   * @brief Rx Transfer completed callback.
1841   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1842   *               the configuration information for SAI module.
1843   * @retval None
1844   */
HAL_SAI_RxCpltCallback(SAI_HandleTypeDef * hsai)1845 __weak void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
1846 {
1847   /* Prevent unused argument(s) compilation warning */
1848   UNUSED(hsai);
1849 
1850   /* NOTE : This function should not be modified, when the callback is needed,
1851             the HAL_SAI_RxCpltCallback could be implemented in the user file
1852    */
1853 }
1854 
1855 /**
1856   * @brief Rx Transfer half completed callback.
1857   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1858   *               the configuration information for SAI module.
1859   * @retval None
1860   */
HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef * hsai)1861 __weak void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
1862 {
1863   /* Prevent unused argument(s) compilation warning */
1864   UNUSED(hsai);
1865 
1866   /* NOTE : This function should not be modified, when the callback is needed,
1867             the HAL_SAI_RxHalfCpltCallback could be implemented in the user file
1868    */
1869 }
1870 
1871 /**
1872   * @brief SAI error callback.
1873   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1874   *               the configuration information for SAI module.
1875   * @retval None
1876   */
HAL_SAI_ErrorCallback(SAI_HandleTypeDef * hsai)1877 __weak void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
1878 {
1879   /* Prevent unused argument(s) compilation warning */
1880   UNUSED(hsai);
1881 
1882   /* NOTE : This function should not be modified, when the callback is needed,
1883             the HAL_SAI_ErrorCallback could be implemented in the user file
1884    */
1885 }
1886 
1887 /**
1888   * @}
1889   */
1890 
1891 /** @defgroup SAI_Exported_Functions_Group3 Peripheral State functions
1892   * @brief    Peripheral State functions
1893   *
1894 @verbatim
1895  ===============================================================================
1896                 ##### Peripheral State and Errors functions #####
1897  ===============================================================================
1898   [..]
1899     This subsection permits to get in run-time the status of the peripheral
1900     and the data flow.
1901 
1902 @endverbatim
1903   * @{
1904   */
1905 
1906 /**
1907   * @brief  Return the SAI handle state.
1908   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1909   *               the configuration information for SAI module.
1910   * @retval HAL state
1911   */
HAL_SAI_GetState(SAI_HandleTypeDef * hsai)1912 HAL_SAI_StateTypeDef HAL_SAI_GetState(SAI_HandleTypeDef *hsai)
1913 {
1914   return hsai->State;
1915 }
1916 
1917 /**
1918   * @brief  Return the SAI error code.
1919   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1920   *              the configuration information for the specified SAI Block.
1921   * @retval SAI Error Code
1922   */
HAL_SAI_GetError(SAI_HandleTypeDef * hsai)1923 uint32_t HAL_SAI_GetError(SAI_HandleTypeDef *hsai)
1924 {
1925   return hsai->ErrorCode;
1926 }
1927 /**
1928   * @}
1929   */
1930 
1931 /**
1932   * @}
1933   */
1934 
1935 /** @addtogroup SAI_Private_Functions
1936   * @brief      Private functions
1937   * @{
1938   */
1939 
1940 /**
1941   * @brief  Initialize the SAI I2S protocol according to the specified parameters
1942   *         in the SAI_InitTypeDef and create the associated handle.
1943   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
1944   *               the configuration information for SAI module.
1945   * @param  protocol one of the supported protocol.
1946   * @param  datasize one of the supported datasize @ref SAI_Protocol_DataSize
1947   *                the configuration information for SAI module.
1948   * @param  nbslot number of slot minimum value is 2 and max is 16.
1949   *                    the value must be a multiple of 2.
1950   * @retval HAL status
1951   */
SAI_InitI2S(SAI_HandleTypeDef * hsai,uint32_t protocol,uint32_t datasize,uint32_t nbslot)1952 static HAL_StatusTypeDef SAI_InitI2S(SAI_HandleTypeDef *hsai, uint32_t protocol, uint32_t datasize, uint32_t nbslot)
1953 {
1954   hsai->Init.Protocol            = SAI_FREE_PROTOCOL;
1955   hsai->Init.FirstBit            = SAI_FIRSTBIT_MSB;
1956   /* Compute ClockStrobing according AudioMode */
1957   if ((hsai->Init.AudioMode == SAI_MODEMASTER_TX) || (hsai->Init.AudioMode == SAI_MODESLAVE_TX))
1958   {
1959     /* Transmit */
1960     hsai->Init.ClockStrobing     = SAI_CLOCKSTROBING_FALLINGEDGE;
1961   }
1962   else
1963   {
1964     /* Receive */
1965     hsai->Init.ClockStrobing     = SAI_CLOCKSTROBING_RISINGEDGE;
1966   }
1967   hsai->FrameInit.FSDefinition   = SAI_FS_CHANNEL_IDENTIFICATION;
1968   hsai->SlotInit.SlotActive      = SAI_SLOTACTIVE_ALL;
1969   hsai->SlotInit.FirstBitOffset  = 0U;
1970   hsai->SlotInit.SlotNumber      = nbslot;
1971 
1972   /* in IS2 the number of slot must be even */
1973   if ((nbslot & 0x1U) != 0U)
1974   {
1975     return HAL_ERROR;
1976   }
1977 
1978   if (protocol == SAI_I2S_STANDARD)
1979   {
1980     hsai->FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
1981     hsai->FrameInit.FSOffset   = SAI_FS_BEFOREFIRSTBIT;
1982   }
1983   else
1984   {
1985     /* SAI_I2S_MSBJUSTIFIED or SAI_I2S_LSBJUSTIFIED */
1986     hsai->FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH;
1987     hsai->FrameInit.FSOffset   = SAI_FS_FIRSTBIT;
1988   }
1989 
1990   /* Frame definition */
1991   switch (datasize)
1992   {
1993     case SAI_PROTOCOL_DATASIZE_16BIT:
1994       hsai->Init.DataSize = SAI_DATASIZE_16;
1995       hsai->FrameInit.FrameLength = 32U * (nbslot / 2U);
1996       hsai->FrameInit.ActiveFrameLength = 16U * (nbslot / 2U);
1997       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_16B;
1998       break;
1999     case SAI_PROTOCOL_DATASIZE_16BITEXTENDED :
2000       hsai->Init.DataSize = SAI_DATASIZE_16;
2001       hsai->FrameInit.FrameLength = 64U * (nbslot / 2U);
2002       hsai->FrameInit.ActiveFrameLength = 32U * (nbslot / 2U);
2003       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
2004       break;
2005     case SAI_PROTOCOL_DATASIZE_24BIT:
2006       hsai->Init.DataSize = SAI_DATASIZE_24;
2007       hsai->FrameInit.FrameLength = 64U * (nbslot / 2U);
2008       hsai->FrameInit.ActiveFrameLength = 32U * (nbslot / 2U);
2009       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
2010       break;
2011     case SAI_PROTOCOL_DATASIZE_32BIT:
2012       hsai->Init.DataSize = SAI_DATASIZE_32;
2013       hsai->FrameInit.FrameLength = 64U * (nbslot / 2U);
2014       hsai->FrameInit.ActiveFrameLength = 32U * (nbslot / 2U);
2015       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
2016       break;
2017     default :
2018       return HAL_ERROR;
2019   }
2020   if (protocol == SAI_I2S_LSBJUSTIFIED)
2021   {
2022     if (datasize == SAI_PROTOCOL_DATASIZE_16BITEXTENDED)
2023     {
2024       hsai->SlotInit.FirstBitOffset = 16U;
2025     }
2026     if (datasize == SAI_PROTOCOL_DATASIZE_24BIT)
2027     {
2028       hsai->SlotInit.FirstBitOffset = 8U;
2029     }
2030   }
2031   return HAL_OK;
2032 }
2033 
2034 /**
2035   * @brief  Initialize the SAI PCM protocol according to the specified parameters
2036   *         in the SAI_InitTypeDef and create the associated handle.
2037   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2038   *               the configuration information for SAI module.
2039   * @param  protocol one of the supported protocol
2040   * @param  datasize one of the supported datasize @ref SAI_Protocol_DataSize
2041   * @param  nbslot number of slot minimum value is 1 and the max is 16.
2042   * @retval HAL status
2043   */
SAI_InitPCM(SAI_HandleTypeDef * hsai,uint32_t protocol,uint32_t datasize,uint32_t nbslot)2044 static HAL_StatusTypeDef SAI_InitPCM(SAI_HandleTypeDef *hsai, uint32_t protocol, uint32_t datasize, uint32_t nbslot)
2045 {
2046   hsai->Init.Protocol            = SAI_FREE_PROTOCOL;
2047   hsai->Init.FirstBit            = SAI_FIRSTBIT_MSB;
2048   /* Compute ClockStrobing according AudioMode */
2049   if ((hsai->Init.AudioMode == SAI_MODEMASTER_TX) || (hsai->Init.AudioMode == SAI_MODESLAVE_TX))
2050   {
2051     /* Transmit */
2052     hsai->Init.ClockStrobing     = SAI_CLOCKSTROBING_RISINGEDGE;
2053   }
2054   else
2055   {
2056     /* Receive */
2057     hsai->Init.ClockStrobing     = SAI_CLOCKSTROBING_FALLINGEDGE;
2058   }
2059   hsai->FrameInit.FSDefinition   = SAI_FS_STARTFRAME;
2060   hsai->FrameInit.FSPolarity     = SAI_FS_ACTIVE_HIGH;
2061   hsai->FrameInit.FSOffset       = SAI_FS_BEFOREFIRSTBIT;
2062   hsai->SlotInit.FirstBitOffset  = 0U;
2063   hsai->SlotInit.SlotNumber      = nbslot;
2064   hsai->SlotInit.SlotActive      = SAI_SLOTACTIVE_ALL;
2065 
2066   if (protocol == SAI_PCM_SHORT)
2067   {
2068     hsai->FrameInit.ActiveFrameLength = 1;
2069   }
2070   else
2071   {
2072     /* SAI_PCM_LONG */
2073     hsai->FrameInit.ActiveFrameLength = 13;
2074   }
2075 
2076   switch (datasize)
2077   {
2078     case SAI_PROTOCOL_DATASIZE_16BIT:
2079       hsai->Init.DataSize = SAI_DATASIZE_16;
2080       hsai->FrameInit.FrameLength = 16U * nbslot;
2081       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_16B;
2082       break;
2083     case SAI_PROTOCOL_DATASIZE_16BITEXTENDED :
2084       hsai->Init.DataSize = SAI_DATASIZE_16;
2085       hsai->FrameInit.FrameLength = 32U * nbslot;
2086       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
2087       break;
2088     case SAI_PROTOCOL_DATASIZE_24BIT :
2089       hsai->Init.DataSize = SAI_DATASIZE_24;
2090       hsai->FrameInit.FrameLength = 32U * nbslot;
2091       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
2092       break;
2093     case SAI_PROTOCOL_DATASIZE_32BIT:
2094       hsai->Init.DataSize = SAI_DATASIZE_32;
2095       hsai->FrameInit.FrameLength = 32U * nbslot;
2096       hsai->SlotInit.SlotSize = SAI_SLOTSIZE_32B;
2097       break;
2098     default :
2099       return HAL_ERROR;
2100   }
2101 
2102   return HAL_OK;
2103 }
2104 
2105 /**
2106   * @brief  Fill the fifo.
2107   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2108   *               the configuration information for SAI module.
2109   * @retval None
2110   */
SAI_FillFifo(SAI_HandleTypeDef * hsai)2111 static void SAI_FillFifo(SAI_HandleTypeDef *hsai)
2112 {
2113   /* fill the fifo with data before to enabled the SAI */
2114   while (((hsai->Instance->SR & SAI_xSR_FLVL) != SAI_FIFOSTATUS_FULL) && (hsai->XferCount > 0U))
2115   {
2116     if ((hsai->Init.DataSize == SAI_DATASIZE_8) && (hsai->Init.CompandingMode == SAI_NOCOMPANDING))
2117     {
2118       hsai->Instance->DR = (*hsai->pBuffPtr++);
2119     }
2120     else if (hsai->Init.DataSize <= SAI_DATASIZE_16)
2121     {
2122       hsai->Instance->DR = *((uint32_t *)hsai->pBuffPtr);
2123       hsai->pBuffPtr += 2U;
2124     }
2125     else
2126     {
2127       hsai->Instance->DR = *((uint32_t *)hsai->pBuffPtr);
2128       hsai->pBuffPtr += 4U;
2129     }
2130     hsai->XferCount--;
2131   }
2132 }
2133 
2134 /**
2135   * @brief  Return the interrupt flag to set according the SAI setup.
2136   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2137   *               the configuration information for SAI module.
2138   * @param  mode SAI_MODE_DMA or SAI_MODE_IT
2139   * @retval the list of the IT flag to enable
2140  */
SAI_InterruptFlag(SAI_HandleTypeDef * hsai,uint32_t mode)2141 static uint32_t SAI_InterruptFlag(SAI_HandleTypeDef *hsai, uint32_t mode)
2142 {
2143   uint32_t tmpIT = SAI_IT_OVRUDR;
2144 
2145   if (mode == SAI_MODE_IT)
2146   {
2147     tmpIT |= SAI_IT_FREQ;
2148   }
2149 
2150   if ((hsai->Init.Protocol == SAI_AC97_PROTOCOL) &&
2151       ((hsai->Init.AudioMode == SAI_MODESLAVE_RX) || (hsai->Init.AudioMode == SAI_MODEMASTER_RX)))
2152   {
2153     tmpIT |= SAI_IT_CNRDY;
2154   }
2155 
2156   if ((hsai->Init.AudioMode == SAI_MODESLAVE_RX) || (hsai->Init.AudioMode == SAI_MODESLAVE_TX))
2157   {
2158     tmpIT |= SAI_IT_AFSDET | SAI_IT_LFSDET;
2159   }
2160   else
2161   {
2162     /* hsai has been configured in master mode */
2163     tmpIT |= SAI_IT_WCKCFG;
2164   }
2165   return tmpIT;
2166 }
2167 
2168 /**
2169   * @brief  Disable the SAI and wait for the disabling.
2170   * @param  hsai  pointer to a SAI_HandleTypeDef structure that contains
2171   *               the configuration information for SAI module.
2172   * @retval None
2173   */
SAI_Disable(SAI_HandleTypeDef * hsai)2174 static HAL_StatusTypeDef SAI_Disable(SAI_HandleTypeDef *hsai)
2175 {
2176   uint32_t count = SAI_DEFAULT_TIMEOUT * (SystemCoreClock / 7U / 1000U);
2177   HAL_StatusTypeDef status = HAL_OK;
2178 
2179   /* Disable the SAI instance */
2180   __HAL_SAI_DISABLE(hsai);
2181 
2182   do
2183   {
2184     /* Check for the Timeout */
2185     if (count-- == 0U)
2186     {
2187       /* Update error code */
2188       hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT;
2189       status = HAL_TIMEOUT;
2190       break;
2191     }
2192   }
2193   while ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != RESET);
2194 
2195   return status;
2196 }
2197 
2198 /**
2199   * @brief  Tx Handler for Transmit in Interrupt mode 8-Bit transfer.
2200   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2201   *               the configuration information for SAI module.
2202   * @retval None
2203   */
SAI_Transmit_IT8Bit(SAI_HandleTypeDef * hsai)2204 static void SAI_Transmit_IT8Bit(SAI_HandleTypeDef *hsai)
2205 {
2206   if (hsai->XferCount == 0U)
2207   {
2208     /* Handle the end of the transmission */
2209     /* Disable FREQ and OVRUDR interrupts */
2210     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
2211     hsai->State = HAL_SAI_STATE_READY;
2212 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2213     hsai->TxCpltCallback(hsai);
2214 #else
2215     HAL_SAI_TxCpltCallback(hsai);
2216 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2217   }
2218   else
2219   {
2220     /* Write data on DR register */
2221     hsai->Instance->DR = (*hsai->pBuffPtr++);
2222     hsai->XferCount--;
2223   }
2224 }
2225 
2226 /**
2227   * @brief  Tx Handler for Transmit in Interrupt mode for 16-Bit transfer.
2228   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2229   *               the configuration information for SAI module.
2230   * @retval None
2231   */
SAI_Transmit_IT16Bit(SAI_HandleTypeDef * hsai)2232 static void SAI_Transmit_IT16Bit(SAI_HandleTypeDef *hsai)
2233 {
2234   if (hsai->XferCount == 0U)
2235   {
2236     /* Handle the end of the transmission */
2237     /* Disable FREQ and OVRUDR interrupts */
2238     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
2239     hsai->State = HAL_SAI_STATE_READY;
2240 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2241     hsai->TxCpltCallback(hsai);
2242 #else
2243     HAL_SAI_TxCpltCallback(hsai);
2244 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2245   }
2246   else
2247   {
2248     /* Write data on DR register */
2249     hsai->Instance->DR = *(uint16_t *)hsai->pBuffPtr;
2250     hsai->pBuffPtr += 2U;
2251     hsai->XferCount--;
2252   }
2253 }
2254 
2255 /**
2256   * @brief  Tx Handler for Transmit in Interrupt mode for 32-Bit transfer.
2257   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2258   *               the configuration information for SAI module.
2259   * @retval None
2260   */
SAI_Transmit_IT32Bit(SAI_HandleTypeDef * hsai)2261 static void SAI_Transmit_IT32Bit(SAI_HandleTypeDef *hsai)
2262 {
2263   if (hsai->XferCount == 0U)
2264   {
2265     /* Handle the end of the transmission */
2266     /* Disable FREQ and OVRUDR interrupts */
2267     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
2268     hsai->State = HAL_SAI_STATE_READY;
2269 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2270     hsai->TxCpltCallback(hsai);
2271 #else
2272     HAL_SAI_TxCpltCallback(hsai);
2273 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2274   }
2275   else
2276   {
2277     /* Write data on DR register */
2278     hsai->Instance->DR = *(uint32_t *)hsai->pBuffPtr;
2279     hsai->pBuffPtr += 4U;
2280     hsai->XferCount--;
2281   }
2282 }
2283 
2284 /**
2285   * @brief  Rx Handler for Receive in Interrupt mode 8-Bit transfer.
2286   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2287   *               the configuration information for SAI module.
2288   * @retval None
2289   */
SAI_Receive_IT8Bit(SAI_HandleTypeDef * hsai)2290 static void SAI_Receive_IT8Bit(SAI_HandleTypeDef *hsai)
2291 {
2292   /* Receive data */
2293   (*hsai->pBuffPtr++) = hsai->Instance->DR;
2294   hsai->XferCount--;
2295 
2296   /* Check end of the transfer */
2297   if (hsai->XferCount == 0U)
2298   {
2299     /* Disable TXE and OVRUDR interrupts */
2300     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
2301 
2302     /* Clear the SAI Overrun flag */
2303     __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR);
2304 
2305     hsai->State = HAL_SAI_STATE_READY;
2306 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2307     hsai->RxCpltCallback(hsai);
2308 #else
2309     HAL_SAI_RxCpltCallback(hsai);
2310 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2311   }
2312 }
2313 
2314 /**
2315   * @brief  Rx Handler for Receive in Interrupt mode for 16-Bit transfer.
2316   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2317   *               the configuration information for SAI module.
2318   * @retval None
2319   */
SAI_Receive_IT16Bit(SAI_HandleTypeDef * hsai)2320 static void SAI_Receive_IT16Bit(SAI_HandleTypeDef *hsai)
2321 {
2322   /* Receive data */
2323   *(uint16_t *)hsai->pBuffPtr = hsai->Instance->DR;
2324   hsai->pBuffPtr += 2U;
2325   hsai->XferCount--;
2326 
2327   /* Check end of the transfer */
2328   if (hsai->XferCount == 0U)
2329   {
2330     /* Disable TXE and OVRUDR interrupts */
2331     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
2332 
2333     /* Clear the SAI Overrun flag */
2334     __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR);
2335 
2336     hsai->State = HAL_SAI_STATE_READY;
2337 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2338     hsai->RxCpltCallback(hsai);
2339 #else
2340     HAL_SAI_RxCpltCallback(hsai);
2341 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2342   }
2343 }
2344 
2345 /**
2346   * @brief  Rx Handler for Receive in Interrupt mode for 32-Bit transfer.
2347   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
2348   *               the configuration information for SAI module.
2349   * @retval None
2350   */
SAI_Receive_IT32Bit(SAI_HandleTypeDef * hsai)2351 static void SAI_Receive_IT32Bit(SAI_HandleTypeDef *hsai)
2352 {
2353   /* Receive data */
2354   *(uint32_t *)hsai->pBuffPtr = hsai->Instance->DR;
2355   hsai->pBuffPtr += 4U;
2356   hsai->XferCount--;
2357 
2358   /* Check end of the transfer */
2359   if (hsai->XferCount == 0U)
2360   {
2361     /* Disable TXE and OVRUDR interrupts */
2362     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_IT));
2363 
2364     /* Clear the SAI Overrun flag */
2365     __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR);
2366 
2367     hsai->State = HAL_SAI_STATE_READY;
2368 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2369     hsai->RxCpltCallback(hsai);
2370 #else
2371     HAL_SAI_RxCpltCallback(hsai);
2372 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2373   }
2374 }
2375 
2376 /**
2377   * @brief DMA SAI transmit process complete callback.
2378   * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
2379   *               the configuration information for the specified DMA module.
2380   * @retval None
2381   */
SAI_DMATxCplt(DMA_HandleTypeDef * hdma)2382 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma)
2383 {
2384   SAI_HandleTypeDef *hsai = (SAI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
2385 
2386   if (hdma->Init.Mode != DMA_CIRCULAR)
2387   {
2388     hsai->XferCount = 0U;
2389 
2390     /* Disable SAI Tx DMA Request */
2391     hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN);
2392 
2393     /* Stop the interrupts error handling */
2394     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
2395 
2396     hsai->State = HAL_SAI_STATE_READY;
2397   }
2398 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2399   hsai->TxCpltCallback(hsai);
2400 #else
2401   HAL_SAI_TxCpltCallback(hsai);
2402 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2403 }
2404 
2405 /**
2406   * @brief DMA SAI transmit process half complete callback.
2407   * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
2408   *               the configuration information for the specified DMA module.
2409   * @retval None
2410   */
SAI_DMATxHalfCplt(DMA_HandleTypeDef * hdma)2411 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
2412 {
2413   SAI_HandleTypeDef *hsai = (SAI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
2414 
2415 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2416   hsai->TxHalfCpltCallback(hsai);
2417 #else
2418   HAL_SAI_TxHalfCpltCallback(hsai);
2419 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2420 }
2421 
2422 /**
2423   * @brief DMA SAI receive process complete callback.
2424   * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
2425   *               the configuration information for the specified DMA module.
2426   * @retval None
2427   */
SAI_DMARxCplt(DMA_HandleTypeDef * hdma)2428 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma)
2429 {
2430   SAI_HandleTypeDef *hsai = (SAI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
2431 
2432   if (hdma->Init.Mode != DMA_CIRCULAR)
2433   {
2434     /* Disable Rx DMA Request */
2435     hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN);
2436     hsai->XferCount = 0U;
2437 
2438     /* Stop the interrupts error handling */
2439     __HAL_SAI_DISABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
2440 
2441     hsai->State = HAL_SAI_STATE_READY;
2442   }
2443 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2444   hsai->RxCpltCallback(hsai);
2445 #else
2446   HAL_SAI_RxCpltCallback(hsai);
2447 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2448 }
2449 
2450 /**
2451   * @brief DMA SAI receive process half complete callback
2452   * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
2453   *               the configuration information for the specified DMA module.
2454   * @retval None
2455   */
SAI_DMARxHalfCplt(DMA_HandleTypeDef * hdma)2456 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
2457 {
2458   SAI_HandleTypeDef *hsai = (SAI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
2459 
2460 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2461   hsai->RxHalfCpltCallback(hsai);
2462 #else
2463   HAL_SAI_RxHalfCpltCallback(hsai);
2464 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2465 }
2466 
2467 /**
2468   * @brief DMA SAI communication error callback.
2469   * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
2470   *               the configuration information for the specified DMA module.
2471   * @retval None
2472   */
SAI_DMAError(DMA_HandleTypeDef * hdma)2473 static void SAI_DMAError(DMA_HandleTypeDef *hdma)
2474 {
2475   SAI_HandleTypeDef *hsai = (SAI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
2476 
2477   /* Set SAI error code */
2478   hsai->ErrorCode |= HAL_SAI_ERROR_DMA;
2479 
2480   if ((hsai->hdmatx->ErrorCode == HAL_DMA_ERROR_TE) || (hsai->hdmarx->ErrorCode == HAL_DMA_ERROR_TE))
2481   {
2482     /* Disable the SAI DMA request */
2483     hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
2484 
2485     /* Disable SAI peripheral */
2486     SAI_Disable(hsai);
2487 
2488     /* Set the SAI state ready to be able to start again the process */
2489     hsai->State = HAL_SAI_STATE_READY;
2490 
2491     /* Initialize XferCount */
2492     hsai->XferCount = 0U;
2493   }
2494   /* SAI error Callback */
2495 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2496   hsai->ErrorCallback(hsai);
2497 #else
2498   HAL_SAI_ErrorCallback(hsai);
2499 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2500 }
2501 
2502 /**
2503   * @brief  DMA SAI Abort callback.
2504   * @param  hdma pointer to a DMA_HandleTypeDef structure that contains
2505   *               the configuration information for the specified DMA module.
2506   * @retval None
2507   */
SAI_DMAAbort(DMA_HandleTypeDef * hdma)2508 static void SAI_DMAAbort(DMA_HandleTypeDef *hdma)
2509 {
2510   SAI_HandleTypeDef *hsai = (SAI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
2511 
2512   /* Disable DMA request */
2513   hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN;
2514 
2515   /* Disable all interrupts and clear all flags */
2516   hsai->Instance->IMR = 0U;
2517   hsai->Instance->CLRFR = 0xFFFFFFFFU;
2518 
2519   if (hsai->ErrorCode != HAL_SAI_ERROR_WCKCFG)
2520   {
2521     /* Disable SAI peripheral */
2522     SAI_Disable(hsai);
2523 
2524     /* Flush the fifo */
2525     SET_BIT(hsai->Instance->CR2, SAI_xCR2_FFLUSH);
2526   }
2527   /* Set the SAI state to ready to be able to start again the process */
2528   hsai->State = HAL_SAI_STATE_READY;
2529 
2530   /* Initialize XferCount */
2531   hsai->XferCount = 0U;
2532 
2533   /* SAI error Callback */
2534 #if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
2535   hsai->ErrorCallback(hsai);
2536 #else
2537   HAL_SAI_ErrorCallback(hsai);
2538 #endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
2539 }
2540 
2541 /**
2542   * @}
2543   */
2544 
2545 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */
2546 #endif /* HAL_SAI_MODULE_ENABLED */
2547 /**
2548   * @}
2549   */
2550 
2551 /**
2552   * @}
2553   */
2554 
2555