Mercurial > public > ostc4
comparison Common/Drivers/STM32F4xx_HAL_DRIVER_v120/Src/stm32f4xx_hal_sai.c @ 38:5f11787b4f42
include in ostc4 repository
author | heinrichsweikamp |
---|---|
date | Sat, 28 Apr 2018 11:52:34 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
37:ccc45c0e1ea2 | 38:5f11787b4f42 |
---|---|
1 /** | |
2 ****************************************************************************** | |
3 * @file stm32f4xx_hal_sai.c | |
4 * @author MCD Application Team | |
5 * @version V1.2.0 | |
6 * @date 26-December-2014 | |
7 * @brief SAI HAL module driver. | |
8 * This file provides firmware functions to manage the following | |
9 * functionalities of the Serial Audio Interface (SAI) peripheral: | |
10 * + Initialization/de-initialization functions | |
11 * + I/O operation functions | |
12 * + Peripheral Control functions | |
13 * + Peripheral State functions | |
14 * | |
15 @verbatim | |
16 ============================================================================== | |
17 ##### How to use this driver ##### | |
18 ============================================================================== | |
19 | |
20 [..] | |
21 The SAI HAL driver can be used as follows: | |
22 | |
23 (#) Declare a SAI_HandleTypeDef handle structure. | |
24 (#) Initialize the SAI low level resources by implementing the HAL_SAI_MspInit() API: | |
25 (##) Enable the SAI interface clock. | |
26 (##) SAI pins configuration: | |
27 (+++) Enable the clock for the SAI GPIOs. | |
28 (+++) Configure these SAI pins as alternate function pull-up. | |
29 (##) NVIC configuration if you need to use interrupt process (HAL_SAI_Transmit_IT() | |
30 and HAL_SAI_Receive_IT() APIs): | |
31 (+++) Configure the SAI interrupt priority. | |
32 (+++) Enable the NVIC SAI IRQ handle. | |
33 | |
34 (##) DMA Configuration if you need to use DMA process (HAL_SAI_Transmit_DMA() | |
35 and HAL_SAI_Receive_DMA() APIs): | |
36 (+++) Declare a DMA handle structure for the Tx/Rx stream. | |
37 (+++) Enable the DMAx interface clock. | |
38 (+++) Configure the declared DMA handle structure with the required Tx/Rx parameters. | |
39 (+++) Configure the DMA Tx/Rx Stream. | |
40 (+++) Associate the initialized DMA handle to the SAI DMA Tx/Rx handle. | |
41 (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the | |
42 DMA Tx/Rx Stream. | |
43 | |
44 (#) Program the SAI Mode, Standard, Data Format, MCLK Output, Audio frequency and Polarity | |
45 using HAL_SAI_Init() function. | |
46 | |
47 -@- The specific SAI interrupts (FIFO request and Overrun underrun interrupt) | |
48 will be managed using the macros __SAI_ENABLE_IT() and __SAI_DISABLE_IT() | |
49 inside the transmit and receive process. | |
50 | |
51 [..] | |
52 (@) Make sure that either: | |
53 (+@) I2S PLL is configured or | |
54 (+@) SAI PLL is configured or | |
55 (+@) External clock source is configured after setting correctly | |
56 the define constant EXTERNAL_CLOCK_VALUE in the stm32f4xx_hal_conf.h file. | |
57 | |
58 [..] | |
59 (@) In master Tx mode: enabling the audio block immediately generates the bit clock | |
60 for the external slaves even if there is no data in the FIFO, However FS signal | |
61 generation is conditioned by the presence of data in the FIFO. | |
62 | |
63 [..] | |
64 (@) In master Rx mode: enabling the audio block immediately generates the bit clock | |
65 and FS signal for the external slaves. | |
66 | |
67 [..] | |
68 (@) It is mandatory to respect the following conditions in order to avoid bad SAI behavior: | |
69 (+@) First bit Offset <= (SLOT size - Data size) | |
70 (+@) Data size <= SLOT size | |
71 (+@) Number of SLOT x SLOT size = Frame length | |
72 (+@) The number of slots should be even when SAI_FS_CHANNEL_IDENTIFICATION is selected. | |
73 | |
74 [..] | |
75 Three operation modes are available within this driver : | |
76 | |
77 *** Polling mode IO operation *** | |
78 ================================= | |
79 [..] | |
80 (+) Send an amount of data in blocking mode using HAL_SAI_Transmit() | |
81 (+) Receive an amount of data in blocking mode using HAL_SAI_Receive() | |
82 | |
83 *** Interrupt mode IO operation *** | |
84 =================================== | |
85 [..] | |
86 (+) Send an amount of data in non blocking mode using HAL_SAI_Transmit_IT() | |
87 (+) At transmission end of transfer HAL_SAI_TxCpltCallback is executed and user can | |
88 add his own code by customization of function pointer HAL_SAI_TxCpltCallback | |
89 (+) Receive an amount of data in non blocking mode using HAL_SAI_Receive_IT() | |
90 (+) At reception end of transfer HAL_SAI_RxCpltCallback is executed and user can | |
91 add his own code by customization of function pointer HAL_SAI_RxCpltCallback | |
92 (+) In case of transfer Error, HAL_SAI_ErrorCallback() function is executed and user can | |
93 add his own code by customization of function pointer HAL_SAI_ErrorCallback | |
94 | |
95 *** DMA mode IO operation *** | |
96 ============================== | |
97 [..] | |
98 (+) Send an amount of data in non blocking mode (DMA) using HAL_SAI_Transmit_DMA() | |
99 (+) At transmission end of transfer HAL_SAI_TxCpltCallback is executed and user can | |
100 add his own code by customization of function pointer HAL_SAI_TxCpltCallback | |
101 (+) Receive an amount of data in non blocking mode (DMA) using HAL_SAI_Receive_DMA() | |
102 (+) At reception end of transfer HAL_SAI_RxCpltCallback is executed and user can | |
103 add his own code by customization of function pointer HAL_SAI_RxCpltCallback | |
104 (+) In case of transfer Error, HAL_SAI_ErrorCallback() function is executed and user can | |
105 add his own code by customization of function pointer HAL_SAI_ErrorCallback | |
106 (+) Pause the DMA Transfer using HAL_SAI_DMAPause() | |
107 (+) Resume the DMA Transfer using HAL_SAI_DMAResume() | |
108 (+) Stop the DMA Transfer using HAL_SAI_DMAStop() | |
109 | |
110 *** SAI HAL driver macros list *** | |
111 ============================================= | |
112 [..] | |
113 Below the list of most used macros in USART HAL driver : | |
114 | |
115 (+) __HAL_SAI_ENABLE: Enable the SAI peripheral | |
116 (+) __HAL_SAI_DISABLE: Disable the SAI peripheral | |
117 (+) __HAL_SAI_ENABLE_IT : Enable the specified SAI interrupts | |
118 (+) __HAL_SAI_DISABLE_IT : Disable the specified SAI interrupts | |
119 (+) __HAL_SAI_GET_IT_SOURCE: Check if the specified SAI interrupt source is | |
120 enabled or disabled | |
121 (+) __HAL_SAI_GET_FLAG: Check whether the specified SAI flag is set or not | |
122 | |
123 @endverbatim | |
124 ****************************************************************************** | |
125 * @attention | |
126 * | |
127 * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> | |
128 * | |
129 * Redistribution and use in source and binary forms, with or without modification, | |
130 * are permitted provided that the following conditions are met: | |
131 * 1. Redistributions of source code must retain the above copyright notice, | |
132 * this list of conditions and the following disclaimer. | |
133 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
134 * this list of conditions and the following disclaimer in the documentation | |
135 * and/or other materials provided with the distribution. | |
136 * 3. Neither the name of STMicroelectronics nor the names of its contributors | |
137 * may be used to endorse or promote products derived from this software | |
138 * without specific prior written permission. | |
139 * | |
140 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
141 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
142 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
143 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
144 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
145 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
146 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
147 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
148 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
149 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
150 * | |
151 ****************************************************************************** | |
152 */ | |
153 | |
154 /* Includes ------------------------------------------------------------------*/ | |
155 #include "stm32f4xx_hal.h" | |
156 | |
157 /** @addtogroup STM32F4xx_HAL_Driver | |
158 * @{ | |
159 */ | |
160 | |
161 /** @defgroup SAI SAI | |
162 * @brief SAI HAL module driver | |
163 * @{ | |
164 */ | |
165 | |
166 #ifdef HAL_SAI_MODULE_ENABLED | |
167 | |
168 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) | |
169 | |
170 /* Private typedef -----------------------------------------------------------*/ | |
171 /* Private define ------------------------------------------------------------*/ | |
172 /* SAI registers Masks */ | |
173 #define CR1_CLEAR_MASK ((uint32_t)0xFF07C010) | |
174 #define FRCR_CLEAR_MASK ((uint32_t)0xFFF88000) | |
175 #define SLOTR_CLEAR_MASK ((uint32_t)0x0000F020) | |
176 | |
177 #define SAI_TIMEOUT_VALUE 10 | |
178 /* Private macro -------------------------------------------------------------*/ | |
179 /* Private variables ---------------------------------------------------------*/ | |
180 /* Private function prototypes -----------------------------------------------*/ | |
181 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma); | |
182 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma); | |
183 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma); | |
184 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma); | |
185 static void SAI_DMAError(DMA_HandleTypeDef *hdma); | |
186 | |
187 /* Private functions ---------------------------------------------------------*/ | |
188 | |
189 /** @defgroup SAI_Private_Functions SAI Private Functions | |
190 * @{ | |
191 */ | |
192 | |
193 /** @defgroup SAI_Exported_Functions_Group1 Initialization and de-initialization functions | |
194 * @brief Initialization and Configuration functions | |
195 * | |
196 @verbatim | |
197 =============================================================================== | |
198 ##### Initialization and de-initialization functions ##### | |
199 =============================================================================== | |
200 [..] This subsection provides a set of functions allowing to initialize and | |
201 de-initialize the SAIx peripheral: | |
202 | |
203 (+) User must implement HAL_SAI_MspInit() function in which he configures | |
204 all related peripherals resources (CLOCK, GPIO, DMA, IT and NVIC ). | |
205 | |
206 (+) Call the function HAL_SAI_Init() to configure the selected device with | |
207 the selected configuration: | |
208 (++) Mode (Master/slave TX/RX) | |
209 (++) Protocol | |
210 (++) Data Size | |
211 (++) MCLK Output | |
212 (++) Audio frequency | |
213 (++) FIFO Threshold | |
214 (++) Frame Config | |
215 (++) Slot Config | |
216 | |
217 (+) Call the function HAL_SAI_DeInit() to restore the default configuration | |
218 of the selected SAI peripheral. | |
219 | |
220 @endverbatim | |
221 * @{ | |
222 */ | |
223 | |
224 /** | |
225 * @brief Initializes the SAI according to the specified parameters | |
226 * in the SAI_InitTypeDef and create the associated handle. | |
227 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
228 * the configuration information for SAI module. | |
229 * @retval HAL status | |
230 */ | |
231 HAL_StatusTypeDef HAL_SAI_Init(SAI_HandleTypeDef *hsai) | |
232 { | |
233 uint32_t tmpreg = 0; | |
234 uint32_t tmpclock = 0, tmp2clock = 0; | |
235 /* This variable used to store the VCO Input (value in Hz) */ | |
236 uint32_t vcoinput = 0; | |
237 /* This variable used to store the SAI_CK_x (value in Hz) */ | |
238 uint32_t saiclocksource = 0; | |
239 | |
240 /* Check the SAI handle allocation */ | |
241 if(hsai == NULL) | |
242 { | |
243 return HAL_ERROR; | |
244 } | |
245 | |
246 /* Check the SAI Block parameters */ | |
247 assert_param(IS_SAI_BLOCK_PROTOCOL(hsai->Init.Protocol)); | |
248 assert_param(IS_SAI_BLOCK_MODE(hsai->Init.AudioMode)); | |
249 assert_param(IS_SAI_BLOCK_DATASIZE(hsai->Init.DataSize)); | |
250 assert_param(IS_SAI_BLOCK_FIRST_BIT(hsai->Init.FirstBit)); | |
251 assert_param(IS_SAI_BLOCK_CLOCK_STROBING(hsai->Init.ClockStrobing)); | |
252 assert_param(IS_SAI_BLOCK_SYNCHRO(hsai->Init.Synchro)); | |
253 assert_param(IS_SAI_BLOCK_OUTPUT_DRIVE(hsai->Init.OutputDrive)); | |
254 assert_param(IS_SAI_BLOCK_NODIVIDER(hsai->Init.NoDivider)); | |
255 assert_param(IS_SAI_BLOCK_FIFO_THRESHOLD(hsai->Init.FIFOThreshold)); | |
256 assert_param(IS_SAI_AUDIO_FREQUENCY(hsai->Init.AudioFrequency)); | |
257 | |
258 /* Check the SAI Block Frame parameters */ | |
259 assert_param(IS_SAI_BLOCK_FRAME_LENGTH(hsai->FrameInit.FrameLength)); | |
260 assert_param(IS_SAI_BLOCK_ACTIVE_FRAME(hsai->FrameInit.ActiveFrameLength)); | |
261 assert_param(IS_SAI_BLOCK_FS_DEFINITION(hsai->FrameInit.FSDefinition)); | |
262 assert_param(IS_SAI_BLOCK_FS_POLARITY(hsai->FrameInit.FSPolarity)); | |
263 assert_param(IS_SAI_BLOCK_FS_OFFSET(hsai->FrameInit.FSOffset)); | |
264 | |
265 /* Check the SAI Block Slot parameters */ | |
266 assert_param(IS_SAI_BLOCK_FIRSTBIT_OFFSET(hsai->SlotInit.FirstBitOffset)); | |
267 assert_param(IS_SAI_BLOCK_SLOT_SIZE(hsai->SlotInit.SlotSize)); | |
268 assert_param(IS_SAI_BLOCK_SLOT_NUMBER(hsai->SlotInit.SlotNumber)); | |
269 assert_param(IS_SAI_SLOT_ACTIVE(hsai->SlotInit.SlotActive)); | |
270 | |
271 if(hsai->State == HAL_SAI_STATE_RESET) | |
272 { | |
273 /* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */ | |
274 HAL_SAI_MspInit(hsai); | |
275 } | |
276 | |
277 hsai->State = HAL_SAI_STATE_BUSY; | |
278 | |
279 /* Disable the selected SAI peripheral */ | |
280 __HAL_SAI_DISABLE(hsai); | |
281 | |
282 /* SAI Block Configuration ------------------------------------------------------------*/ | |
283 /* SAI Block_x CR1 Configuration */ | |
284 /* Get the SAI Block_x CR1 value */ | |
285 tmpreg = hsai->Instance->CR1; | |
286 /* Clear MODE, PRTCFG, DS, LSBFIRST, CKSTR, SYNCEN, OUTDRIV, NODIV, and MCKDIV bits */ | |
287 tmpreg &= CR1_CLEAR_MASK; | |
288 /* Configure SAI_Block_x: Audio Protocol, Data Size, first transmitted bit, Clock strobing | |
289 edge, Synchronization mode, Output drive, Master Divider and FIFO level */ | |
290 /* Set PRTCFG bits according to Protocol value */ | |
291 /* Set DS bits according to DataSize value */ | |
292 /* Set LSBFIRST bit according to FirstBit value */ | |
293 /* Set CKSTR bit according to ClockStrobing value */ | |
294 /* Set SYNCEN bit according to Synchro value */ | |
295 /* Set OUTDRIV bit according to OutputDrive value */ | |
296 /* Set NODIV bit according to NoDivider value */ | |
297 tmpreg |= (uint32_t)(hsai->Init.Protocol | | |
298 hsai->Init.AudioMode | | |
299 hsai->Init.DataSize | | |
300 hsai->Init.FirstBit | | |
301 hsai->Init.ClockStrobing | | |
302 hsai->Init.Synchro | | |
303 hsai->Init.OutputDrive | | |
304 hsai->Init.NoDivider); | |
305 /* Write to SAI_Block_x CR1 */ | |
306 hsai->Instance->CR1 = tmpreg; | |
307 | |
308 /* SAI Block_x CR2 Configuration */ | |
309 /* Get the SAIBlock_x CR2 value */ | |
310 tmpreg = hsai->Instance->CR2; | |
311 /* Clear FTH bits */ | |
312 tmpreg &= ~(SAI_xCR2_FTH); | |
313 /* Configure the FIFO Level */ | |
314 /* Set FTH bits according to SAI_FIFOThreshold value */ | |
315 tmpreg |= (uint32_t)(hsai->Init.FIFOThreshold); | |
316 /* Write to SAI_Block_x CR2 */ | |
317 hsai->Instance->CR2 = tmpreg; | |
318 | |
319 /* SAI Block_x Frame Configuration -----------------------------------------*/ | |
320 /* Get the SAI Block_x FRCR value */ | |
321 tmpreg = hsai->Instance->FRCR; | |
322 /* Clear FRL, FSALL, FSDEF, FSPOL, FSOFF bits */ | |
323 tmpreg &= FRCR_CLEAR_MASK; | |
324 /* Configure SAI_Block_x Frame: Frame Length, Active Frame Length, Frame Synchronization | |
325 Definition, Frame Synchronization Polarity and Frame Synchronization Polarity */ | |
326 /* Set FRL bits according to SAI_FrameLength value */ | |
327 /* Set FSALL bits according to SAI_ActiveFrameLength value */ | |
328 /* Set FSDEF bit according to SAI_FSDefinition value */ | |
329 /* Set FSPOL bit according to SAI_FSPolarity value */ | |
330 /* Set FSOFF bit according to SAI_FSOffset value */ | |
331 tmpreg |= (uint32_t)((uint32_t)(hsai->FrameInit.FrameLength - 1) | | |
332 hsai->FrameInit.FSOffset | | |
333 hsai->FrameInit.FSDefinition | | |
334 hsai->FrameInit.FSPolarity | | |
335 (uint32_t)((hsai->FrameInit.ActiveFrameLength - 1) << 8)); | |
336 | |
337 /* Write to SAI_Block_x FRCR */ | |
338 hsai->Instance->FRCR = tmpreg; | |
339 | |
340 /* SAI Block_x SLOT Configuration ------------------------------------------*/ | |
341 /* Get the SAI Block_x SLOTR value */ | |
342 tmpreg = hsai->Instance->SLOTR; | |
343 /* Clear FBOFF, SLOTSZ, NBSLOT, SLOTEN bits */ | |
344 tmpreg &= SLOTR_CLEAR_MASK; | |
345 /* Configure SAI_Block_x Slot: First bit offset, Slot size, Number of Slot in | |
346 audio frame and slots activated in audio frame */ | |
347 /* Set FBOFF bits according to SAI_FirstBitOffset value */ | |
348 /* Set SLOTSZ bits according to SAI_SlotSize value */ | |
349 /* Set NBSLOT bits according to SAI_SlotNumber value */ | |
350 /* Set SLOTEN bits according to SAI_SlotActive value */ | |
351 tmpreg |= (uint32_t)(hsai->SlotInit.FirstBitOffset | | |
352 hsai->SlotInit.SlotSize | | |
353 hsai->SlotInit.SlotActive | | |
354 (uint32_t)((hsai->SlotInit.SlotNumber - 1) << 8)); | |
355 | |
356 /* Write to SAI_Block_x SLOTR */ | |
357 hsai->Instance->SLOTR = tmpreg; | |
358 | |
359 /* SAI Block_x Clock Configuration -----------------------------------------*/ | |
360 /* Check the Clock parameters */ | |
361 assert_param(IS_SAI_CLK_SOURCE(hsai->Init.ClockSource)); | |
362 | |
363 /* SAI Block clock source selection */ | |
364 if(hsai->Instance == SAI1_Block_A) | |
365 { | |
366 __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(hsai->Init.ClockSource); | |
367 } | |
368 else | |
369 { | |
370 __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG((uint32_t)(hsai->Init.ClockSource << 2)); | |
371 } | |
372 | |
373 /* VCO Input Clock value calculation */ | |
374 if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI) | |
375 { | |
376 /* In Case the PLL Source is HSI (Internal Clock) */ | |
377 vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)); | |
378 } | |
379 else | |
380 { | |
381 /* In Case the PLL Source is HSE (External Clock) */ | |
382 vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM))); | |
383 } | |
384 | |
385 /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */ | |
386 if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLSAI) | |
387 { | |
388 /* Configure the PLLI2S division factor */ | |
389 /* PLLSAI_VCO Input = PLL_SOURCE/PLLM */ | |
390 /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */ | |
391 /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */ | |
392 tmpreg = (RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24; | |
393 saiclocksource = (vcoinput * ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> 6))/(tmpreg); | |
394 | |
395 /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */ | |
396 tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8) + 1); | |
397 saiclocksource = saiclocksource/(tmpreg); | |
398 | |
399 } | |
400 else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S) | |
401 { | |
402 /* Configure the PLLI2S division factor */ | |
403 /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */ | |
404 /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */ | |
405 /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */ | |
406 tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> 24; | |
407 saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6))/(tmpreg); | |
408 | |
409 /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */ | |
410 tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1); | |
411 saiclocksource = saiclocksource/(tmpreg); | |
412 } | |
413 else /* sConfig->ClockSource == SAI_CLKSource_Ext */ | |
414 { | |
415 /* Enable the External Clock selection */ | |
416 __HAL_RCC_I2S_CONFIG(RCC_I2SCLKSOURCE_EXT); | |
417 | |
418 saiclocksource = EXTERNAL_CLOCK_VALUE; | |
419 } | |
420 | |
421 /* Configure Master Clock using the following formula : | |
422 MCLK_x = SAI_CK_x / (MCKDIV[3:0] * 2) with MCLK_x = 256 * FS | |
423 FS = SAI_CK_x / (MCKDIV[3:0] * 2) * 256 | |
424 MCKDIV[3:0] = SAI_CK_x / FS * 512 */ | |
425 if(hsai->Init.NoDivider == SAI_MASTERDIVIDER_ENABLE) | |
426 { | |
427 /* (saiclocksource x 10) to keep Significant digits */ | |
428 tmpclock = (((saiclocksource * 10) / ((hsai->Init.AudioFrequency) * 512))); | |
429 | |
430 /* Get the result of modulo division */ | |
431 tmp2clock = (tmpclock % 10); | |
432 | |
433 /* Round result to the nearest integer*/ | |
434 if (tmp2clock > 8) | |
435 { | |
436 tmpclock = ((tmpclock / 10) + 1); | |
437 } | |
438 else | |
439 { | |
440 tmpclock = (tmpclock / 10); | |
441 } | |
442 /*Set MCKDIV value in CR1 register*/ | |
443 hsai->Instance->CR1 |= (tmpclock << 20); | |
444 | |
445 } | |
446 | |
447 /* Initialize the error code */ | |
448 hsai->ErrorCode = HAL_SAI_ERROR_NONE; | |
449 | |
450 /* Initialize the SAI state */ | |
451 hsai->State= HAL_SAI_STATE_READY; | |
452 | |
453 return HAL_OK; | |
454 } | |
455 | |
456 /** | |
457 * @brief DeInitializes the SAI peripheral. | |
458 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
459 * the configuration information for SAI module. | |
460 * @retval HAL status | |
461 */ | |
462 HAL_StatusTypeDef HAL_SAI_DeInit(SAI_HandleTypeDef *hsai) | |
463 { | |
464 /* Check the SAI handle allocation */ | |
465 if(hsai == NULL) | |
466 { | |
467 return HAL_ERROR; | |
468 } | |
469 | |
470 hsai->State = HAL_SAI_STATE_BUSY; | |
471 | |
472 /* DeInit the low level hardware: GPIO, CLOCK, NVIC and DMA */ | |
473 HAL_SAI_MspDeInit(hsai); | |
474 | |
475 /* Initialize the error code */ | |
476 hsai->ErrorCode = HAL_SAI_ERROR_NONE; | |
477 | |
478 /* Initialize the SAI state */ | |
479 hsai->State = HAL_SAI_STATE_RESET; | |
480 | |
481 /* Release Lock */ | |
482 __HAL_UNLOCK(hsai); | |
483 | |
484 return HAL_OK; | |
485 } | |
486 | |
487 /** | |
488 * @brief SAI MSP Init. | |
489 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
490 * the configuration information for SAI module. | |
491 * @retval None | |
492 */ | |
493 __weak void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai) | |
494 { | |
495 /* NOTE : This function Should not be modified, when the callback is needed, | |
496 the HAL_SAI_MspInit could be implemented in the user file | |
497 */ | |
498 } | |
499 | |
500 /** | |
501 * @brief SAI MSP DeInit. | |
502 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
503 * the configuration information for SAI module. | |
504 * @retval None | |
505 */ | |
506 __weak void HAL_SAI_MspDeInit(SAI_HandleTypeDef *hsai) | |
507 { | |
508 /* NOTE : This function Should not be modified, when the callback is needed, | |
509 the HAL_SAI_MspDeInit could be implemented in the user file | |
510 */ | |
511 } | |
512 | |
513 /** | |
514 * @} | |
515 */ | |
516 | |
517 /** @defgroup SAI_Exported_Functions_Group2 IO operation functions | |
518 * @brief Data transfers functions | |
519 * | |
520 @verbatim | |
521 =============================================================================== | |
522 ##### IO operation functions ##### | |
523 =============================================================================== | |
524 [..] | |
525 This subsection provides a set of functions allowing to manage the SAI data | |
526 transfers. | |
527 | |
528 (+) There are two modes of transfer: | |
529 (++) Blocking mode : The communication is performed in the polling mode. | |
530 The status of all data processing is returned by the same function | |
531 after finishing transfer. | |
532 (++) No-Blocking mode : The communication is performed using Interrupts | |
533 or DMA. These functions return the status of the transfer startup. | |
534 The end of the data processing will be indicated through the | |
535 dedicated SAI IRQ when using Interrupt mode or the DMA IRQ when | |
536 using DMA mode. | |
537 | |
538 (+) Blocking mode functions are : | |
539 (++) HAL_SAI_Transmit() | |
540 (++) HAL_SAI_Receive() | |
541 (++) HAL_SAI_TransmitReceive() | |
542 | |
543 (+) Non Blocking mode functions with Interrupt are : | |
544 (++) HAL_SAI_Transmit_IT() | |
545 (++) HAL_SAI_Receive_IT() | |
546 (++) HAL_SAI_TransmitReceive_IT() | |
547 | |
548 (+) Non Blocking mode functions with DMA are : | |
549 (++) HAL_SAI_Transmit_DMA() | |
550 (++) HAL_SAI_Receive_DMA() | |
551 (++) HAL_SAI_TransmitReceive_DMA() | |
552 | |
553 (+) A set of Transfer Complete Callbacks are provided in non Blocking mode: | |
554 (++) HAL_SAI_TxCpltCallback() | |
555 (++) HAL_SAI_RxCpltCallback() | |
556 (++) HAL_SAI_ErrorCallback() | |
557 | |
558 @endverbatim | |
559 * @{ | |
560 */ | |
561 | |
562 /** | |
563 * @brief Transmits an amount of data in blocking mode. | |
564 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
565 * the configuration information for SAI module. | |
566 * @param pData: Pointer to data buffer | |
567 * @param Size: Amount of data to be sent | |
568 * @param Timeout: Timeout duration | |
569 * @retval HAL status | |
570 */ | |
571 HAL_StatusTypeDef HAL_SAI_Transmit(SAI_HandleTypeDef *hsai, uint16_t* pData, uint16_t Size, uint32_t Timeout) | |
572 { | |
573 uint32_t tickstart = 0; | |
574 | |
575 if((pData == NULL ) || (Size == 0)) | |
576 { | |
577 return HAL_ERROR; | |
578 } | |
579 | |
580 if(hsai->State == HAL_SAI_STATE_READY) | |
581 { | |
582 /* Process Locked */ | |
583 __HAL_LOCK(hsai); | |
584 | |
585 hsai->State = HAL_SAI_STATE_BUSY_TX; | |
586 | |
587 /* Check if the SAI is already enabled */ | |
588 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN) | |
589 { | |
590 /* Enable SAI peripheral */ | |
591 __HAL_SAI_ENABLE(hsai); | |
592 } | |
593 | |
594 while(Size > 0) | |
595 { | |
596 /* Get tick */ | |
597 tickstart = HAL_GetTick(); | |
598 | |
599 /* Wait the FIFO to be empty */ | |
600 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ) == RESET) | |
601 { | |
602 /* Check for the Timeout */ | |
603 if(Timeout != HAL_MAX_DELAY) | |
604 { | |
605 if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout)) | |
606 { | |
607 /* Update error code */ | |
608 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT; | |
609 | |
610 /* Process Unlocked */ | |
611 __HAL_UNLOCK(hsai); | |
612 | |
613 /* Change the SAI state */ | |
614 hsai->State = HAL_SAI_STATE_TIMEOUT; | |
615 | |
616 return HAL_TIMEOUT; | |
617 } | |
618 } | |
619 } | |
620 hsai->Instance->DR = (*pData++); | |
621 Size--; | |
622 } | |
623 | |
624 hsai->State = HAL_SAI_STATE_READY; | |
625 | |
626 /* Process Unlocked */ | |
627 __HAL_UNLOCK(hsai); | |
628 | |
629 return HAL_OK; | |
630 } | |
631 else | |
632 { | |
633 return HAL_BUSY; | |
634 } | |
635 } | |
636 | |
637 /** | |
638 * @brief Receives an amount of data in blocking mode. | |
639 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
640 * the configuration information for SAI module. | |
641 * @param pData: Pointer to data buffer | |
642 * @param Size: Amount of data to be received | |
643 * @param Timeout: Timeout duration | |
644 * @retval HAL status | |
645 */ | |
646 HAL_StatusTypeDef HAL_SAI_Receive(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size, uint32_t Timeout) | |
647 { | |
648 uint32_t tickstart = 0; | |
649 | |
650 if((pData == NULL ) || (Size == 0)) | |
651 { | |
652 return HAL_ERROR; | |
653 } | |
654 | |
655 if(hsai->State == HAL_SAI_STATE_READY) | |
656 { | |
657 /* Process Locked */ | |
658 __HAL_LOCK(hsai); | |
659 | |
660 hsai->State = HAL_SAI_STATE_BUSY_RX; | |
661 | |
662 /* Check if the SAI is already enabled */ | |
663 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN) | |
664 { | |
665 /* Enable SAI peripheral */ | |
666 __HAL_SAI_ENABLE(hsai); | |
667 } | |
668 | |
669 /* Receive data */ | |
670 while(Size > 0) | |
671 { | |
672 /* Get tick */ | |
673 tickstart = HAL_GetTick(); | |
674 | |
675 /* Wait until RXNE flag is set */ | |
676 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ) == RESET) | |
677 { | |
678 /* Check for the Timeout */ | |
679 if(Timeout != HAL_MAX_DELAY) | |
680 { | |
681 if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout)) | |
682 { | |
683 /* Update error code */ | |
684 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT; | |
685 | |
686 /* Process Unlocked */ | |
687 __HAL_UNLOCK(hsai); | |
688 | |
689 /* Change the SAI state */ | |
690 hsai->State = HAL_SAI_STATE_TIMEOUT; | |
691 | |
692 return HAL_TIMEOUT; | |
693 } | |
694 } | |
695 } | |
696 | |
697 (*pData++) = hsai->Instance->DR; | |
698 Size--; | |
699 } | |
700 | |
701 hsai->State = HAL_SAI_STATE_READY; | |
702 | |
703 /* Process Unlocked */ | |
704 __HAL_UNLOCK(hsai); | |
705 | |
706 return HAL_OK; | |
707 } | |
708 else | |
709 { | |
710 return HAL_BUSY; | |
711 } | |
712 } | |
713 | |
714 /** | |
715 * @brief Transmits an amount of data in no-blocking mode with Interrupt. | |
716 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
717 * the configuration information for SAI module. | |
718 * @param pData: Pointer to data buffer | |
719 * @param Size: Amount of data to be sent | |
720 * @retval HAL status | |
721 */ | |
722 HAL_StatusTypeDef HAL_SAI_Transmit_IT(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size) | |
723 { | |
724 if(hsai->State == HAL_SAI_STATE_READY) | |
725 { | |
726 if((pData == NULL) || (Size == 0)) | |
727 { | |
728 return HAL_ERROR; | |
729 } | |
730 | |
731 hsai->pTxBuffPtr = pData; | |
732 hsai->TxXferSize = Size; | |
733 hsai->TxXferCount = Size; | |
734 | |
735 /* Process Locked */ | |
736 __HAL_LOCK(hsai); | |
737 | |
738 hsai->State = HAL_SAI_STATE_BUSY_TX; | |
739 | |
740 /* Transmit data */ | |
741 hsai->Instance->DR = (*hsai->pTxBuffPtr++); | |
742 hsai->TxXferCount--; | |
743 | |
744 /* Process Unlocked */ | |
745 __HAL_UNLOCK(hsai); | |
746 | |
747 /* Enable FRQ and OVRUDR interrupts */ | |
748 __HAL_SAI_ENABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR)); | |
749 | |
750 /* Check if the SAI is already enabled */ | |
751 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN) | |
752 { | |
753 /* Enable SAI peripheral */ | |
754 __HAL_SAI_ENABLE(hsai); | |
755 } | |
756 | |
757 | |
758 return HAL_OK; | |
759 } | |
760 else if(hsai->State == HAL_SAI_STATE_BUSY_TX) | |
761 { | |
762 /* Process Locked */ | |
763 __HAL_LOCK(hsai); | |
764 | |
765 /* Transmit data */ | |
766 hsai->Instance->DR = (*hsai->pTxBuffPtr++); | |
767 | |
768 hsai->TxXferCount--; | |
769 | |
770 if(hsai->TxXferCount == 0) | |
771 { | |
772 /* Disable FREQ and OVRUDR interrupts */ | |
773 __HAL_SAI_DISABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR)); | |
774 | |
775 hsai->State = HAL_SAI_STATE_READY; | |
776 | |
777 HAL_SAI_TxCpltCallback(hsai); | |
778 } | |
779 | |
780 /* Process Unlocked */ | |
781 __HAL_UNLOCK(hsai); | |
782 | |
783 return HAL_OK; | |
784 } | |
785 | |
786 else | |
787 { | |
788 return HAL_BUSY; | |
789 } | |
790 } | |
791 | |
792 /** | |
793 * @brief Receives an amount of data in no-blocking mode with Interrupt. | |
794 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
795 * the configuration information for SAI module. | |
796 * @param pData: Pointer to data buffer | |
797 * @param Size: Amount of data to be received | |
798 * @retval HAL status | |
799 */ | |
800 HAL_StatusTypeDef HAL_SAI_Receive_IT(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size) | |
801 { | |
802 if(hsai->State == HAL_SAI_STATE_READY) | |
803 { | |
804 if((pData == NULL) || (Size == 0)) | |
805 { | |
806 return HAL_ERROR; | |
807 } | |
808 | |
809 hsai->pRxBuffPtr = pData; | |
810 hsai->RxXferSize = Size; | |
811 hsai->RxXferCount = Size; | |
812 | |
813 /* Process Locked */ | |
814 __HAL_LOCK(hsai); | |
815 | |
816 hsai->State = HAL_SAI_STATE_BUSY_RX; | |
817 | |
818 /* Enable TXE and OVRUDR interrupts */ | |
819 __HAL_SAI_ENABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR)); | |
820 | |
821 /* Check if the SAI is already enabled */ | |
822 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN) | |
823 { | |
824 /* Enable SAI peripheral */ | |
825 __HAL_SAI_ENABLE(hsai); | |
826 } | |
827 | |
828 /* Process Unlocked */ | |
829 __HAL_UNLOCK(hsai); | |
830 | |
831 return HAL_OK; | |
832 } | |
833 else if(hsai->State == HAL_SAI_STATE_BUSY_RX) | |
834 { | |
835 /* Process Locked */ | |
836 __HAL_LOCK(hsai); | |
837 | |
838 /* Receive data */ | |
839 (*hsai->pRxBuffPtr++) = hsai->Instance->DR; | |
840 | |
841 hsai->RxXferCount--; | |
842 | |
843 if(hsai->RxXferCount == 0) | |
844 { | |
845 /* Disable TXE and OVRUDR interrupts */ | |
846 __HAL_SAI_DISABLE_IT(hsai, (SAI_IT_FREQ | SAI_IT_OVRUDR)); | |
847 | |
848 hsai->State = HAL_SAI_STATE_READY; | |
849 HAL_SAI_RxCpltCallback(hsai); | |
850 } | |
851 | |
852 /* Process Unlocked */ | |
853 __HAL_UNLOCK(hsai); | |
854 | |
855 return HAL_OK; | |
856 } | |
857 | |
858 else | |
859 { | |
860 return HAL_BUSY; | |
861 } | |
862 } | |
863 | |
864 /** | |
865 * @brief Pauses the audio stream playing from the Media. | |
866 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
867 * the configuration information for SAI module. | |
868 * @retval HAL status | |
869 */ | |
870 HAL_StatusTypeDef HAL_SAI_DMAPause(SAI_HandleTypeDef *hsai) | |
871 { | |
872 /* Process Locked */ | |
873 __HAL_LOCK(hsai); | |
874 | |
875 /* Pause the audio file playing by disabling the SAI DMA requests */ | |
876 hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN; | |
877 | |
878 | |
879 /* Process Unlocked */ | |
880 __HAL_UNLOCK(hsai); | |
881 | |
882 return HAL_OK; | |
883 } | |
884 | |
885 /** | |
886 * @brief Resumes the audio stream playing from the Media. | |
887 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
888 * the configuration information for SAI module. | |
889 * @retval HAL status | |
890 */ | |
891 HAL_StatusTypeDef HAL_SAI_DMAResume(SAI_HandleTypeDef *hsai) | |
892 { | |
893 /* Process Locked */ | |
894 __HAL_LOCK(hsai); | |
895 | |
896 /* Enable the SAI DMA requests */ | |
897 hsai->Instance->CR1 |= SAI_xCR1_DMAEN; | |
898 | |
899 | |
900 /* If the SAI peripheral is still not enabled, enable it */ | |
901 if ((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == 0) | |
902 { | |
903 /* Enable SAI peripheral */ | |
904 __HAL_SAI_ENABLE(hsai); | |
905 } | |
906 | |
907 /* Process Unlocked */ | |
908 __HAL_UNLOCK(hsai); | |
909 | |
910 return HAL_OK; | |
911 } | |
912 | |
913 /** | |
914 * @brief Stops the audio stream playing from the Media. | |
915 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
916 * the configuration information for SAI module. | |
917 * @retval HAL status | |
918 */ | |
919 HAL_StatusTypeDef HAL_SAI_DMAStop(SAI_HandleTypeDef *hsai) | |
920 { | |
921 /* Process Locked */ | |
922 __HAL_LOCK(hsai); | |
923 | |
924 /* Disable the SAI DMA request */ | |
925 hsai->Instance->CR1 &= ~SAI_xCR1_DMAEN; | |
926 | |
927 /* Abort the SAI DMA Tx Stream */ | |
928 if(hsai->hdmatx != NULL) | |
929 { | |
930 HAL_DMA_Abort(hsai->hdmatx); | |
931 } | |
932 /* Abort the SAI DMA Rx Stream */ | |
933 if(hsai->hdmarx != NULL) | |
934 { | |
935 HAL_DMA_Abort(hsai->hdmarx); | |
936 } | |
937 | |
938 /* Disable SAI peripheral */ | |
939 __HAL_SAI_DISABLE(hsai); | |
940 | |
941 hsai->State = HAL_SAI_STATE_READY; | |
942 | |
943 /* Process Unlocked */ | |
944 __HAL_UNLOCK(hsai); | |
945 | |
946 return HAL_OK; | |
947 } | |
948 /** | |
949 * @brief Transmits an amount of data in no-blocking mode with DMA. | |
950 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
951 * the configuration information for SAI module. | |
952 * @param pData: Pointer to data buffer | |
953 * @param Size: Amount of data to be sent | |
954 * @retval HAL status | |
955 */ | |
956 HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size) | |
957 { | |
958 uint32_t *tmp; | |
959 | |
960 if((pData == NULL) || (Size == 0)) | |
961 { | |
962 return HAL_ERROR; | |
963 } | |
964 | |
965 if(hsai->State == HAL_SAI_STATE_READY) | |
966 { | |
967 hsai->pTxBuffPtr = pData; | |
968 hsai->TxXferSize = Size; | |
969 hsai->TxXferCount = Size; | |
970 | |
971 /* Process Locked */ | |
972 __HAL_LOCK(hsai); | |
973 | |
974 hsai->State = HAL_SAI_STATE_BUSY_TX; | |
975 | |
976 /* Set the SAI Tx DMA Half transfer complete callback */ | |
977 hsai->hdmatx->XferHalfCpltCallback = SAI_DMATxHalfCplt; | |
978 | |
979 /* Set the SAI TxDMA transfer complete callback */ | |
980 hsai->hdmatx->XferCpltCallback = SAI_DMATxCplt; | |
981 | |
982 /* Set the DMA error callback */ | |
983 hsai->hdmatx->XferErrorCallback = SAI_DMAError; | |
984 | |
985 /* Enable the Tx DMA Stream */ | |
986 tmp = (uint32_t*)&pData; | |
987 HAL_DMA_Start_IT(hsai->hdmatx, *(uint32_t*)tmp, (uint32_t)&hsai->Instance->DR, hsai->TxXferSize); | |
988 | |
989 /* Check if the SAI is already enabled */ | |
990 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN) | |
991 { | |
992 /* Enable SAI peripheral */ | |
993 __HAL_SAI_ENABLE(hsai); | |
994 } | |
995 | |
996 /* Enable SAI Tx DMA Request */ | |
997 hsai->Instance->CR1 |= SAI_xCR1_DMAEN; | |
998 | |
999 /* Process Unlocked */ | |
1000 __HAL_UNLOCK(hsai); | |
1001 | |
1002 return HAL_OK; | |
1003 } | |
1004 else | |
1005 { | |
1006 return HAL_BUSY; | |
1007 } | |
1008 } | |
1009 | |
1010 /** | |
1011 * @brief Receives an amount of data in no-blocking mode with DMA. | |
1012 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1013 * the configuration information for SAI module. | |
1014 * @param pData: Pointer to data buffer | |
1015 * @param Size: Amount of data to be received | |
1016 * @retval HAL status | |
1017 */ | |
1018 HAL_StatusTypeDef HAL_SAI_Receive_DMA(SAI_HandleTypeDef *hsai, uint16_t *pData, uint16_t Size) | |
1019 { | |
1020 uint32_t *tmp; | |
1021 | |
1022 if((pData == NULL) || (Size == 0)) | |
1023 { | |
1024 return HAL_ERROR; | |
1025 } | |
1026 | |
1027 if(hsai->State == HAL_SAI_STATE_READY) | |
1028 { | |
1029 hsai->pRxBuffPtr = pData; | |
1030 hsai->RxXferSize = Size; | |
1031 hsai->RxXferCount = Size; | |
1032 | |
1033 /* Process Locked */ | |
1034 __HAL_LOCK(hsai); | |
1035 | |
1036 hsai->State = HAL_SAI_STATE_BUSY_RX; | |
1037 | |
1038 /* Set the SAI Rx DMA Half transfer complete callback */ | |
1039 hsai->hdmarx->XferHalfCpltCallback = SAI_DMARxHalfCplt; | |
1040 | |
1041 /* Set the SAI Rx DMA transfer complete callback */ | |
1042 hsai->hdmarx->XferCpltCallback = SAI_DMARxCplt; | |
1043 | |
1044 /* Set the DMA error callback */ | |
1045 hsai->hdmarx->XferErrorCallback = SAI_DMAError; | |
1046 | |
1047 /* Enable the Rx DMA Stream */ | |
1048 tmp = (uint32_t*)&pData; | |
1049 HAL_DMA_Start_IT(hsai->hdmarx, (uint32_t)&hsai->Instance->DR, *(uint32_t*)tmp, hsai->RxXferSize); | |
1050 | |
1051 /* Check if the SAI is already enabled */ | |
1052 if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) != SAI_xCR1_SAIEN) | |
1053 { | |
1054 /* Enable SAI peripheral */ | |
1055 __HAL_SAI_ENABLE(hsai); | |
1056 } | |
1057 | |
1058 /* Enable SAI Rx DMA Request */ | |
1059 hsai->Instance->CR1 |= SAI_xCR1_DMAEN; | |
1060 | |
1061 /* Process Unlocked */ | |
1062 __HAL_UNLOCK(hsai); | |
1063 | |
1064 return HAL_OK; | |
1065 } | |
1066 else | |
1067 { | |
1068 return HAL_BUSY; | |
1069 } | |
1070 } | |
1071 | |
1072 /** | |
1073 * @brief This function handles SAI interrupt request. | |
1074 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1075 * the configuration information for SAI module. | |
1076 * @retval HAL status | |
1077 */ | |
1078 void HAL_SAI_IRQHandler(SAI_HandleTypeDef *hsai) | |
1079 { | |
1080 uint32_t tmp1 = 0, tmp2 = 0; | |
1081 | |
1082 if(hsai->State == HAL_SAI_STATE_BUSY_RX) | |
1083 { | |
1084 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ); | |
1085 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_FREQ); | |
1086 /* SAI in mode Receiver --------------------------------------------------*/ | |
1087 if((tmp1 != RESET) && (tmp2 != RESET)) | |
1088 { | |
1089 HAL_SAI_Receive_IT(hsai, NULL, 0); | |
1090 } | |
1091 | |
1092 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_FLAG_OVRUDR); | |
1093 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_OVRUDR); | |
1094 /* SAI Overrun error interrupt occurred ----------------------------------*/ | |
1095 if((tmp1 != RESET) && (tmp2 != RESET)) | |
1096 { | |
1097 /* Change the SAI error code */ | |
1098 hsai->ErrorCode = HAL_SAI_ERROR_OVR; | |
1099 | |
1100 /* Clear the SAI Overrun flag */ | |
1101 __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR); | |
1102 /* Set the SAI state ready to be able to start again the process */ | |
1103 hsai->State = HAL_SAI_STATE_READY; | |
1104 HAL_SAI_ErrorCallback(hsai); | |
1105 } | |
1106 } | |
1107 | |
1108 if(hsai->State == HAL_SAI_STATE_BUSY_TX) | |
1109 { | |
1110 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_xSR_FREQ); | |
1111 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_FREQ); | |
1112 /* SAI in mode Transmitter -----------------------------------------------*/ | |
1113 if((tmp1 != RESET) && (tmp2 != RESET)) | |
1114 { | |
1115 HAL_SAI_Transmit_IT(hsai, NULL, 0); | |
1116 } | |
1117 | |
1118 tmp1 = __HAL_SAI_GET_FLAG(hsai, SAI_FLAG_OVRUDR); | |
1119 tmp2 = __HAL_SAI_GET_IT_SOURCE(hsai, SAI_IT_OVRUDR); | |
1120 /* SAI Underrun error interrupt occurred ---------------------------------*/ | |
1121 if((tmp1 != RESET) && (tmp2 != RESET)) | |
1122 { | |
1123 /* Change the SAI error code */ | |
1124 hsai->ErrorCode = HAL_SAI_ERROR_UDR; | |
1125 | |
1126 /* Clear the SAI Underrun flag */ | |
1127 __HAL_SAI_CLEAR_FLAG(hsai, SAI_FLAG_OVRUDR); | |
1128 /* Set the SAI state ready to be able to start again the process */ | |
1129 hsai->State = HAL_SAI_STATE_READY; | |
1130 HAL_SAI_ErrorCallback(hsai); | |
1131 } | |
1132 } | |
1133 } | |
1134 | |
1135 /** | |
1136 * @brief Tx Transfer completed callbacks. | |
1137 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1138 * the configuration information for SAI module. | |
1139 * @retval None | |
1140 */ | |
1141 __weak void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) | |
1142 { | |
1143 /* NOTE : This function Should not be modified, when the callback is needed, | |
1144 the HAL_SAI_TxCpltCallback could be implemented in the user file | |
1145 */ | |
1146 } | |
1147 | |
1148 /** | |
1149 * @brief Tx Transfer Half completed callbacks | |
1150 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1151 * the configuration information for SAI module. | |
1152 * @retval None | |
1153 */ | |
1154 __weak void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) | |
1155 { | |
1156 /* NOTE : This function Should not be modified, when the callback is needed, | |
1157 the HAL_SAI_TxHalfCpltCallback could be implemented in the user file | |
1158 */ | |
1159 } | |
1160 | |
1161 /** | |
1162 * @brief Rx Transfer completed callbacks. | |
1163 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1164 * the configuration information for SAI module. | |
1165 * @retval None | |
1166 */ | |
1167 __weak void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) | |
1168 { | |
1169 /* NOTE : This function Should not be modified, when the callback is needed, | |
1170 the HAL_SAI_RxCpltCallback could be implemented in the user file | |
1171 */ | |
1172 } | |
1173 | |
1174 /** | |
1175 * @brief Rx Transfer half completed callbacks | |
1176 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1177 * the configuration information for SAI module. | |
1178 * @retval None | |
1179 */ | |
1180 __weak void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) | |
1181 { | |
1182 /* NOTE : This function Should not be modified, when the callback is needed, | |
1183 the HAL_SAI_RxCpltCallback could be implemented in the user file | |
1184 */ | |
1185 } | |
1186 | |
1187 /** | |
1188 * @brief SAI error callbacks. | |
1189 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1190 * the configuration information for SAI module. | |
1191 * @retval None | |
1192 */ | |
1193 __weak void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) | |
1194 { | |
1195 /* NOTE : This function Should not be modified, when the callback is needed, | |
1196 the HAL_SAI_ErrorCallback could be implemented in the user file | |
1197 */ | |
1198 } | |
1199 | |
1200 /** | |
1201 * @} | |
1202 */ | |
1203 | |
1204 | |
1205 /** @defgroup SAI_Exported_Functions_Group3 Peripheral State functions | |
1206 * @brief Peripheral State functions | |
1207 * | |
1208 @verbatim | |
1209 =============================================================================== | |
1210 ##### Peripheral State and Errors functions ##### | |
1211 =============================================================================== | |
1212 [..] | |
1213 This subsection permits to get in run-time the status of the peripheral | |
1214 and the data flow. | |
1215 | |
1216 @endverbatim | |
1217 * @{ | |
1218 */ | |
1219 | |
1220 /** | |
1221 * @brief Returns the SAI state. | |
1222 * @param hsai: pointer to a SAI_HandleTypeDef structure that contains | |
1223 * the configuration information for SAI module. | |
1224 * @retval HAL state | |
1225 */ | |
1226 HAL_SAI_StateTypeDef HAL_SAI_GetState(SAI_HandleTypeDef *hsai) | |
1227 { | |
1228 return hsai->State; | |
1229 } | |
1230 | |
1231 /** | |
1232 * @brief Return the SAI error code | |
1233 * @param hsai : pointer to a SAI_HandleTypeDef structure that contains | |
1234 * the configuration information for the specified SAI Block. | |
1235 * @retval SAI Error Code | |
1236 */ | |
1237 uint32_t HAL_SAI_GetError(SAI_HandleTypeDef *hsai) | |
1238 { | |
1239 return hsai->ErrorCode; | |
1240 } | |
1241 /** | |
1242 * @} | |
1243 */ | |
1244 | |
1245 /** | |
1246 * @brief DMA SAI transmit process complete callback. | |
1247 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains | |
1248 * the configuration information for the specified DMA module. | |
1249 * @retval None | |
1250 */ | |
1251 static void SAI_DMATxCplt(DMA_HandleTypeDef *hdma) | |
1252 { | |
1253 uint32_t tickstart = 0; | |
1254 | |
1255 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef* )hdma)->Parent; | |
1256 | |
1257 if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0) | |
1258 { | |
1259 hsai->TxXferCount = 0; | |
1260 hsai->RxXferCount = 0; | |
1261 | |
1262 /* Disable SAI Tx DMA Request */ | |
1263 hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN); | |
1264 | |
1265 /* Get tick */ | |
1266 tickstart = HAL_GetTick(); | |
1267 | |
1268 /* Set timeout: 10 is the max delay to send the remaining data in the SAI FIFO */ | |
1269 /* Wait until FIFO is empty */ | |
1270 while(__HAL_SAI_GET_FLAG(hsai, SAI_xSR_FLVL) != RESET) | |
1271 { | |
1272 /* Check for the Timeout */ | |
1273 if((HAL_GetTick() - tickstart ) > SAI_TIMEOUT_VALUE) | |
1274 { | |
1275 /* Update error code */ | |
1276 hsai->ErrorCode |= HAL_SAI_ERROR_TIMEOUT; | |
1277 | |
1278 /* Change the SAI state */ | |
1279 HAL_SAI_ErrorCallback(hsai); | |
1280 } | |
1281 } | |
1282 | |
1283 hsai->State= HAL_SAI_STATE_READY; | |
1284 } | |
1285 HAL_SAI_TxCpltCallback(hsai); | |
1286 } | |
1287 | |
1288 /** | |
1289 * @brief DMA SAI transmit process half complete callback | |
1290 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains | |
1291 * the configuration information for the specified DMA module. | |
1292 * @retval None | |
1293 */ | |
1294 static void SAI_DMATxHalfCplt(DMA_HandleTypeDef *hdma) | |
1295 { | |
1296 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; | |
1297 | |
1298 HAL_SAI_TxHalfCpltCallback(hsai); | |
1299 } | |
1300 | |
1301 /** | |
1302 * @brief DMA SAI receive process complete callback. | |
1303 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains | |
1304 * the configuration information for the specified DMA module. | |
1305 * @retval None | |
1306 */ | |
1307 static void SAI_DMARxCplt(DMA_HandleTypeDef *hdma) | |
1308 { | |
1309 SAI_HandleTypeDef* hsai = ( SAI_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; | |
1310 if((hdma->Instance->CR & DMA_SxCR_CIRC) == 0) | |
1311 { | |
1312 /* Disable Rx DMA Request */ | |
1313 hsai->Instance->CR1 &= (uint32_t)(~SAI_xCR1_DMAEN); | |
1314 hsai->RxXferCount = 0; | |
1315 | |
1316 hsai->State = HAL_SAI_STATE_READY; | |
1317 } | |
1318 HAL_SAI_RxCpltCallback(hsai); | |
1319 } | |
1320 | |
1321 /** | |
1322 * @brief DMA SAI receive process half complete callback | |
1323 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains | |
1324 * the configuration information for the specified DMA module. | |
1325 * @retval None | |
1326 */ | |
1327 static void SAI_DMARxHalfCplt(DMA_HandleTypeDef *hdma) | |
1328 { | |
1329 SAI_HandleTypeDef* hsai = (SAI_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; | |
1330 | |
1331 HAL_SAI_RxHalfCpltCallback(hsai); | |
1332 } | |
1333 /** | |
1334 * @brief DMA SAI communication error callback. | |
1335 * @param hdma: pointer to a DMA_HandleTypeDef structure that contains | |
1336 * the configuration information for the specified DMA module. | |
1337 * @retval None | |
1338 */ | |
1339 static void SAI_DMAError(DMA_HandleTypeDef *hdma) | |
1340 { | |
1341 SAI_HandleTypeDef* hsai = ( SAI_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; | |
1342 /* Set the SAI state ready to be able to start again the process */ | |
1343 hsai->State= HAL_SAI_STATE_READY; | |
1344 HAL_SAI_ErrorCallback(hsai); | |
1345 | |
1346 hsai->TxXferCount = 0; | |
1347 hsai->RxXferCount = 0; | |
1348 } | |
1349 | |
1350 /** | |
1351 * @} | |
1352 */ | |
1353 | |
1354 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ | |
1355 #endif /* HAL_SAI_MODULE_ENABLED */ | |
1356 /** | |
1357 * @} | |
1358 */ | |
1359 | |
1360 /** | |
1361 * @} | |
1362 */ | |
1363 | |
1364 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |