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