1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2019 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_flexio_i2s.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.flexio_i2s"
14 #endif
15
16 /*******************************************************************************
17 * Definitations
18 ******************************************************************************/
19 /*!@brief _sai_transfer_state*/
20 enum
21 {
22 kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO_I2S is busy */
23 kFLEXIO_I2S_Idle, /*!< Transfer is done. */
24 };
25
26 /*******************************************************************************
27 * Prototypes
28 ******************************************************************************/
29
30 /*!
31 * @brief Receive a piece of data in non-blocking way.
32 *
33 * @param base FLEXIO I2S base pointer
34 * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
35 * @param buffer Pointer to the data to be read.
36 * @param size Bytes to be read.
37 */
38 static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size);
39
40 /*!
41 * @brief sends a piece of data in non-blocking way.
42 *
43 * @param base FLEXIO I2S base pointer
44 * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
45 * @param buffer Pointer to the data to be written.
46 * @param size Bytes to be written.
47 */
48 static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size);
49 /*******************************************************************************
50 * Variables
51 ******************************************************************************/
52
53 /*******************************************************************************
54 * Code
55 ******************************************************************************/
56
FLEXIO_I2S_GetInstance(FLEXIO_I2S_Type * base)57 static uint32_t FLEXIO_I2S_GetInstance(FLEXIO_I2S_Type *base)
58 {
59 return FLEXIO_GetInstance(base->flexioBase);
60 }
61
FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * txData,size_t size)62 static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
63 {
64 uint32_t i = 0;
65 uint8_t j = 0;
66 uint8_t bytesPerWord = bitWidth / 8U;
67 uint32_t data = 0;
68 uint32_t temp = 0;
69
70 for (i = 0; i < size / bytesPerWord; i++)
71 {
72 for (j = 0; j < bytesPerWord; j++)
73 {
74 temp = (uint32_t)(*txData);
75 data |= (temp << (8U * j));
76 txData++;
77 }
78 base->flexioBase->SHIFTBUFBIS[base->txShifterIndex] = data << (32U - bitWidth);
79 data = 0;
80 }
81 }
82
FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * rxData,size_t size)83 static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
84 {
85 uint32_t i = 0;
86 uint8_t j = 0;
87 uint8_t bytesPerWord = bitWidth / 8U;
88 uint32_t data = 0;
89
90 for (i = 0; i < size / bytesPerWord; i++)
91 {
92 data = (base->flexioBase->SHIFTBUFBIS[base->rxShifterIndex]);
93 for (j = 0; j < bytesPerWord; j++)
94 {
95 *rxData = (uint8_t)((data >> (8U * j)) & 0xFFU);
96 rxData++;
97 }
98 }
99 }
100
101 /*!
102 * brief Initializes the FlexIO I2S.
103 *
104 * This API configures FlexIO pins and shifter to I2S and configures the FlexIO I2S with a configuration structure.
105 * The configuration structure can be filled by the user, or be set with default values by
106 * FLEXIO_I2S_GetDefaultConfig().
107 *
108 * note This API should be called at the beginning of the application to use
109 * the FlexIO I2S driver. Otherwise, any access to the FlexIO I2S module can cause hard fault
110 * because the clock is not enabled.
111 *
112 * param base FlexIO I2S base pointer
113 * param config FlexIO I2S configure structure.
114 */
FLEXIO_I2S_Init(FLEXIO_I2S_Type * base,const flexio_i2s_config_t * config)115 void FLEXIO_I2S_Init(FLEXIO_I2S_Type *base, const flexio_i2s_config_t *config)
116 {
117 assert((base != NULL) && (config != NULL));
118
119 flexio_shifter_config_t shifterConfig = {0};
120 flexio_timer_config_t timerConfig = {0};
121
122 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
123 /* Ungate flexio clock. */
124 CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2S_GetInstance(base)]);
125 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
126
127 /* reset Flexio */
128 FLEXIO_Reset(base->flexioBase);
129
130 /* Set shifter for I2S Tx data */
131 shifterConfig.timerSelect = base->bclkTimerIndex;
132 shifterConfig.pinSelect = base->txPinIndex;
133 shifterConfig.timerPolarity = config->txTimerPolarity;
134 shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
135 shifterConfig.pinPolarity = config->txPinPolarity;
136 shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
137 shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
138 shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
139 if (config->masterSlave == kFLEXIO_I2S_Master)
140 {
141 shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
142 }
143 else
144 {
145 shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
146 }
147
148 FLEXIO_SetShifterConfig(base->flexioBase, base->txShifterIndex, &shifterConfig);
149
150 /* Set shifter for I2S Rx Data */
151 shifterConfig.timerSelect = base->bclkTimerIndex;
152 shifterConfig.pinSelect = base->rxPinIndex;
153 shifterConfig.timerPolarity = config->rxTimerPolarity;
154 shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
155 shifterConfig.pinPolarity = config->rxPinPolarity;
156 shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
157 shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
158 shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
159 shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
160
161 FLEXIO_SetShifterConfig(base->flexioBase, base->rxShifterIndex, &shifterConfig);
162
163 /* Set Timer to I2S frame sync */
164 if (config->masterSlave == kFLEXIO_I2S_Master)
165 {
166 timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->txPinIndex);
167 timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
168 timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceExternal;
169 timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
170 timerConfig.pinSelect = base->fsPinIndex;
171 timerConfig.pinPolarity = config->fsPinPolarity;
172 timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
173 timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
174 timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
175 timerConfig.timerReset = kFLEXIO_TimerResetNever;
176 timerConfig.timerDisable = kFLEXIO_TimerDisableNever;
177 timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
178 timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
179 timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
180 }
181 else
182 {
183 timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->bclkPinIndex);
184 timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
185 timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
186 timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
187 timerConfig.pinSelect = base->fsPinIndex;
188 timerConfig.pinPolarity = config->fsPinPolarity;
189 timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
190 timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
191 timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnTriggerInputShiftTriggerInput;
192 timerConfig.timerReset = kFLEXIO_TimerResetNever;
193 timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
194 timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdge;
195 timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
196 timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
197 }
198 FLEXIO_SetTimerConfig(base->flexioBase, base->fsTimerIndex, &timerConfig);
199
200 /* Set Timer to I2S bit clock */
201 if (config->masterSlave == kFLEXIO_I2S_Master)
202 {
203 timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterIndex);
204 timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
205 timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
206 timerConfig.pinSelect = base->bclkPinIndex;
207 timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
208 timerConfig.pinPolarity = config->bclkPinPolarity;
209 timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
210 timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
211 timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
212 timerConfig.timerReset = kFLEXIO_TimerResetNever;
213 timerConfig.timerDisable = kFLEXIO_TimerDisableNever;
214 timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
215 timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
216 timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
217 }
218 else
219 {
220 timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_TIMn(base->fsTimerIndex);
221 timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
222 timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
223 timerConfig.pinSelect = base->bclkPinIndex;
224 timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
225 timerConfig.pinPolarity = config->bclkPinPolarity;
226 timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
227 timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
228 timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
229 timerConfig.timerReset = kFLEXIO_TimerResetNever;
230 timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompareTriggerLow;
231 timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdgeTriggerHigh;
232 timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
233 timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
234 }
235 FLEXIO_SetTimerConfig(base->flexioBase, base->bclkTimerIndex, &timerConfig);
236
237 /* If enable flexio I2S */
238 if (config->enableI2S)
239 {
240 base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
241 }
242 else
243 {
244 base->flexioBase->CTRL &= ~FLEXIO_CTRL_FLEXEN_MASK;
245 }
246 }
247
248 /*!
249 * brief Sets the FlexIO I2S configuration structure to default values.
250 *
251 * The purpose of this API is to get the configuration structure initialized for use in FLEXIO_I2S_Init().
252 * Users may use the initialized structure unchanged in FLEXIO_I2S_Init() or modify
253 * some fields of the structure before calling FLEXIO_I2S_Init().
254 *
255 * param config pointer to master configuration structure
256 */
FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t * config)257 void FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t *config)
258 {
259 /* Initializes the configure structure to zero. */
260 (void)memset(config, 0, sizeof(*config));
261
262 config->masterSlave = kFLEXIO_I2S_Master;
263 config->enableI2S = true;
264 config->txPinPolarity = kFLEXIO_PinActiveHigh;
265 config->rxPinPolarity = kFLEXIO_PinActiveHigh;
266 config->bclkPinPolarity = kFLEXIO_PinActiveHigh;
267 config->fsPinPolarity = kFLEXIO_PinActiveLow;
268 config->txTimerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
269 config->rxTimerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
270 }
271
272 /*!
273 * brief De-initializes the FlexIO I2S.
274 *
275 * Calling this API resets the FlexIO I2S shifter and timer config. After calling this API,
276 * call the FLEXO_I2S_Init to use the FlexIO I2S module.
277 *
278 * param base FlexIO I2S base pointer
279 */
FLEXIO_I2S_Deinit(FLEXIO_I2S_Type * base)280 void FLEXIO_I2S_Deinit(FLEXIO_I2S_Type *base)
281 {
282 base->flexioBase->SHIFTCFG[base->txShifterIndex] = 0;
283 base->flexioBase->SHIFTCTL[base->txShifterIndex] = 0;
284 base->flexioBase->SHIFTCFG[base->rxShifterIndex] = 0;
285 base->flexioBase->SHIFTCTL[base->rxShifterIndex] = 0;
286 base->flexioBase->TIMCFG[base->fsTimerIndex] = 0;
287 base->flexioBase->TIMCMP[base->fsTimerIndex] = 0;
288 base->flexioBase->TIMCTL[base->fsTimerIndex] = 0;
289 base->flexioBase->TIMCFG[base->bclkTimerIndex] = 0;
290 base->flexioBase->TIMCMP[base->bclkTimerIndex] = 0;
291 base->flexioBase->TIMCTL[base->bclkTimerIndex] = 0;
292 }
293
294 /*!
295 * brief Enables the FlexIO I2S interrupt.
296 *
297 * This function enables the FlexIO UART interrupt.
298 *
299 * param base Pointer to FLEXIO_I2S_Type structure
300 * param mask interrupt source
301 */
FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type * base,uint32_t mask)302 void FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
303 {
304 if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
305 {
306 FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
307 }
308 if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
309 {
310 FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
311 }
312 }
313
314 /*!
315 * brief Gets the FlexIO I2S status flags.
316 *
317 * param base Pointer to FLEXIO_I2S_Type structure
318 * return Status flag, which are ORed by the enumerators in the _flexio_i2s_status_flags.
319 */
FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type * base)320 uint32_t FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type *base)
321 {
322 uint32_t status = 0;
323 status = ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->txShifterIndex)) >> base->txShifterIndex);
324 status |=
325 (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) >> (base->rxShifterIndex))
326 << 1U);
327 return status;
328 }
329
330 /*!
331 * brief Disables the FlexIO I2S interrupt.
332 *
333 * This function enables the FlexIO UART interrupt.
334 *
335 * param base pointer to FLEXIO_I2S_Type structure
336 * param mask interrupt source
337 */
FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type * base,uint32_t mask)338 void FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
339 {
340 if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
341 {
342 FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
343 }
344 if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
345 {
346 FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
347 }
348 }
349
350 /*!
351 * brief Configures the FlexIO I2S audio format in master mode.
352 *
353 * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
354 * format to be transferred.
355 *
356 * param base Pointer to FLEXIO_I2S_Type structure
357 * param format Pointer to FlexIO I2S audio data format structure.
358 * param srcClock_Hz I2S master clock source frequency in Hz.
359 */
FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type * base,flexio_i2s_format_t * format,uint32_t srcClock_Hz)360 void FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format, uint32_t srcClock_Hz)
361 {
362 uint32_t timDiv = srcClock_Hz / (format->sampleRate_Hz * format->bitWidth * 2U);
363 uint32_t bclkDiv = 0;
364
365 /* Shall keep bclk and fs div an integer */
366 if ((timDiv % 2UL) != 0UL)
367 {
368 timDiv += 1U;
369 }
370 /* Set Frame sync timer cmp */
371 base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * timDiv - 1U);
372
373 /* Set bit clock timer cmp */
374 bclkDiv = ((timDiv / 2U - 1U) | ((format->bitWidth * 2UL - 1UL) << 8U));
375 base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(bclkDiv);
376 }
377
378 /*!
379 * brief Configures the FlexIO I2S audio format in slave mode.
380 *
381 * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
382 * format to be transferred.
383 *
384 * param base Pointer to FLEXIO_I2S_Type structure
385 * param format Pointer to FlexIO I2S audio data format structure.
386 */
FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type * base,flexio_i2s_format_t * format)387 void FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format)
388 {
389 /* Set Frame sync timer cmp */
390 base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 4UL - 3UL);
391
392 /* Set bit clock timer cmp */
393 base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 2UL - 1UL);
394 }
395
396 /*!
397 * brief Sends data using a blocking method.
398 *
399 * note This function blocks via polling until data is ready to be sent.
400 *
401 * param base FlexIO I2S base pointer.
402 * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
403 * param txData Pointer to the data to be written.
404 * param size Bytes to be written.
405 * retval kStatus_Success Successfully write data.
406 * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
407 */
FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * txData,size_t size)408 status_t FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
409 {
410 uint32_t i = 0;
411 uint8_t bytesPerWord = bitWidth / 8U;
412 #if I2S_RETRY_TIMES
413 uint32_t waitTimes = I2S_RETRY_TIMES;
414 #endif
415
416 for (i = 0; i < size / bytesPerWord; i++)
417 {
418 /* Wait until it can write data */
419 #if I2S_RETRY_TIMES
420 waitTimes = I2S_RETRY_TIMES;
421 while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) &&
422 (--waitTimes != 0U))
423 {
424 }
425 if (waitTimes == 0U)
426 {
427 return kStatus_FLEXIO_I2S_Timeout;
428 }
429 #else
430 while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
431 {
432 }
433 #endif
434
435 FLEXIO_I2S_WriteNonBlocking(base, bitWidth, txData, bytesPerWord);
436 txData = (uint8_t *)((uint32_t)txData + bytesPerWord);
437 }
438
439 /* Wait until the last data is sent */
440 #if I2S_RETRY_TIMES
441 waitTimes = I2S_RETRY_TIMES;
442 while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) && (--waitTimes != 0U))
443 {
444 }
445 if (waitTimes == 0U)
446 {
447 return kStatus_FLEXIO_I2S_Timeout;
448 }
449 #else
450 while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
451 {
452 }
453 #endif
454
455 return kStatus_Success;
456 }
457
458 /*!
459 * brief Receives a piece of data using a blocking method.
460 *
461 * note This function blocks via polling until data is ready to be sent.
462 *
463 * param base FlexIO I2S base pointer
464 * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
465 * param rxData Pointer to the data to be read.
466 * param size Bytes to be read.
467 * retval kStatus_Success Successfully read data.
468 * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
469 */
FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * rxData,size_t size)470 status_t FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
471 {
472 uint32_t i = 0;
473 uint8_t bytesPerWord = bitWidth / 8U;
474 #if I2S_RETRY_TIMES
475 uint32_t waitTimes = I2S_RETRY_TIMES;
476 #endif
477
478 for (i = 0; i < size / bytesPerWord; i++)
479 {
480 /* Wait until data is received */
481 #if I2S_RETRY_TIMES
482 waitTimes = I2S_RETRY_TIMES;
483 while ((!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL)) &&
484 (--waitTimes != 0U))
485 {
486 }
487 if (waitTimes == 0U)
488 {
489 return kStatus_FLEXIO_I2S_Timeout;
490 }
491 #else
492 while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL))
493 {
494 }
495 #endif
496
497 FLEXIO_I2S_ReadNonBlocking(base, bitWidth, rxData, bytesPerWord);
498 rxData = (uint8_t *)((uint32_t)rxData + bytesPerWord);
499 }
500 return kStatus_Success;
501 }
502
503 /*!
504 * brief Initializes the FlexIO I2S handle.
505 *
506 * This function initializes the FlexIO I2S handle which can be used for other
507 * FlexIO I2S transactional APIs. Call this API once to get the
508 * initialized handle.
509 *
510 * param base Pointer to FLEXIO_I2S_Type structure
511 * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
512 * param callback FlexIO I2S callback function, which is called while finished a block.
513 * param userData User parameter for the FlexIO I2S callback.
514 */
FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_callback_t callback,void * userData)515 void FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type *base,
516 flexio_i2s_handle_t *handle,
517 flexio_i2s_callback_t callback,
518 void *userData)
519 {
520 assert(handle != NULL);
521
522 IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
523
524 /* Zero the handle. */
525 (void)memset(handle, 0, sizeof(*handle));
526
527 /* Store callback and user data. */
528 handle->callback = callback;
529 handle->userData = userData;
530
531 /* Save the context in global variables to support the double weak mechanism. */
532 (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferTxHandleIRQ);
533
534 /* Set the TX/RX state. */
535 handle->state = (uint32_t)kFLEXIO_I2S_Idle;
536
537 /* Enable interrupt in NVIC. */
538 (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
539 }
540
541 /*!
542 * brief Initializes the FlexIO I2S receive handle.
543 *
544 * This function initializes the FlexIO I2S handle which can be used for other
545 * FlexIO I2S transactional APIs. Call this API once to get the
546 * initialized handle.
547 *
548 * param base Pointer to FLEXIO_I2S_Type structure.
549 * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
550 * param callback FlexIO I2S callback function, which is called while finished a block.
551 * param userData User parameter for the FlexIO I2S callback.
552 */
FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_callback_t callback,void * userData)553 void FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type *base,
554 flexio_i2s_handle_t *handle,
555 flexio_i2s_callback_t callback,
556 void *userData)
557 {
558 assert(handle != NULL);
559
560 IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
561
562 /* Zero the handle. */
563 (void)memset(handle, 0, sizeof(*handle));
564
565 /* Store callback and user data. */
566 handle->callback = callback;
567 handle->userData = userData;
568
569 /* Save the context in global variables to support the double weak mechanism. */
570 (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferRxHandleIRQ);
571
572 /* Set the TX/RX state. */
573 handle->state = (uint32_t)kFLEXIO_I2S_Idle;
574
575 /* Enable interrupt in NVIC. */
576 (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
577 }
578
579 /*!
580 * brief Configures the FlexIO I2S audio format.
581 *
582 * Audio format can be changed at run-time of FlexIO I2S. This function configures the sample rate and audio data
583 * format to be transferred.
584 *
585 * param base Pointer to FLEXIO_I2S_Type structure.
586 * param handle FlexIO I2S handle pointer.
587 * param format Pointer to audio data format structure.
588 * param srcClock_Hz FlexIO I2S bit clock source frequency in Hz. This parameter should be 0 while in slave mode.
589 */
FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_format_t * format,uint32_t srcClock_Hz)590 void FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type *base,
591 flexio_i2s_handle_t *handle,
592 flexio_i2s_format_t *format,
593 uint32_t srcClock_Hz)
594 {
595 assert((handle != NULL) && (format != NULL));
596
597 /* Set the bitWidth to handle */
598 handle->bitWidth = format->bitWidth;
599
600 /* Set sample rate */
601 if (srcClock_Hz != 0UL)
602 {
603 /* It is master */
604 FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
605 }
606 else
607 {
608 FLEXIO_I2S_SlaveSetFormat(base, format);
609 }
610 }
611
612 /*!
613 * brief Performs an interrupt non-blocking send transfer on FlexIO I2S.
614 *
615 * note The API returns immediately after transfer initiates.
616 * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status and check whether
617 * the transfer is finished. If the return status is 0, the transfer is finished.
618 *
619 * param base Pointer to FLEXIO_I2S_Type structure.
620 * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
621 * param xfer Pointer to flexio_i2s_transfer_t structure
622 * retval kStatus_Success Successfully start the data transmission.
623 * retval kStatus_FLEXIO_I2S_TxBusy Previous transmission still not finished, data not all written to TX register yet.
624 * retval kStatus_InvalidArgument The input parameter is invalid.
625 */
FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_transfer_t * xfer)626 status_t FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type *base,
627 flexio_i2s_handle_t *handle,
628 flexio_i2s_transfer_t *xfer)
629 {
630 assert(handle != NULL);
631
632 /* Check if the queue is full */
633 if (handle->queue[handle->queueUser].data != NULL)
634 {
635 return kStatus_FLEXIO_I2S_QueueFull;
636 }
637 if ((xfer->dataSize == 0U) || (xfer->data == NULL))
638 {
639 return kStatus_InvalidArgument;
640 }
641
642 /* Add into queue */
643 handle->queue[handle->queueUser].data = xfer->data;
644 handle->queue[handle->queueUser].dataSize = xfer->dataSize;
645 handle->transferSize[handle->queueUser] = xfer->dataSize;
646 handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
647
648 /* Set the state to busy */
649 handle->state = (uint32_t)kFLEXIO_I2S_Busy;
650
651 FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
652
653 /* Enable Tx transfer */
654 FLEXIO_I2S_Enable(base, true);
655
656 return kStatus_Success;
657 }
658
659 /*!
660 * brief Performs an interrupt non-blocking receive transfer on FlexIO I2S.
661 *
662 * note The API returns immediately after transfer initiates.
663 * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status to check whether
664 * the transfer is finished. If the return status is 0, the transfer is finished.
665 *
666 * param base Pointer to FLEXIO_I2S_Type structure.
667 * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
668 * param xfer Pointer to flexio_i2s_transfer_t structure
669 * retval kStatus_Success Successfully start the data receive.
670 * retval kStatus_FLEXIO_I2S_RxBusy Previous receive still not finished.
671 * retval kStatus_InvalidArgument The input parameter is invalid.
672 */
FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_transfer_t * xfer)673 status_t FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type *base,
674 flexio_i2s_handle_t *handle,
675 flexio_i2s_transfer_t *xfer)
676 {
677 assert(handle != NULL);
678
679 /* Check if the queue is full */
680 if (handle->queue[handle->queueUser].data != NULL)
681 {
682 return kStatus_FLEXIO_I2S_QueueFull;
683 }
684
685 if ((xfer->dataSize == 0U) || (xfer->data == NULL))
686 {
687 return kStatus_InvalidArgument;
688 }
689
690 /* Add into queue */
691 handle->queue[handle->queueUser].data = xfer->data;
692 handle->queue[handle->queueUser].dataSize = xfer->dataSize;
693 handle->transferSize[handle->queueUser] = xfer->dataSize;
694 handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
695
696 /* Set state to busy */
697 handle->state = (uint32_t)kFLEXIO_I2S_Busy;
698
699 /* Enable interrupt */
700 FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
701
702 /* Enable Rx transfer */
703 FLEXIO_I2S_Enable(base, true);
704
705 return kStatus_Success;
706 }
707
708 /*!
709 * brief Aborts the current send.
710 *
711 * note This API can be called at any time when interrupt non-blocking transfer initiates
712 * to abort the transfer in a early time.
713 *
714 * param base Pointer to FLEXIO_I2S_Type structure.
715 * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
716 */
FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle)717 void FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
718 {
719 assert(handle != NULL);
720
721 /* Stop Tx transfer and disable interrupt */
722 FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
723 handle->state = (uint32_t)kFLEXIO_I2S_Idle;
724
725 /* Clear the queue */
726 (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
727 handle->queueDriver = 0;
728 handle->queueUser = 0;
729 }
730
731 /*!
732 * brief Aborts the current receive.
733 *
734 * note This API can be called at any time when interrupt non-blocking transfer initiates
735 * to abort the transfer in a early time.
736 *
737 * param base Pointer to FLEXIO_I2S_Type structure.
738 * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
739 */
FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle)740 void FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
741 {
742 assert(handle != NULL);
743
744 /* Stop rx transfer and disable interrupt */
745 FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
746 handle->state = (uint32_t)kFLEXIO_I2S_Idle;
747
748 /* Clear the queue */
749 (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
750 handle->queueDriver = 0;
751 handle->queueUser = 0;
752 }
753
754 /*!
755 * brief Gets the remaining bytes to be sent.
756 *
757 * param base Pointer to FLEXIO_I2S_Type structure.
758 * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
759 * param count Bytes sent.
760 * retval kStatus_Success Succeed get the transfer count.
761 * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
762 */
FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,size_t * count)763 status_t FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
764 {
765 assert(handle != NULL);
766
767 status_t status = kStatus_Success;
768 uint8_t queueDriver = handle->queueDriver;
769
770 if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
771 {
772 status = kStatus_NoTransferInProgress;
773 }
774 else
775 {
776 *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
777 }
778
779 return status;
780 }
781
782 /*!
783 * brief Gets the remaining bytes to be received.
784 *
785 * param base Pointer to FLEXIO_I2S_Type structure.
786 * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
787 * return count Bytes received.
788 * retval kStatus_Success Succeed get the transfer count.
789 * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
790 */
FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,size_t * count)791 status_t FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
792 {
793 assert(handle != NULL);
794
795 status_t status = kStatus_Success;
796 uint8_t queueDriver = handle->queueDriver;
797
798 if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
799 {
800 status = kStatus_NoTransferInProgress;
801 }
802 else
803 {
804 *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
805 }
806
807 return status;
808 }
809
810 /*!
811 * brief Tx interrupt handler.
812 *
813 * param i2sBase Pointer to FLEXIO_I2S_Type structure.
814 * param i2sHandle Pointer to flexio_i2s_handle_t structure
815 */
FLEXIO_I2S_TransferTxHandleIRQ(void * i2sBase,void * i2sHandle)816 void FLEXIO_I2S_TransferTxHandleIRQ(void *i2sBase, void *i2sHandle)
817 {
818 assert(i2sHandle != NULL);
819
820 flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
821 FLEXIO_I2S_Type *base = (FLEXIO_I2S_Type *)i2sBase;
822 uint8_t *buffer = handle->queue[handle->queueDriver].data;
823 uint8_t dataSize = handle->bitWidth / 8U;
824
825 /* Handle error */
826 if ((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->txShifterIndex)) != 0UL)
827 {
828 FLEXIO_ClearShifterErrorFlags(base->flexioBase, (1UL << base->txShifterIndex));
829 }
830 /* Handle transfer */
831 if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) != 0UL) &&
832 (handle->queue[handle->queueDriver].data != NULL))
833 {
834 FLEXIO_I2S_WriteNonBlocking(base, handle->bitWidth, buffer, dataSize);
835
836 /* Update internal counter */
837 handle->queue[handle->queueDriver].dataSize -= dataSize;
838 handle->queue[handle->queueDriver].data =
839 (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
840 }
841
842 /* If finished a block, call the callback function */
843 if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
844 {
845 (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
846 handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
847 if (handle->callback != NULL)
848 {
849 (handle->callback)(base, handle, kStatus_Success, handle->userData);
850 }
851 }
852
853 /* If all data finished, just stop the transfer */
854 if (handle->queue[handle->queueDriver].data == NULL)
855 {
856 FLEXIO_I2S_TransferAbortSend(base, handle);
857 }
858 }
859
860 /*!
861 * brief Rx interrupt handler.
862 *
863 * param i2sBase Pointer to FLEXIO_I2S_Type structure.
864 * param i2sHandle Pointer to flexio_i2s_handle_t structure.
865 */
FLEXIO_I2S_TransferRxHandleIRQ(void * i2sBase,void * i2sHandle)866 void FLEXIO_I2S_TransferRxHandleIRQ(void *i2sBase, void *i2sHandle)
867 {
868 assert(i2sHandle != NULL);
869
870 flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
871 FLEXIO_I2S_Type *base = (FLEXIO_I2S_Type *)i2sBase;
872 uint8_t *buffer = handle->queue[handle->queueDriver].data;
873 uint8_t dataSize = handle->bitWidth / 8U;
874
875 /* Handle transfer */
876 if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_RxDataRegFullFlag) != 0UL) &&
877 (handle->queue[handle->queueDriver].data != NULL))
878 {
879 FLEXIO_I2S_ReadNonBlocking(base, handle->bitWidth, buffer, dataSize);
880
881 /* Update internal state */
882 handle->queue[handle->queueDriver].dataSize -= dataSize;
883 handle->queue[handle->queueDriver].data =
884 (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
885 }
886
887 /* If finished a block, call the callback function */
888 if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
889 {
890 (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
891 handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
892 if (handle->callback != NULL)
893 {
894 (handle->callback)(base, handle, kStatus_Success, handle->userData);
895 }
896 }
897
898 /* If all data finished, just stop the transfer */
899 if (handle->queue[handle->queueDriver].data == NULL)
900 {
901 FLEXIO_I2S_TransferAbortReceive(base, handle);
902 }
903 }
904