2 ******************************************************************************
3 * @file stm32f4xx_sai.c
4 * @author MCD Application Team
7 * @brief This file provides firmware functions to manage the following
8 * functionalities of the Serial Audio Interface (SAI):
9 * + Initialization and Configuration
10 * + Data transfers functions
11 * + DMA transfers management
12 * + Interrupts and flags management
15 ===============================================================================
16 ##### How to use this driver #####
17 ===============================================================================
20 (#) Enable peripheral clock using the following functions
21 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SAI1, ENABLE) for SAI1
23 (#) For each SAI Block A/B enable SCK, SD, FS and MCLK GPIO clocks
24 using RCC_AHB1PeriphClockCmd() function.
26 (#) Peripherals alternate function:
27 (++) Connect the pin to the desired peripherals' Alternate
28 Function (AF) using GPIO_PinAFConfig() function.
29 (++) Configure the desired pin in alternate function by:
30 GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF
31 (++) Select the type, pull-up/pull-down and output speed via
32 GPIO_PuPd, GPIO_OType and GPIO_Speed members
33 (++) Call GPIO_Init() function
34 -@@- If an external clock source is used then the I2S CKIN pin should be
35 also configured in Alternate function Push-pull pull-up mode.
37 (#) The SAI clock can be generated from different clock source :
38 PLL I2S, PLL SAI or external clock source.
39 (++) The PLL I2S is configured using the following functions RCC_PLLI2SConfig(),
40 RCC_PLLI2SCmd(ENABLE), RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY) and
41 RCC_SAIPLLI2SClkDivConfig() or;
43 (++) The PLL SAI is configured using the following functions RCC_PLLSAIConfig(),
44 RCC_PLLSAICmd(ENABLE), RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) and
45 RCC_SAIPLLSAIClkDivConfig()or;
47 (++) External clock source is configured using the function
48 RCC_I2SCLKConfig(RCC_I2S2CLKSource_Ext) and after setting correctly the
49 define constant I2S_EXTERNAL_CLOCK_VAL in the stm32f4xx_conf.h file.
51 (#) Each SAI Block A or B has its own clock generator to make these two blocks
52 completely independent. The Clock generator is configured using RCC_SAIBlockACLKConfig() and
53 RCC_SAIBlockBCLKConfig() functions.
55 (#) Each SAI Block A or B can be configured separately :
56 (++) Program the Master clock divider, Audio mode, Protocol, Data Length, Clock Strobing Edge,
57 Synchronous mode, Output drive and FIFO Thresold using SAI_Init() function.
58 In case of master mode, program the Master clock divider (MCKDIV) using
59 the following formula :
60 (+++) MCLK_x = SAI_CK_x / (MCKDIV * 2) with MCLK_x = 256 * FS
61 (+++) FS = SAI_CK_x / (MCKDIV * 2) * 256
62 (+++) MCKDIV = SAI_CK_x / FS * 512
63 (++) Program the Frame Length, Frame active Length, FS Definition, FS Polarity,
64 FS Offset using SAI_FrameInit() function.
65 (++) Program the Slot First Bit Offset, Slot Size, Slot Number, Slot Active
66 using SAI_SlotInit() function.
68 (#) Enable the NVIC and the corresponding interrupt using the function
69 SAI_ITConfig() if you need to use interrupt mode.
71 (#) When using the DMA mode
72 (++) Configure the DMA using DMA_Init() function
73 (++) Active the needed channel Request using SAI_DMACmd() function
75 (#) Enable the SAI using the SAI_Cmd() function.
77 (#) Enable the DMA using the DMA_Cmd() function when using DMA mode.
79 (#) The SAI has some specific functions which can be useful depending
80 on the audio protocol selected.
81 (++) Enable Mute mode when the audio block is a transmitter using SAI_MuteModeCmd()
82 function and configure the value transmitted during mute using SAI_MuteValueConfig().
83 (++) Detect the Mute mode when audio block is a receiver using SAI_MuteFrameCounterConfig().
84 (++) Enable the MONO mode without any data preprocessing in memory when the number
85 of slot is equal to 2 using SAI_MonoModeConfig() function.
86 (++) Enable data companding algorithm (U law and A law) using SAI_CompandingModeConfig().
87 (++) Choose the behavior of the SD line in output when an inactive slot is sent
88 on the data line using SAI_TRIStateConfig() function.
90 (@) In master TX mode: enabling the audio block immediately generates the bit clock
91 for the external slaves even if there is no data in the FIFO, However FS signal
92 generation is conditioned by the presence of data in the FIFO.
94 (@) In master RX mode: enabling the audio block immediately generates the bit clock
95 and FS signal for the external slaves.
97 (@) It is mandatory to respect the following conditions in order to avoid bad SAI behavior:
98 (+@) First bit Offset <= (SLOT size - Data size)
99 (+@) Data size <= SLOT size
100 (+@) Number of SLOT x SLOT size = Frame length
101 (+@) The number of slots should be even when bit FSDEF in the SAI_xFRCR is set.
105 ******************************************************************************
108 * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2>
110 * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
111 * You may not use this file except in compliance with the License.
112 * You may obtain a copy of the License at:
114 * http://www.st.com/software_license_agreement_liberty_v2
116 * Unless required by applicable law or agreed to in writing, software
117 * distributed under the License is distributed on an "AS IS" BASIS,
118 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
119 * See the License for the specific language governing permissions and
120 * limitations under the License.
122 ******************************************************************************
125 /* Includes ------------------------------------------------------------------*/
126 #include "stm32f4xx_sai.h"
127 #include "stm32f4xx_rcc.h"
129 /** @addtogroup STM32F4xx_StdPeriph_Driver
134 * @brief SAI driver modules
137 #if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx) || \
138 defined (STM32F401xx) || defined (STM32F411xE) || defined (STM32F446xx) || defined (STM32F469_479xx)
140 /* Private typedef -----------------------------------------------------------*/
141 /* Private define ------------------------------------------------------------*/
143 /* *SAI registers Masks */
144 #define CR1_CLEAR_MASK ((uint32_t)0xFF07C010)
145 #define FRCR_CLEAR_MASK ((uint32_t)0xFFF88000)
146 #define SLOTR_CLEAR_MASK ((uint32_t)0x0000F020)
148 /* Private macro -------------------------------------------------------------*/
149 /* Private variables ---------------------------------------------------------*/
150 /* Private function prototypes -----------------------------------------------*/
151 /* Private functions ---------------------------------------------------------*/
153 /** @defgroup SAI_Private_Functions
157 /** @defgroup SAI_Group1 Initialization and Configuration functions
158 * @brief Initialization and Configuration functions
161 ===============================================================================
162 ##### Initialization and Configuration functions #####
163 ===============================================================================
165 This section provides a set of functions allowing to initialize the SAI Audio
166 Block Mode, Audio Protocol, Data size, Synchronization between audio block,
167 Master clock Divider, Fifo threshold, Frame configuration, slot configuration,
168 Tristate mode, Companding mode and Mute mode.
170 The SAI_Init(), SAI_FrameInit() and SAI_SlotInit() functions follows the SAI Block
171 configuration procedures for Master mode and Slave mode (details for these procedures
172 are available in reference manual(RM0090).
179 * @brief Deinitialize the SAIx peripheral registers to their default reset values.
180 * @param SAIx: To select the SAIx peripheral, where x can be the different instances
184 void SAI_DeInit(SAI_TypeDef
* SAIx
)
186 /* Check the parameters */
187 assert_param(IS_SAI_PERIPH(SAIx
));
191 /* Enable SAI1 reset state */
192 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SAI1
, ENABLE
);
193 /* Release SAI1 from reset state */
194 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SAI1
, DISABLE
);
198 #if defined(STM32F446xx)
201 /* Enable SAI2 reset state */
202 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SAI2
, ENABLE
);
203 /* Release SAI2 from reset state */
204 RCC_APB2PeriphResetCmd(RCC_APB2Periph_SAI2
, DISABLE
);
206 #endif /* STM32F446xx */
211 * @brief Initializes the SAI Block x peripheral according to the specified
212 * parameters in the SAI_InitStruct.
214 * @note SAI clock is generated from a specific output of the PLLSAI or a specific
215 * output of the PLLI2S or from an alternate function bypassing the PLL I2S.
217 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
218 * @param SAI_InitStruct: pointer to a SAI_InitTypeDef structure that
219 * contains the configuration information for the specified SAI Block peripheral.
222 void SAI_Init(SAI_Block_TypeDef
* SAI_Block_x
, SAI_InitTypeDef
* SAI_InitStruct
)
226 /* Check the parameters */
227 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
229 /* Check the SAI Block parameters */
230 assert_param(IS_SAI_BLOCK_MODE(SAI_InitStruct
->SAI_AudioMode
));
231 assert_param(IS_SAI_BLOCK_PROTOCOL(SAI_InitStruct
->SAI_Protocol
));
232 assert_param(IS_SAI_BLOCK_DATASIZE(SAI_InitStruct
->SAI_DataSize
));
233 assert_param(IS_SAI_BLOCK_FIRST_BIT(SAI_InitStruct
->SAI_FirstBit
));
234 assert_param(IS_SAI_BLOCK_CLOCK_STROBING(SAI_InitStruct
->SAI_ClockStrobing
));
235 assert_param(IS_SAI_BLOCK_SYNCHRO(SAI_InitStruct
->SAI_Synchro
));
236 assert_param(IS_SAI_BLOCK_OUTPUT_DRIVE(SAI_InitStruct
->SAI_OUTDRIV
));
237 assert_param(IS_SAI_BLOCK_NODIVIDER(SAI_InitStruct
->SAI_NoDivider
));
238 assert_param(IS_SAI_BLOCK_MASTER_DIVIDER(SAI_InitStruct
->SAI_MasterDivider
));
239 assert_param(IS_SAI_BLOCK_FIFO_THRESHOLD(SAI_InitStruct
->SAI_FIFOThreshold
));
241 /* SAI Block_x CR1 Configuration */
242 /* Get the SAI Block_x CR1 value */
243 tmpreg
= SAI_Block_x
->CR1
;
244 /* Clear MODE, PRTCFG, DS, LSBFIRST, CKSTR, SYNCEN, OUTDRIV, NODIV, and MCKDIV bits */
245 tmpreg
&= CR1_CLEAR_MASK
;
246 /* Configure SAI_Block_x: Audio mode, Protocol, Data Size, first transmitted bit, Clock strobing
247 edge, Synchronization mode, Output drive, Master Divider and FIFO level */
248 /* Set MODE bits according to SAI_AudioMode value */
249 /* Set PRTCFG bits according to SAI_Protocol value */
250 /* Set DS bits according to SAI_DataSize value */
251 /* Set LSBFIRST bit according to SAI_FirstBit value */
252 /* Set CKSTR bit according to SAI_ClockStrobing value */
253 /* Set SYNCEN bit according to SAI_Synchro value */
254 /* Set OUTDRIV bit according to SAI_OUTDRIV value */
255 /* Set NODIV bit according to SAI_NoDivider value */
256 /* Set MCKDIV bits according to SAI_MasterDivider value */
257 tmpreg
|= (uint32_t)(SAI_InitStruct
->SAI_AudioMode
| SAI_InitStruct
->SAI_Protocol
|
258 SAI_InitStruct
->SAI_DataSize
| SAI_InitStruct
->SAI_FirstBit
|
259 SAI_InitStruct
->SAI_ClockStrobing
| SAI_InitStruct
->SAI_Synchro
|
260 SAI_InitStruct
->SAI_OUTDRIV
| SAI_InitStruct
->SAI_NoDivider
|
261 (uint32_t)((SAI_InitStruct
->SAI_MasterDivider
) << 20));
262 /* Write to SAI_Block_x CR1 */
263 SAI_Block_x
->CR1
= tmpreg
;
265 /* SAI Block_x CR2 Configuration */
266 /* Get the SAIBlock_x CR2 value */
267 tmpreg
= SAI_Block_x
->CR2
;
269 tmpreg
&= ~(SAI_xCR2_FTH
);
270 /* Configure the FIFO Level */
271 /* Set FTH bits according to SAI_FIFOThreshold value */
272 tmpreg
|= (uint32_t)(SAI_InitStruct
->SAI_FIFOThreshold
);
273 /* Write to SAI_Block_x CR2 */
274 SAI_Block_x
->CR2
= tmpreg
;
278 * @brief Initializes the SAI Block Audio frame according to the specified
279 * parameters in the SAI_FrameInitStruct.
281 * @note this function has no meaning if the AC'97 or SPDIF audio protocol
284 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
285 * @param SAI_FrameInitStruct: pointer to an SAI_FrameInitTypeDef structure that
286 * contains the configuration of audio frame for a specified SAI Block
289 void SAI_FrameInit(SAI_Block_TypeDef
* SAI_Block_x
, SAI_FrameInitTypeDef
* SAI_FrameInitStruct
)
293 /* Check the parameters */
294 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
296 /* Check the SAI Block frame parameters */
297 assert_param(IS_SAI_BLOCK_FRAME_LENGTH(SAI_FrameInitStruct
->SAI_FrameLength
));
298 assert_param(IS_SAI_BLOCK_ACTIVE_FRAME(SAI_FrameInitStruct
->SAI_ActiveFrameLength
));
299 assert_param(IS_SAI_BLOCK_FS_DEFINITION(SAI_FrameInitStruct
->SAI_FSDefinition
));
300 assert_param(IS_SAI_BLOCK_FS_POLARITY(SAI_FrameInitStruct
->SAI_FSPolarity
));
301 assert_param(IS_SAI_BLOCK_FS_OFFSET(SAI_FrameInitStruct
->SAI_FSOffset
));
303 /* SAI Block_x FRCR Configuration */
304 /* Get the SAI Block_x FRCR value */
305 tmpreg
= SAI_Block_x
->FRCR
;
306 /* Clear FRL, FSALL, FSDEF, FSPOL, FSOFF bits */
307 tmpreg
&= FRCR_CLEAR_MASK
;
308 /* Configure SAI_Block_x Frame: Frame Length, Active Frame Length, Frame Synchronization
309 Definition, Frame Synchronization Polarity and Frame Synchronization Polarity */
310 /* Set FRL bits according to SAI_FrameLength value */
311 /* Set FSALL bits according to SAI_ActiveFrameLength value */
312 /* Set FSDEF bit according to SAI_FSDefinition value */
313 /* Set FSPOL bit according to SAI_FSPolarity value */
314 /* Set FSOFF bit according to SAI_FSOffset value */
315 tmpreg
|= (uint32_t)((uint32_t)(SAI_FrameInitStruct
->SAI_FrameLength
- 1) |
316 SAI_FrameInitStruct
->SAI_FSOffset
|
317 SAI_FrameInitStruct
->SAI_FSDefinition
|
318 SAI_FrameInitStruct
->SAI_FSPolarity
|
319 (uint32_t)((SAI_FrameInitStruct
->SAI_ActiveFrameLength
- 1) << 8));
321 /* Write to SAI_Block_x FRCR */
322 SAI_Block_x
->FRCR
= tmpreg
;
326 * @brief Initializes the SAI Block audio Slot according to the specified
327 * parameters in the SAI_SlotInitStruct.
329 * @note this function has no meaning if the AC'97 or SPDIF audio protocol
332 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
333 * @param SAI_SlotInitStruct: pointer to an SAI_SlotInitTypeDef structure that
334 * contains the configuration of audio slot for a specified SAI Block
337 void SAI_SlotInit(SAI_Block_TypeDef
* SAI_Block_x
, SAI_SlotInitTypeDef
* SAI_SlotInitStruct
)
341 /* Check the parameters */
342 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
344 /* Check the SAI Block Slot parameters */
345 assert_param(IS_SAI_BLOCK_FIRSTBIT_OFFSET(SAI_SlotInitStruct
->SAI_FirstBitOffset
));
346 assert_param(IS_SAI_BLOCK_SLOT_SIZE(SAI_SlotInitStruct
->SAI_SlotSize
));
347 assert_param(IS_SAI_BLOCK_SLOT_NUMBER(SAI_SlotInitStruct
->SAI_SlotNumber
));
348 assert_param(IS_SAI_SLOT_ACTIVE(SAI_SlotInitStruct
->SAI_SlotActive
));
350 /* SAI Block_x SLOTR Configuration */
351 /* Get the SAI Block_x SLOTR value */
352 tmpreg
= SAI_Block_x
->SLOTR
;
353 /* Clear FBOFF, SLOTSZ, NBSLOT, SLOTEN bits */
354 tmpreg
&= SLOTR_CLEAR_MASK
;
355 /* Configure SAI_Block_x Slot: First bit offset, Slot size, Number of Slot in
356 audio frame and slots activated in audio frame */
357 /* Set FBOFF bits according to SAI_FirstBitOffset value */
358 /* Set SLOTSZ bits according to SAI_SlotSize value */
359 /* Set NBSLOT bits according to SAI_SlotNumber value */
360 /* Set SLOTEN bits according to SAI_SlotActive value */
361 tmpreg
|= (uint32_t)(SAI_SlotInitStruct
->SAI_FirstBitOffset
|
362 SAI_SlotInitStruct
->SAI_SlotSize
|
363 SAI_SlotInitStruct
->SAI_SlotActive
|
364 (uint32_t)((SAI_SlotInitStruct
->SAI_SlotNumber
- 1) << 8));
366 /* Write to SAI_Block_x SLOTR */
367 SAI_Block_x
->SLOTR
= tmpreg
;
371 * @brief Fills each SAI_InitStruct member with its default value.
372 * @param SAI_InitStruct: pointer to a SAI_InitTypeDef structure which will
376 void SAI_StructInit(SAI_InitTypeDef
* SAI_InitStruct
)
378 /* Reset SAI init structure parameters values */
379 /* Initialize the SAI_AudioMode member */
380 SAI_InitStruct
->SAI_AudioMode
= SAI_Mode_MasterTx
;
381 /* Initialize the SAI_Protocol member */
382 SAI_InitStruct
->SAI_Protocol
= SAI_Free_Protocol
;
383 /* Initialize the SAI_DataSize member */
384 SAI_InitStruct
->SAI_DataSize
= SAI_DataSize_8b
;
385 /* Initialize the SAI_FirstBit member */
386 SAI_InitStruct
->SAI_FirstBit
= SAI_FirstBit_MSB
;
387 /* Initialize the SAI_ClockStrobing member */
388 SAI_InitStruct
->SAI_ClockStrobing
= SAI_ClockStrobing_FallingEdge
;
389 /* Initialize the SAI_Synchro member */
390 SAI_InitStruct
->SAI_Synchro
= SAI_Asynchronous
;
391 /* Initialize the SAI_OUTDRIV member */
392 SAI_InitStruct
->SAI_OUTDRIV
= SAI_OutputDrive_Disabled
;
393 /* Initialize the SAI_NoDivider member */
394 SAI_InitStruct
->SAI_NoDivider
= SAI_MasterDivider_Enabled
;
395 /* Initialize the SAI_MasterDivider member */
396 SAI_InitStruct
->SAI_MasterDivider
= 0;
397 /* Initialize the SAI_FIFOThreshold member */
398 SAI_InitStruct
->SAI_FIFOThreshold
= SAI_Threshold_FIFOEmpty
;
402 * @brief Fills each SAI_FrameInitStruct member with its default value.
403 * @param SAI_FrameInitStruct: pointer to a SAI_FrameInitTypeDef structure
404 * which will be initialized.
407 void SAI_FrameStructInit(SAI_FrameInitTypeDef
* SAI_FrameInitStruct
)
409 /* Reset SAI Frame init structure parameters values */
410 /* Initialize the SAI_FrameLength member */
411 SAI_FrameInitStruct
->SAI_FrameLength
= 8;
412 /* Initialize the SAI_ActiveFrameLength member */
413 SAI_FrameInitStruct
->SAI_ActiveFrameLength
= 1;
414 /* Initialize the SAI_FSDefinition member */
415 SAI_FrameInitStruct
->SAI_FSDefinition
= SAI_FS_StartFrame
;
416 /* Initialize the SAI_FSPolarity member */
417 SAI_FrameInitStruct
->SAI_FSPolarity
= SAI_FS_ActiveLow
;
418 /* Initialize the SAI_FSOffset member */
419 SAI_FrameInitStruct
->SAI_FSOffset
= SAI_FS_FirstBit
;
423 * @brief Fills each SAI_SlotInitStruct member with its default value.
424 * @param SAI_SlotInitStruct: pointer to a SAI_SlotInitTypeDef structure
425 * which will be initialized.
428 void SAI_SlotStructInit(SAI_SlotInitTypeDef
* SAI_SlotInitStruct
)
430 /* Reset SAI Slot init structure parameters values */
431 /* Initialize the SAI_FirstBitOffset member */
432 SAI_SlotInitStruct
->SAI_FirstBitOffset
= 0;
433 /* Initialize the SAI_SlotSize member */
434 SAI_SlotInitStruct
->SAI_SlotSize
= SAI_SlotSize_DataSize
;
435 /* Initialize the SAI_SlotNumber member */
436 SAI_SlotInitStruct
->SAI_SlotNumber
= 1;
437 /* Initialize the SAI_SlotActive member */
438 SAI_SlotInitStruct
->SAI_SlotActive
= SAI_Slot_NotActive
;
443 * @brief Enables or disables the specified SAI Block peripheral.
444 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
445 * @param NewState: new state of the SAI_Block_x peripheral.
446 * This parameter can be: ENABLE or DISABLE.
449 void SAI_Cmd(SAI_Block_TypeDef
* SAI_Block_x
, FunctionalState NewState
)
451 /* Check the parameters */
452 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
453 assert_param(IS_FUNCTIONAL_STATE(NewState
));
454 if (NewState
!= DISABLE
)
456 /* Enable the selected SAI peripheral */
457 SAI_Block_x
->CR1
|= SAI_xCR1_SAIEN
;
461 /* Disable the selected SAI peripheral */
462 SAI_Block_x
->CR1
&= ~(SAI_xCR1_SAIEN
);
467 * @brief Configures the mono mode for the selected SAI block.
469 * @note This function has a meaning only when the number of slot is equal to 2.
471 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
472 * @param SAI_MonoMode: specifies the SAI block mono mode.
473 * This parameter can be one of the following values:
474 * @arg SAI_MonoMode : Set mono audio mode
475 * @arg SAI_StreoMode : Set streo audio mode
478 void SAI_MonoModeConfig(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_Mono_StreoMode
)
480 /* Check the parameters */
481 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
482 assert_param(IS_SAI_BLOCK_MONO_STREO_MODE(SAI_MonoMode
));
484 SAI_Block_x
->CR1
&= ~(SAI_xCR1_MONO
);
485 /* Set new Mono Mode value */
486 SAI_Block_x
->CR1
|= SAI_MonoMode
;
490 * @brief Configures the TRIState management on data line for the selected SAI block.
492 * @note This function has a meaning only when the SAI block is configured in transmitter
494 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
495 * @param SAI_TRIState: specifies the SAI block TRIState management.
496 * This parameter can be one of the following values:
497 * @arg SAI_Output_NotReleased : SD output line is still driven by the SAI.
498 * @arg SAI_Output_Released : SD output line is released (HI-Z)
501 void SAI_TRIStateConfig(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_TRIState
)
503 /* Check the parameters */
504 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
505 assert_param(IS_SAI_BLOCK_TRISTATE_MANAGEMENT(SAI_TRIState
));
507 SAI_Block_x
->CR1
&= ~(SAI_xCR1_MONO
);
508 /* Set new Mono Mode value */
509 SAI_Block_x
->CR1
|= SAI_MonoMode
;
514 * @brief Configures the companding mode for the selected SAI block.
516 * @note The data expansion or data compression are determined by the state of
517 * SAI block selected (transmitter or receiver).
519 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
520 * @param SAI_CompandingMode: specifies the SAI block companding mode.
521 * This parameter can be one of the following values:
522 * @arg SAI_NoCompanding : no companding algorithm set
523 * @arg SAI_ULaw_1CPL_Companding : Set U law (algorithm 1's complement representation)
524 * @arg SAI_ALaw_1CPL_Companding : Set A law (algorithm 1's complement representation)
525 * @arg SAI_ULaw_2CPL_Companding : Set U law (algorithm 2's complement representation)
526 * @arg SAI_ALaw_2CPL_Companding : Set A law (algorithm 2's complement representation)
529 void SAI_CompandingModeConfig(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_CompandingMode
)
531 /* Check the parameters */
532 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
533 assert_param(IS_SAI_BLOCK_COMPANDING_MODE(SAI_CompandingMode
));
534 /* Clear Companding Mode bits */
535 SAI_Block_x
->CR2
&= ~(SAI_xCR2_COMP
);
536 /* Set new Companding Mode value */
537 SAI_Block_x
->CR2
|= SAI_CompandingMode
;
541 * @brief Enables or disables the Mute mode for the selected SAI block.
543 * @note This function has a meaning only when the audio block is transmitter
544 * @note Mute mode is applied for an entire frame for all the valid slot
545 * It becomes active at the end of an audio frame when set somewhere in a frame.
546 * Mute mode exit occurs at the end of the frame in which the bit MUTE has been set.
548 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
549 * @param NewState: new state of the SAIx block.
550 * This parameter can be: ENABLE or DISABLE.
553 void SAI_MuteModeCmd(SAI_Block_TypeDef
* SAI_Block_x
, FunctionalState NewState
)
555 /* Check the parameters */
556 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
557 assert_param(IS_FUNCTIONAL_STATE(NewState
));
558 if (NewState
!= DISABLE
)
560 /* Enable the selected SAI block mute mode */
561 SAI_Block_x
->CR2
|= SAI_xCR2_MUTE
;
565 /* Disable the selected SAI SS output */
566 SAI_Block_x
->CR2
&= ~(SAI_xCR2_MUTE
);
571 * @brief Configure the mute value for the selected SAI block.
573 * @note This function has a meaning only when the audio block is transmitter
574 * @note the configuration last value sent during mute mode has only a meaning
575 * when the number of slot is lower or equal to 2 and if the MUTE bit is set.
577 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
578 * @param SAI_MuteValue: specifies the SAI block mute value.
579 * This parameter can be one of the following values:
580 * @arg SAI_ZeroValue : bit value 0 is sent during Mute Mode
581 * @arg SAI_LastSentValue : Last value is sent during Mute Mode
584 void SAI_MuteValueConfig(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_MuteValue
)
586 /* Check the parameters */
587 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
588 assert_param(IS_SAI_BLOCK_MUTE_VALUE(SAI_MuteValue
));
590 /* Clear Mute value bits */
591 SAI_Block_x
->CR2
&= ~(SAI_xCR2_MUTEVAL
);
592 /* Set new Mute value */
593 SAI_Block_x
->CR2
|= SAI_MuteValue
;
597 * @brief Enables or disables the Mute mode for the selected SAI block.
599 * @note This function has a meaning only when the audio block is Receiver
600 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
601 * @param SAI_MuteCounter: specifies the SAI block mute value.
602 * This parameter can be a number between 0 and 63.
606 void SAI_MuteFrameCounterConfig(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_MuteCounter
)
608 /* Check the parameters */
609 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
610 assert_param(IS_SAI_BLOCK_MUTE_COUNTER(SAI_MuteCounter
));
612 /* Clear Mute value bits */
613 SAI_Block_x
->CR2
&= ~(SAI_xCR2_MUTECNT
);
614 /* Set new Mute value */
615 SAI_Block_x
->CR2
|= (SAI_MuteCounter
<< 7);
619 * @brief Reinitialize the FIFO pointer
621 * @note The FIFO pointers can be reinitialized at anytime The data present
622 * into the FIFO, if it is not empty, will be lost.
624 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
625 * @param NewState: new state of the selected SAI TI communication mode.
626 * This parameter can be: ENABLE or DISABLE.
629 void SAI_FlushFIFO(SAI_Block_TypeDef
* SAI_Block_x
)
631 /* Check the parameters */
632 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
635 SAI_Block_x
->CR2
|= SAI_xCR2_FFLUSH
;
642 /** @defgroup SAI_Group2 Data transfers functions
643 * @brief Data transfers functions
646 ===============================================================================
647 ##### Data transfers functions #####
648 ===============================================================================
650 This section provides a set of functions allowing to manage the SAI data transfers.
652 In reception, data are received and then stored into an internal FIFO while
653 In transmission, data are first stored into an internal FIFO before being
656 The read access of the SAI_xDR register can be done using the SAI_ReceiveData()
657 function and returns the Rx buffered value. Whereas a write access to the SAI_DR
658 can be done using SAI_SendData() function and stores the written data into
666 * @brief Returns the most recent received data by the SAI block x peripheral.
667 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
669 * @retval The value of the received data.
671 uint32_t SAI_ReceiveData(SAI_Block_TypeDef
* SAI_Block_x
)
673 /* Check the parameters */
674 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
676 /* Return the data in the DR register */
677 return SAI_Block_x
->DR
;
681 * @brief Transmits a Data through the SAI block x peripheral.
682 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
684 * @param Data: Data to be transmitted.
687 void SAI_SendData(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t Data
)
689 /* Check the parameters */
690 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
692 /* Write in the DR register the data to be sent */
693 SAI_Block_x
->DR
= Data
;
700 /** @defgroup SAI_Group3 DMA transfers management functions
701 * @brief DMA transfers management functions
704 ===============================================================================
705 ##### DMA transfers management functions #####
706 ===============================================================================
713 * @brief Enables or disables the SAI Block x DMA interface.
714 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
715 * @param NewState: new state of the selected SAI block DMA transfer request.
716 * This parameter can be: ENABLE or DISABLE.
719 void SAI_DMACmd(SAI_Block_TypeDef
* SAI_Block_x
, FunctionalState NewState
)
721 /* Check the parameters */
722 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
723 assert_param(IS_FUNCTIONAL_STATE(NewState
));
725 if (NewState
!= DISABLE
)
727 /* Enable the selected SAI block mute mode */
728 SAI_Block_x
->CR1
|= SAI_xCR1_DMAEN
;
732 /* Disable the selected SAI SS output */
733 SAI_Block_x
->CR1
&= ~(SAI_xCR1_DMAEN
);
741 /** @defgroup SAI_Group4 Interrupts and flags management functions
742 * @brief Interrupts and flags management functions
745 ===============================================================================
746 ##### Interrupts and flags management functions #####
747 ===============================================================================
749 This section provides a set of functions allowing to configure the SAI Interrupts
750 sources and check or clear the flags or pending bits status.
751 The user should identify which mode will be used in his application to manage
752 the communication: Polling mode, Interrupt mode or DMA mode.
757 In Polling Mode, the SAI communication can be managed by 7 flags:
758 (#) SAI_FLAG_FREQ : to indicate if there is a FIFO Request to write or to read.
759 (#) SAI_FLAG_MUTEDET : to indicate if a MUTE frame detected
760 (#) SAI_FLAG_OVRUDR : to indicate if an Overrun or Underrun error occur
761 (#) SAI_FLAG_AFSDET : to indicate if there is the detection of a audio frame
762 synchronisation (FS) earlier than expected
763 (#) SAI_FLAG_LFSDET : to indicate if there is the detection of a audio frame
764 synchronisation (FS) later than expected
765 (#) SAI_FLAG_CNRDY : to indicate if the codec is not ready to communicate during
766 the reception of the TAG 0 (slot0) of the AC97 audio frame
767 (#) SAI_FLAG_WCKCFG: to indicate if wrong clock configuration in master mode
770 In this Mode it is advised to use the following functions:
771 (+) FlagStatus SAI_GetFlagStatus(SAI_Block_TypeDef* SAI_Block_x, uint32_t SAI_FLAG);
772 (+) void SAI_ClearFlag(SAI_Block_TypeDef* SAI_Block_x, uint32_t SAI_FLAG);
774 *** Interrupt Mode ***
775 ======================
777 In Interrupt Mode, the SAI communication can be managed by 7 interrupt sources
780 (##) SAI_IT_FREQ : to indicate if there is a FIFO Request to write or to read.
781 (##) SAI_IT_MUTEDET : to indicate if a MUTE frame detected.
782 (##) SAI_IT_OVRUDR : to indicate if an Overrun or Underrun error occur.
783 (##) SAI_IT_AFSDET : to indicate if there is the detection of a audio frame
784 synchronisation (FS) earlier than expected.
785 (##) SAI_IT_LFSDET : to indicate if there is the detection of a audio frame
786 synchronisation (FS) later than expected.
787 (##) SAI_IT_CNRDY : to indicate if the codec is not ready to communicate during
788 the reception of the TAG 0 (slot0) of the AC97 audio frame.
789 (##) SAI_IT_WCKCFG: to indicate if wrong clock configuration in master mode
792 (+) Interrupt Source:
793 (##) SAI_IT_FREQ : specifies the interrupt source for FIFO Request.
794 (##) SAI_IT_MUTEDET : specifies the interrupt source for MUTE frame detected.
795 (##) SAI_IT_OVRUDR : specifies the interrupt source for overrun or underrun error.
796 (##) SAI_IT_AFSDET : specifies the interrupt source for anticipated frame synchronization
798 (##) SAI_IT_LFSDET : specifies the interrupt source for late frame synchronization
800 (##) SAI_IT_CNRDY : specifies the interrupt source for codec not ready interrupt
801 (##) SAI_IT_WCKCFG: specifies the interrupt source for wrong clock configuration
804 In this Mode it is advised to use the following functions:
805 (+) void SAI_ITConfig(SAI_Block_TypeDef* SAI_Block_x, uint32_t SAI_IT, FunctionalState NewState);
806 (+) ITStatus SAI_GetITStatus(SAI_Block_TypeDef* SAI_Block_x, uint32_t SAI_IT);
807 (+) void SAI_ClearITPendingBit(SAI_Block_TypeDef* SAI_Block_x, uint32_t SAI_IT);
812 In DMA Mode, each SAI audio block has an independent DMA interface in order to
813 read or to write into the SAI_xDR register (to hit the internal FIFO).
814 There is one DMA channel by audio block following basic DMA request/acknowledge
817 In this Mode it is advised to use the following function:
818 (+) void SAI_DMACmd(SAI_Block_TypeDef* SAI_Block_x, FunctionalState NewState);
820 This section provides also functions allowing to
821 (+) Check the SAI Block enable status
822 (+)Check the FIFO status
824 *** SAI Block Enable status ***
825 ===============================
827 After disabling a SAI Block, it is recommended to check (or wait until) the SAI Block
828 is effectively disabled. If a Block is disabled while an audio frame transfer is ongoing
829 the current frame will be transferred and the block will be effectively disabled only at
830 the end of audio frame.
831 To monitor this state it is possible to use the following function:
832 (+) FunctionalState SAI_GetCmdStatus(SAI_Block_TypeDef* SAI_Block_x);
834 *** SAI Block FIFO status ***
835 =============================
837 It is possible to monitor the FIFO status when a transfer is ongoing using the following
839 (+) uint32_t SAI_GetFIFOStatus(SAI_Block_TypeDef* SAI_Block_x);
846 * @brief Enables or disables the specified SAI Block interrupts.
847 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
848 * @param SAI_IT: specifies the SAI interrupt source to be enabled or disabled.
849 * This parameter can be one of the following values:
850 * @arg SAI_IT_FREQ: FIFO Request interrupt mask
851 * @arg SAI_IT_MUTEDET: MUTE detection interrupt mask
852 * @arg SAI_IT_OVRUDR: overrun/underrun interrupt mask
853 * @arg SAI_IT_AFSDET: anticipated frame synchronization detection
855 * @arg SAI_IT_LFSDET: late frame synchronization detection interrupt
857 * @arg SAI_IT_CNRDY: codec not ready interrupt mask
858 * @arg SAI_IT_WCKCFG: wrong clock configuration interrupt mask
859 * @param NewState: new state of the specified SAI interrupt.
860 * This parameter can be: ENABLE or DISABLE.
863 void SAI_ITConfig(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_IT
, FunctionalState NewState
)
865 /* Check the parameters */
866 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
867 assert_param(IS_FUNCTIONAL_STATE(NewState
));
868 assert_param(IS_SAI_BLOCK_CONFIG_IT(SAI_IT
));
870 if (NewState
!= DISABLE
)
872 /* Enable the selected SAI Block interrupt */
873 SAI_Block_x
->IMR
|= SAI_IT
;
877 /* Disable the selected SAI Block interrupt */
878 SAI_Block_x
->IMR
&= ~(SAI_IT
);
883 * @brief Checks whether the specified SAI block x flag is set or not.
884 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
885 * @param SAI_FLAG: specifies the SAI block flag to check.
886 * This parameter can be one of the following values:
887 * @arg SAI_FLAG_FREQ: FIFO Request flag.
888 * @arg SAI_FLAG_MUTEDET: MUTE detection flag.
889 * @arg SAI_FLAG_OVRUDR: overrun/underrun flag.
890 * @arg SAI_FLAG_WCKCFG: wrong clock configuration flag.
891 * @arg SAI_FLAG_CNRDY: codec not ready flag.
892 * @arg SAI_FLAG_AFSDET: anticipated frame synchronization detection flag.
893 * @arg SAI_FLAG_LFSDET: late frame synchronization detection flag.
894 * @retval The new state of SAI_FLAG (SET or RESET).
896 FlagStatus
SAI_GetFlagStatus(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_FLAG
)
898 FlagStatus bitstatus
= RESET
;
900 /* Check the parameters */
901 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
902 assert_param(IS_SAI_BLOCK_GET_FLAG(SAI_FLAG
));
904 /* Check the status of the specified SAI flag */
905 if ((SAI_Block_x
->SR
& SAI_FLAG
) != (uint32_t)RESET
)
907 /* SAI_FLAG is set */
912 /* SAI_FLAG is reset */
915 /* Return the SAI_FLAG status */
920 * @brief Clears the specified SAI Block x flag.
921 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
922 * @param SAI_FLAG: specifies the SAI block flag to check.
923 * This parameter can be one of the following values:
924 * @arg SAI_FLAG_MUTEDET: MUTE detection flag.
925 * @arg SAI_FLAG_OVRUDR: overrun/underrun flag.
926 * @arg SAI_FLAG_WCKCFG: wrong clock configuration flag.
927 * @arg SAI_FLAG_CNRDY: codec not ready flag.
928 * @arg SAI_FLAG_AFSDET: anticipated frame synchronization detection flag.
929 * @arg SAI_FLAG_LFSDET: late frame synchronization detection flag.
931 * @note FREQ (FIFO Request) flag is cleared :
932 * - When the audio block is transmitter and the FIFO is full or the FIFO
933 * has one data (one buffer mode) depending the bit FTH in the
935 * - When the audio block is receiver and the FIFO is not empty
939 void SAI_ClearFlag(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_FLAG
)
941 /* Check the parameters */
942 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
943 assert_param(IS_SAI_BLOCK_CLEAR_FLAG(SAI_FLAG
));
945 /* Clear the selected SAI Block flag */
946 SAI_Block_x
->CLRFR
|= SAI_FLAG
;
950 * @brief Checks whether the specified SAI Block x interrupt has occurred or not.
951 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
952 * @param SAI_IT: specifies the SAI interrupt source to be enabled or disabled.
953 * This parameter can be one of the following values:
954 * @arg SAI_IT_FREQ: FIFO Request interrupt
955 * @arg SAI_IT_MUTEDET: MUTE detection interrupt
956 * @arg SAI_IT_OVRUDR: overrun/underrun interrupt
957 * @arg SAI_IT_AFSDET: anticipated frame synchronization detection interrupt
958 * @arg SAI_IT_LFSDET: late frame synchronization detection interrupt
959 * @arg SAI_IT_CNRDY: codec not ready interrupt
960 * @arg SAI_IT_WCKCFG: wrong clock configuration interrupt
962 * @retval The new state of SAI_IT (SET or RESET).
964 ITStatus
SAI_GetITStatus(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_IT
)
966 ITStatus bitstatus
= RESET
;
967 uint32_t enablestatus
= 0;
969 /* Check the parameters */
970 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
971 assert_param(IS_SAI_BLOCK_CONFIG_IT(SAI_IT
));
973 /* Get the SAI_IT enable bit status */
974 enablestatus
= (SAI_Block_x
->IMR
& SAI_IT
) ;
976 /* Check the status of the specified SAI interrupt */
977 if (((SAI_Block_x
->SR
& SAI_IT
) != (uint32_t)RESET
) && (enablestatus
!= (uint32_t)RESET
))
984 /* SAI_IT is reset */
987 /* Return the SAI_IT status */
992 * @brief Clears the SAI Block x interrupt pending bit.
993 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
994 * @param SAI_IT: specifies the SAI Block interrupt pending bit to clear.
995 * This parameter can be one of the following values:
996 * @arg SAI_IT_MUTEDET: MUTE detection interrupt.
997 * @arg SAI_IT_OVRUDR: overrun/underrun interrupt.
998 * @arg SAI_IT_WCKCFG: wrong clock configuration interrupt.
999 * @arg SAI_IT_CNRDY: codec not ready interrupt.
1000 * @arg SAI_IT_AFSDET: anticipated frame synchronization detection interrupt.
1001 * @arg SAI_IT_LFSDET: late frame synchronization detection interrupt.
1003 * @note FREQ (FIFO Request) flag is cleared :
1004 * - When the audio block is transmitter and the FIFO is full or the FIFO
1005 * has one data (one buffer mode) depending the bit FTH in the
1006 * SAI_xCR2 register.
1007 * - When the audio block is receiver and the FIFO is not empty
1011 void SAI_ClearITPendingBit(SAI_Block_TypeDef
* SAI_Block_x
, uint32_t SAI_IT
)
1013 /* Check the parameters */
1014 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
1015 assert_param(IS_SAI_BLOCK_CONFIG_IT(SAI_IT
));
1017 /* Clear the selected SAI Block x interrupt pending bit */
1018 SAI_Block_x
->CLRFR
|= SAI_IT
;
1022 * @brief Returns the status of EN bit for the specified SAI Block x.
1023 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
1025 * @note After disabling a SAI Block, it is recommended to check (or wait until)
1026 * the SAI Block is effectively disabled. If a Block is disabled while
1027 * an audio frame transfer is ongoing, the current frame will be
1028 * transferred and the block will be effectively disabled only at
1029 * the end of audio frame.
1031 * @retval Current state of the DMAy Streamx (ENABLE or DISABLE).
1033 FunctionalState
SAI_GetCmdStatus(SAI_Block_TypeDef
* SAI_Block_x
)
1035 FunctionalState state
= DISABLE
;
1037 /* Check the parameters */
1038 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
1039 if ((SAI_Block_x
->CR1
& (uint32_t)SAI_xCR1_SAIEN
) != 0)
1041 /* The selected SAI Block x EN bit is set (audio frame transfer is ongoing) */
1046 /* The selected SAI Block x EN bit is cleared (SAI Block is disabled and
1047 all transfers are complete) */
1054 * @brief Returns the current SAI Block x FIFO filled level.
1055 * @param SAI_Block_x: where x can be A or B to select the SAI Block peripheral.
1057 * @retval The FIFO filling state.
1058 * - SAI_FIFOStatus_Empty: when FIFO is empty
1059 * - SAI_FIFOStatus_Less1QuarterFull: when FIFO is less than 1 quarter-full
1061 * - SAI_FIFOStatus_1QuarterFull: if more than 1 quarter-full.
1062 * - SAI_FIFOStatus_HalfFull: if more than 1 half-full.
1063 * - SAI_FIFOStatus_3QuartersFull: if more than 3 quarters-full.
1064 * - SAI_FIFOStatus_Full: when FIFO is full
1066 uint32_t SAI_GetFIFOStatus(SAI_Block_TypeDef
* SAI_Block_x
)
1068 uint32_t tmpreg
= 0;
1070 /* Check the parameters */
1071 assert_param(IS_SAI_BLOCK_PERIPH(SAI_Block_x
));
1073 /* Get the FIFO level bits */
1074 tmpreg
= (uint32_t)((SAI_Block_x
->SR
& SAI_xSR_FLVL
));
1087 #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx || STM32F411xE || STM32F446xx || STM32F469_479xx */
1097 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/