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