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