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