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