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