Lee Kai Xuan / mbed-os

Fork of mbed-os by erkin yucel

Committer:
xuaner
Date:
Thu Jul 20 14:26:57 2017 +0000
Revision:
1:3deb71413561
Parent:
0:f269e3021894
mbed_os

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 /*
elessair 0:f269e3021894 2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
elessair 0:f269e3021894 3 * All rights reserved.
elessair 0:f269e3021894 4 *
elessair 0:f269e3021894 5 * Redistribution and use in source and binary forms, with or without modification,
elessair 0:f269e3021894 6 * are permitted provided that the following conditions are met:
elessair 0:f269e3021894 7 *
elessair 0:f269e3021894 8 * o Redistributions of source code must retain the above copyright notice, this list
elessair 0:f269e3021894 9 * of conditions and the following disclaimer.
elessair 0:f269e3021894 10 *
elessair 0:f269e3021894 11 * o Redistributions in binary form must reproduce the above copyright notice, this
elessair 0:f269e3021894 12 * list of conditions and the following disclaimer in the documentation and/or
elessair 0:f269e3021894 13 * other materials provided with the distribution.
elessair 0:f269e3021894 14 *
elessair 0:f269e3021894 15 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
elessair 0:f269e3021894 16 * contributors may be used to endorse or promote products derived from this
elessair 0:f269e3021894 17 * software without specific prior written permission.
elessair 0:f269e3021894 18 *
elessair 0:f269e3021894 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
elessair 0:f269e3021894 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
elessair 0:f269e3021894 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
elessair 0:f269e3021894 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
elessair 0:f269e3021894 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
elessair 0:f269e3021894 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
elessair 0:f269e3021894 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
elessair 0:f269e3021894 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
elessair 0:f269e3021894 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
elessair 0:f269e3021894 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
elessair 0:f269e3021894 29 */
elessair 0:f269e3021894 30
elessair 0:f269e3021894 31 #include "fsl_sai.h"
elessair 0:f269e3021894 32
elessair 0:f269e3021894 33 /*******************************************************************************
elessair 0:f269e3021894 34 * Definitations
elessair 0:f269e3021894 35 ******************************************************************************/
elessair 0:f269e3021894 36 enum _sai_transfer_state
elessair 0:f269e3021894 37 {
elessair 0:f269e3021894 38 kSAI_Busy = 0x0U, /*!< SAI is busy */
elessair 0:f269e3021894 39 kSAI_Idle, /*!< Transfer is done. */
elessair 0:f269e3021894 40 kSAI_Error /*!< Transfer error occured. */
elessair 0:f269e3021894 41 };
elessair 0:f269e3021894 42
elessair 0:f269e3021894 43 /*! @brief Typedef for sai tx interrupt handler. */
elessair 0:f269e3021894 44 typedef void (*sai_tx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
elessair 0:f269e3021894 45
elessair 0:f269e3021894 46 /*! @brief Typedef for sai rx interrupt handler. */
elessair 0:f269e3021894 47 typedef void (*sai_rx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
elessair 0:f269e3021894 48
elessair 0:f269e3021894 49 /*******************************************************************************
elessair 0:f269e3021894 50 * Prototypes
elessair 0:f269e3021894 51 ******************************************************************************/
elessair 0:f269e3021894 52 #if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
elessair 0:f269e3021894 53
elessair 0:f269e3021894 54 /*!
elessair 0:f269e3021894 55 * @brief Set the master clock divider.
elessair 0:f269e3021894 56 *
elessair 0:f269e3021894 57 * This API will compute the master clock divider according to master clock frequency and master
elessair 0:f269e3021894 58 * clock source clock source frequency.
elessair 0:f269e3021894 59 *
elessair 0:f269e3021894 60 * @param base SAI base pointer.
elessair 0:f269e3021894 61 * @param mclk_Hz Mater clock frequency in Hz.
elessair 0:f269e3021894 62 * @param mclkSrcClock_Hz Master clock source frequency in Hz.
elessair 0:f269e3021894 63 */
elessair 0:f269e3021894 64 static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz);
elessair 0:f269e3021894 65 #endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
elessair 0:f269e3021894 66
elessair 0:f269e3021894 67 /*!
elessair 0:f269e3021894 68 * @brief Get the instance number for SAI.
elessair 0:f269e3021894 69 *
elessair 0:f269e3021894 70 * @param base SAI base pointer.
elessair 0:f269e3021894 71 */
elessair 0:f269e3021894 72 uint32_t SAI_GetInstance(I2S_Type *base);
elessair 0:f269e3021894 73
elessair 0:f269e3021894 74 /*!
elessair 0:f269e3021894 75 * @brief sends a piece of data in non-blocking way.
elessair 0:f269e3021894 76 *
elessair 0:f269e3021894 77 * @param base SAI base pointer
elessair 0:f269e3021894 78 * @param channel Data channel used.
elessair 0:f269e3021894 79 * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
elessair 0:f269e3021894 80 * @param buffer Pointer to the data to be written.
elessair 0:f269e3021894 81 * @param size Bytes to be written.
elessair 0:f269e3021894 82 */
elessair 0:f269e3021894 83 static void SAI_WriteNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
elessair 0:f269e3021894 84
elessair 0:f269e3021894 85 /*!
elessair 0:f269e3021894 86 * @brief Receive a piece of data in non-blocking way.
elessair 0:f269e3021894 87 *
elessair 0:f269e3021894 88 * @param base SAI base pointer
elessair 0:f269e3021894 89 * @param channel Data channel used.
elessair 0:f269e3021894 90 * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
elessair 0:f269e3021894 91 * @param buffer Pointer to the data to be read.
elessair 0:f269e3021894 92 * @param size Bytes to be read.
elessair 0:f269e3021894 93 */
elessair 0:f269e3021894 94 static void SAI_ReadNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size);
elessair 0:f269e3021894 95 /*******************************************************************************
elessair 0:f269e3021894 96 * Variables
elessair 0:f269e3021894 97 ******************************************************************************/
elessair 0:f269e3021894 98 /*!@brief SAI handle pointer */
elessair 0:f269e3021894 99 sai_handle_t *s_saiHandle[FSL_FEATURE_SOC_I2S_COUNT][2];
elessair 0:f269e3021894 100 /* Base pointer array */
elessair 0:f269e3021894 101 static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
elessair 0:f269e3021894 102 /* IRQ number array */
elessair 0:f269e3021894 103 static const IRQn_Type s_saiTxIRQ[] = I2S_TX_IRQS;
elessair 0:f269e3021894 104 static const IRQn_Type s_saiRxIRQ[] = I2S_RX_IRQS;
elessair 0:f269e3021894 105 /* Clock name array */
elessair 0:f269e3021894 106 static const clock_ip_name_t s_saiClock[] = SAI_CLOCKS;
elessair 0:f269e3021894 107 /*! @brief Pointer to tx IRQ handler for each instance. */
elessair 0:f269e3021894 108 static sai_tx_isr_t s_saiTxIsr;
elessair 0:f269e3021894 109 /*! @brief Pointer to tx IRQ handler for each instance. */
elessair 0:f269e3021894 110 static sai_rx_isr_t s_saiRxIsr;
elessair 0:f269e3021894 111
elessair 0:f269e3021894 112 /*******************************************************************************
elessair 0:f269e3021894 113 * Code
elessair 0:f269e3021894 114 ******************************************************************************/
elessair 0:f269e3021894 115 #if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
elessair 0:f269e3021894 116 static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz)
elessair 0:f269e3021894 117 {
elessair 0:f269e3021894 118 uint32_t freq = mclkSrcClock_Hz;
elessair 0:f269e3021894 119 uint16_t fract, divide;
elessair 0:f269e3021894 120 uint32_t remaind = 0;
elessair 0:f269e3021894 121 uint32_t current_remainder = 0xFFFFFFFFU;
elessair 0:f269e3021894 122 uint16_t current_fract = 0;
elessair 0:f269e3021894 123 uint16_t current_divide = 0;
elessair 0:f269e3021894 124 uint32_t mul_freq = 0;
elessair 0:f269e3021894 125 uint32_t max_fract = 256;
elessair 0:f269e3021894 126
elessair 0:f269e3021894 127 /*In order to prevent overflow */
elessair 0:f269e3021894 128 freq /= 100;
elessair 0:f269e3021894 129 mclk_Hz /= 100;
elessair 0:f269e3021894 130
elessair 0:f269e3021894 131 /* Compute the max fract number */
elessair 0:f269e3021894 132 max_fract = mclk_Hz * 4096 / freq + 1;
elessair 0:f269e3021894 133 if (max_fract > 256)
elessair 0:f269e3021894 134 {
elessair 0:f269e3021894 135 max_fract = 256;
elessair 0:f269e3021894 136 }
elessair 0:f269e3021894 137
elessair 0:f269e3021894 138 /* Looking for the closet frequency */
elessair 0:f269e3021894 139 for (fract = 1; fract < max_fract; fract++)
elessair 0:f269e3021894 140 {
elessair 0:f269e3021894 141 mul_freq = freq * fract;
elessair 0:f269e3021894 142 remaind = mul_freq % mclk_Hz;
elessair 0:f269e3021894 143 divide = mul_freq / mclk_Hz;
elessair 0:f269e3021894 144
elessair 0:f269e3021894 145 /* Find the exactly frequency */
elessair 0:f269e3021894 146 if (remaind == 0)
elessair 0:f269e3021894 147 {
elessair 0:f269e3021894 148 current_fract = fract;
elessair 0:f269e3021894 149 current_divide = mul_freq / mclk_Hz;
elessair 0:f269e3021894 150 break;
elessair 0:f269e3021894 151 }
elessair 0:f269e3021894 152
elessair 0:f269e3021894 153 /* Closer to next one, set the closest to next data */
elessair 0:f269e3021894 154 if (remaind > mclk_Hz / 2)
elessair 0:f269e3021894 155 {
elessair 0:f269e3021894 156 remaind = mclk_Hz - remaind;
elessair 0:f269e3021894 157 divide += 1;
elessair 0:f269e3021894 158 }
elessair 0:f269e3021894 159
elessair 0:f269e3021894 160 /* Update the closest div and fract */
elessair 0:f269e3021894 161 if (remaind < current_remainder)
elessair 0:f269e3021894 162 {
elessair 0:f269e3021894 163 current_fract = fract;
elessair 0:f269e3021894 164 current_divide = divide;
elessair 0:f269e3021894 165 current_remainder = remaind;
elessair 0:f269e3021894 166 }
elessair 0:f269e3021894 167 }
elessair 0:f269e3021894 168
elessair 0:f269e3021894 169 /* Fill the computed fract and divider to registers */
elessair 0:f269e3021894 170 base->MDR = I2S_MDR_DIVIDE(current_divide - 1) | I2S_MDR_FRACT(current_fract - 1);
elessair 0:f269e3021894 171
elessair 0:f269e3021894 172 /* Waiting for the divider updated */
elessair 0:f269e3021894 173 while (base->MCR & I2S_MCR_DUF_MASK)
elessair 0:f269e3021894 174 {
elessair 0:f269e3021894 175 }
elessair 0:f269e3021894 176 }
elessair 0:f269e3021894 177 #endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
elessair 0:f269e3021894 178
elessair 0:f269e3021894 179 uint32_t SAI_GetInstance(I2S_Type *base)
elessair 0:f269e3021894 180 {
elessair 0:f269e3021894 181 uint32_t instance;
elessair 0:f269e3021894 182
elessair 0:f269e3021894 183 /* Find the instance index from base address mappings. */
elessair 0:f269e3021894 184 for (instance = 0; instance < FSL_FEATURE_SOC_I2S_COUNT; instance++)
elessair 0:f269e3021894 185 {
elessair 0:f269e3021894 186 if (s_saiBases[instance] == base)
elessair 0:f269e3021894 187 {
elessair 0:f269e3021894 188 break;
elessair 0:f269e3021894 189 }
elessair 0:f269e3021894 190 }
elessair 0:f269e3021894 191
elessair 0:f269e3021894 192 assert(instance < FSL_FEATURE_SOC_I2S_COUNT);
elessair 0:f269e3021894 193
elessair 0:f269e3021894 194 return instance;
elessair 0:f269e3021894 195 }
elessair 0:f269e3021894 196
elessair 0:f269e3021894 197 static void SAI_WriteNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
elessair 0:f269e3021894 198 {
elessair 0:f269e3021894 199 uint32_t i = 0;
elessair 0:f269e3021894 200 uint8_t j = 0;
elessair 0:f269e3021894 201 uint8_t bytesPerWord = bitWidth / 8U;
elessair 0:f269e3021894 202 uint32_t data = 0;
elessair 0:f269e3021894 203 uint32_t temp = 0;
elessair 0:f269e3021894 204
elessair 0:f269e3021894 205 for (i = 0; i < size / bytesPerWord; i++)
elessair 0:f269e3021894 206 {
elessair 0:f269e3021894 207 for (j = 0; j < bytesPerWord; j++)
elessair 0:f269e3021894 208 {
elessair 0:f269e3021894 209 temp = (uint32_t)(*buffer);
elessair 0:f269e3021894 210 data |= (temp << (8U * j));
elessair 0:f269e3021894 211 buffer++;
elessair 0:f269e3021894 212 }
elessair 0:f269e3021894 213 base->TDR[channel] = data;
elessair 0:f269e3021894 214 data = 0;
elessair 0:f269e3021894 215 }
elessair 0:f269e3021894 216 }
elessair 0:f269e3021894 217
elessair 0:f269e3021894 218 static void SAI_ReadNonBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
elessair 0:f269e3021894 219 {
elessair 0:f269e3021894 220 uint32_t i = 0;
elessair 0:f269e3021894 221 uint8_t j = 0;
elessair 0:f269e3021894 222 uint8_t bytesPerWord = bitWidth / 8U;
elessair 0:f269e3021894 223 uint32_t data = 0;
elessair 0:f269e3021894 224
elessair 0:f269e3021894 225 for (i = 0; i < size / bytesPerWord; i++)
elessair 0:f269e3021894 226 {
elessair 0:f269e3021894 227 data = base->RDR[channel];
elessair 0:f269e3021894 228 for (j = 0; j < bytesPerWord; j++)
elessair 0:f269e3021894 229 {
elessair 0:f269e3021894 230 *buffer = (data >> (8U * j)) & 0xFF;
elessair 0:f269e3021894 231 buffer++;
elessair 0:f269e3021894 232 }
elessair 0:f269e3021894 233 }
elessair 0:f269e3021894 234 }
elessair 0:f269e3021894 235
elessair 0:f269e3021894 236 void SAI_TxInit(I2S_Type *base, const sai_config_t *config)
elessair 0:f269e3021894 237 {
elessair 0:f269e3021894 238 uint32_t val = 0;
elessair 0:f269e3021894 239
elessair 0:f269e3021894 240 /* Enable the SAI clock */
elessair 0:f269e3021894 241 CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
elessair 0:f269e3021894 242
elessair 0:f269e3021894 243 #if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
elessair 0:f269e3021894 244 /* Master clock source setting */
elessair 0:f269e3021894 245 val = (base->MCR & ~I2S_MCR_MICS_MASK);
elessair 0:f269e3021894 246 base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
elessair 0:f269e3021894 247
elessair 0:f269e3021894 248 /* Configure Master clock output enable */
elessair 0:f269e3021894 249 val = (base->MCR & ~I2S_MCR_MOE_MASK);
elessair 0:f269e3021894 250 base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
elessair 0:f269e3021894 251 #endif /* FSL_FEATURE_SAI_HAS_MCR */
elessair 0:f269e3021894 252
elessair 0:f269e3021894 253 /* Configure audio protocol */
elessair 0:f269e3021894 254 switch (config->protocol)
elessair 0:f269e3021894 255 {
elessair 0:f269e3021894 256 case kSAI_BusLeftJustified:
elessair 0:f269e3021894 257 base->TCR2 |= I2S_TCR2_BCP_MASK;
elessair 0:f269e3021894 258 base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
elessair 0:f269e3021894 259 base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
elessair 0:f269e3021894 260 break;
elessair 0:f269e3021894 261
elessair 0:f269e3021894 262 case kSAI_BusRightJustified:
elessair 0:f269e3021894 263 base->TCR2 |= I2S_TCR2_BCP_MASK;
elessair 0:f269e3021894 264 base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
elessair 0:f269e3021894 265 base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
elessair 0:f269e3021894 266 break;
elessair 0:f269e3021894 267
elessair 0:f269e3021894 268 case kSAI_BusI2S:
elessair 0:f269e3021894 269 base->TCR2 |= I2S_TCR2_BCP_MASK;
elessair 0:f269e3021894 270 base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
elessair 0:f269e3021894 271 base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(1U) | I2S_TCR4_FRSZ(1U);
elessair 0:f269e3021894 272 break;
elessair 0:f269e3021894 273
elessair 0:f269e3021894 274 case kSAI_BusPCMA:
elessair 0:f269e3021894 275 base->TCR2 &= ~I2S_TCR2_BCP_MASK;
elessair 0:f269e3021894 276 base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
elessair 0:f269e3021894 277 base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
elessair 0:f269e3021894 278 break;
elessair 0:f269e3021894 279
elessair 0:f269e3021894 280 case kSAI_BusPCMB:
elessair 0:f269e3021894 281 base->TCR2 &= ~I2S_TCR2_BCP_MASK;
elessair 0:f269e3021894 282 base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
elessair 0:f269e3021894 283 base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
elessair 0:f269e3021894 284 break;
elessair 0:f269e3021894 285
elessair 0:f269e3021894 286 default:
elessair 0:f269e3021894 287 break;
elessair 0:f269e3021894 288 }
elessair 0:f269e3021894 289
elessair 0:f269e3021894 290 /* Set master or slave */
elessair 0:f269e3021894 291 if (config->masterSlave == kSAI_Master)
elessair 0:f269e3021894 292 {
elessair 0:f269e3021894 293 base->TCR2 |= I2S_TCR2_BCD_MASK;
elessair 0:f269e3021894 294 base->TCR4 |= I2S_TCR4_FSD_MASK;
elessair 0:f269e3021894 295
elessair 0:f269e3021894 296 /* Bit clock source setting */
elessair 0:f269e3021894 297 val = base->TCR2 & (~I2S_TCR2_MSEL_MASK);
elessair 0:f269e3021894 298 base->TCR2 = (val | I2S_TCR2_MSEL(config->bclkSource));
elessair 0:f269e3021894 299 }
elessair 0:f269e3021894 300 else
elessair 0:f269e3021894 301 {
elessair 0:f269e3021894 302 base->TCR2 &= ~I2S_TCR2_BCD_MASK;
elessair 0:f269e3021894 303 base->TCR4 &= ~I2S_TCR4_FSD_MASK;
elessair 0:f269e3021894 304 }
elessair 0:f269e3021894 305
elessair 0:f269e3021894 306 /* Set Sync mode */
elessair 0:f269e3021894 307 switch (config->syncMode)
elessair 0:f269e3021894 308 {
elessair 0:f269e3021894 309 case kSAI_ModeAsync:
elessair 0:f269e3021894 310 val = base->TCR2;
elessair 0:f269e3021894 311 val &= ~I2S_TCR2_SYNC_MASK;
elessair 0:f269e3021894 312 base->TCR2 = (val | I2S_TCR2_SYNC(0U));
elessair 0:f269e3021894 313 break;
elessair 0:f269e3021894 314 case kSAI_ModeSync:
elessair 0:f269e3021894 315 val = base->TCR2;
elessair 0:f269e3021894 316 val &= ~I2S_TCR2_SYNC_MASK;
elessair 0:f269e3021894 317 base->TCR2 = (val | I2S_TCR2_SYNC(1U));
elessair 0:f269e3021894 318 /* If sync with Rx, should set Rx to async mode */
elessair 0:f269e3021894 319 val = base->RCR2;
elessair 0:f269e3021894 320 val &= ~I2S_RCR2_SYNC_MASK;
elessair 0:f269e3021894 321 base->RCR2 = (val | I2S_RCR2_SYNC(0U));
elessair 0:f269e3021894 322 break;
elessair 0:f269e3021894 323 case kSAI_ModeSyncWithOtherTx:
elessair 0:f269e3021894 324 val = base->TCR2;
elessair 0:f269e3021894 325 val &= ~I2S_TCR2_SYNC_MASK;
elessair 0:f269e3021894 326 base->TCR2 = (val | I2S_TCR2_SYNC(2U));
elessair 0:f269e3021894 327 break;
elessair 0:f269e3021894 328 case kSAI_ModeSyncWithOtherRx:
elessair 0:f269e3021894 329 val = base->TCR2;
elessair 0:f269e3021894 330 val &= ~I2S_TCR2_SYNC_MASK;
elessair 0:f269e3021894 331 base->TCR2 = (val | I2S_TCR2_SYNC(3U));
elessair 0:f269e3021894 332 break;
elessair 0:f269e3021894 333 default:
elessair 0:f269e3021894 334 break;
elessair 0:f269e3021894 335 }
elessair 0:f269e3021894 336 }
elessair 0:f269e3021894 337
elessair 0:f269e3021894 338 void SAI_RxInit(I2S_Type *base, const sai_config_t *config)
elessair 0:f269e3021894 339 {
elessair 0:f269e3021894 340 uint32_t val = 0;
elessair 0:f269e3021894 341
elessair 0:f269e3021894 342 /* Enable SAI clock first. */
elessair 0:f269e3021894 343 CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
elessair 0:f269e3021894 344
elessair 0:f269e3021894 345 #if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
elessair 0:f269e3021894 346 /* Master clock source setting */
elessair 0:f269e3021894 347 val = (base->MCR & ~I2S_MCR_MICS_MASK);
elessair 0:f269e3021894 348 base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
elessair 0:f269e3021894 349
elessair 0:f269e3021894 350 /* Configure Master clock output enable */
elessair 0:f269e3021894 351 val = (base->MCR & ~I2S_MCR_MOE_MASK);
elessair 0:f269e3021894 352 base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
elessair 0:f269e3021894 353 #endif /* FSL_FEATURE_SAI_HAS_MCR */
elessair 0:f269e3021894 354
elessair 0:f269e3021894 355 /* Configure audio protocol */
elessair 0:f269e3021894 356 switch (config->protocol)
elessair 0:f269e3021894 357 {
elessair 0:f269e3021894 358 case kSAI_BusLeftJustified:
elessair 0:f269e3021894 359 base->RCR2 |= I2S_RCR2_BCP_MASK;
elessair 0:f269e3021894 360 base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
elessair 0:f269e3021894 361 base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
elessair 0:f269e3021894 362 break;
elessair 0:f269e3021894 363
elessair 0:f269e3021894 364 case kSAI_BusRightJustified:
elessair 0:f269e3021894 365 base->RCR2 |= I2S_RCR2_BCP_MASK;
elessair 0:f269e3021894 366 base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
elessair 0:f269e3021894 367 base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
elessair 0:f269e3021894 368 break;
elessair 0:f269e3021894 369
elessair 0:f269e3021894 370 case kSAI_BusI2S:
elessair 0:f269e3021894 371 base->RCR2 |= I2S_RCR2_BCP_MASK;
elessair 0:f269e3021894 372 base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
elessair 0:f269e3021894 373 base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(1U) | I2S_RCR4_FRSZ(1U);
elessair 0:f269e3021894 374 break;
elessair 0:f269e3021894 375
elessair 0:f269e3021894 376 case kSAI_BusPCMA:
elessair 0:f269e3021894 377 base->RCR2 &= ~I2S_RCR2_BCP_MASK;
elessair 0:f269e3021894 378 base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
elessair 0:f269e3021894 379 base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
elessair 0:f269e3021894 380 break;
elessair 0:f269e3021894 381
elessair 0:f269e3021894 382 case kSAI_BusPCMB:
elessair 0:f269e3021894 383 base->RCR2 &= ~I2S_RCR2_BCP_MASK;
elessair 0:f269e3021894 384 base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
elessair 0:f269e3021894 385 base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
elessair 0:f269e3021894 386 break;
elessair 0:f269e3021894 387
elessair 0:f269e3021894 388 default:
elessair 0:f269e3021894 389 break;
elessair 0:f269e3021894 390 }
elessair 0:f269e3021894 391
elessair 0:f269e3021894 392 /* Set master or slave */
elessair 0:f269e3021894 393 if (config->masterSlave == kSAI_Master)
elessair 0:f269e3021894 394 {
elessair 0:f269e3021894 395 base->RCR2 |= I2S_RCR2_BCD_MASK;
elessair 0:f269e3021894 396 base->RCR4 |= I2S_RCR4_FSD_MASK;
elessair 0:f269e3021894 397
elessair 0:f269e3021894 398 /* Bit clock source setting */
elessair 0:f269e3021894 399 val = base->RCR2 & (~I2S_RCR2_MSEL_MASK);
elessair 0:f269e3021894 400 base->RCR2 = (val | I2S_RCR2_MSEL(config->bclkSource));
elessair 0:f269e3021894 401 }
elessair 0:f269e3021894 402 else
elessair 0:f269e3021894 403 {
elessair 0:f269e3021894 404 base->RCR2 &= ~I2S_RCR2_BCD_MASK;
elessair 0:f269e3021894 405 base->RCR4 &= ~I2S_RCR4_FSD_MASK;
elessair 0:f269e3021894 406 }
elessair 0:f269e3021894 407
elessair 0:f269e3021894 408 /* Set Sync mode */
elessair 0:f269e3021894 409 switch (config->syncMode)
elessair 0:f269e3021894 410 {
elessair 0:f269e3021894 411 case kSAI_ModeAsync:
elessair 0:f269e3021894 412 val = base->RCR2;
elessair 0:f269e3021894 413 val &= ~I2S_RCR2_SYNC_MASK;
elessair 0:f269e3021894 414 base->RCR2 = (val | I2S_RCR2_SYNC(0U));
elessair 0:f269e3021894 415 break;
elessair 0:f269e3021894 416 case kSAI_ModeSync:
elessair 0:f269e3021894 417 val = base->RCR2;
elessair 0:f269e3021894 418 val &= ~I2S_RCR2_SYNC_MASK;
elessair 0:f269e3021894 419 base->RCR2 = (val | I2S_RCR2_SYNC(1U));
elessair 0:f269e3021894 420 /* If sync with Tx, should set Tx to async mode */
elessair 0:f269e3021894 421 val = base->TCR2;
elessair 0:f269e3021894 422 val &= ~I2S_TCR2_SYNC_MASK;
elessair 0:f269e3021894 423 base->TCR2 = (val | I2S_TCR2_SYNC(0U));
elessair 0:f269e3021894 424 break;
elessair 0:f269e3021894 425 case kSAI_ModeSyncWithOtherTx:
elessair 0:f269e3021894 426 val = base->RCR2;
elessair 0:f269e3021894 427 val &= ~I2S_RCR2_SYNC_MASK;
elessair 0:f269e3021894 428 base->RCR2 = (val | I2S_RCR2_SYNC(2U));
elessair 0:f269e3021894 429 break;
elessair 0:f269e3021894 430 case kSAI_ModeSyncWithOtherRx:
elessair 0:f269e3021894 431 val = base->RCR2;
elessair 0:f269e3021894 432 val &= ~I2S_RCR2_SYNC_MASK;
elessair 0:f269e3021894 433 base->RCR2 = (val | I2S_RCR2_SYNC(3U));
elessair 0:f269e3021894 434 break;
elessair 0:f269e3021894 435 default:
elessair 0:f269e3021894 436 break;
elessair 0:f269e3021894 437 }
elessair 0:f269e3021894 438 }
elessair 0:f269e3021894 439
elessair 0:f269e3021894 440 void SAI_Deinit(I2S_Type *base)
elessair 0:f269e3021894 441 {
elessair 0:f269e3021894 442 SAI_TxEnable(base, false);
elessair 0:f269e3021894 443 SAI_RxEnable(base, false);
elessair 0:f269e3021894 444 CLOCK_DisableClock(s_saiClock[SAI_GetInstance(base)]);
elessair 0:f269e3021894 445 }
elessair 0:f269e3021894 446
elessair 0:f269e3021894 447 void SAI_TxGetDefaultConfig(sai_config_t *config)
elessair 0:f269e3021894 448 {
elessair 0:f269e3021894 449 config->bclkSource = kSAI_BclkSourceMclkDiv;
elessair 0:f269e3021894 450 config->masterSlave = kSAI_Master;
elessair 0:f269e3021894 451 config->mclkSource = kSAI_MclkSourceSysclk;
elessair 0:f269e3021894 452 config->protocol = kSAI_BusLeftJustified;
elessair 0:f269e3021894 453 config->syncMode = kSAI_ModeAsync;
elessair 0:f269e3021894 454 #if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
elessair 0:f269e3021894 455 config->mclkOutputEnable = true;
elessair 0:f269e3021894 456 #endif /* FSL_FEATURE_SAI_HAS_MCR */
elessair 0:f269e3021894 457 }
elessair 0:f269e3021894 458
elessair 0:f269e3021894 459 void SAI_RxGetDefaultConfig(sai_config_t *config)
elessair 0:f269e3021894 460 {
elessair 0:f269e3021894 461 config->bclkSource = kSAI_BclkSourceMclkDiv;
elessair 0:f269e3021894 462 config->masterSlave = kSAI_Master;
elessair 0:f269e3021894 463 config->mclkSource = kSAI_MclkSourceSysclk;
elessair 0:f269e3021894 464 config->protocol = kSAI_BusLeftJustified;
elessair 0:f269e3021894 465 config->syncMode = kSAI_ModeSync;
elessair 0:f269e3021894 466 #if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
elessair 0:f269e3021894 467 config->mclkOutputEnable = true;
elessair 0:f269e3021894 468 #endif /* FSL_FEATURE_SAI_HAS_MCR */
elessair 0:f269e3021894 469 }
elessair 0:f269e3021894 470
elessair 0:f269e3021894 471 void SAI_TxReset(I2S_Type *base)
elessair 0:f269e3021894 472 {
elessair 0:f269e3021894 473 /* Set the software reset and FIFO reset to clear internal state */
elessair 0:f269e3021894 474 base->TCSR = I2S_TCSR_SR_MASK | I2S_TCSR_FR_MASK;
elessair 0:f269e3021894 475
elessair 0:f269e3021894 476 /* Clear software reset bit, this should be done by software */
elessair 0:f269e3021894 477 base->TCSR &= ~I2S_TCSR_SR_MASK;
elessair 0:f269e3021894 478
elessair 0:f269e3021894 479 /* Reset all Tx register values */
elessair 0:f269e3021894 480 base->TCR2 = 0;
elessair 0:f269e3021894 481 base->TCR3 = 0;
elessair 0:f269e3021894 482 base->TCR4 = 0;
elessair 0:f269e3021894 483 base->TCR5 = 0;
elessair 0:f269e3021894 484 base->TMR = 0;
elessair 0:f269e3021894 485 }
elessair 0:f269e3021894 486
elessair 0:f269e3021894 487 void SAI_RxReset(I2S_Type *base)
elessair 0:f269e3021894 488 {
elessair 0:f269e3021894 489 /* Set the software reset and FIFO reset to clear internal state */
elessair 0:f269e3021894 490 base->RCSR = I2S_RCSR_SR_MASK | I2S_RCSR_FR_MASK;
elessair 0:f269e3021894 491
elessair 0:f269e3021894 492 /* Clear software reset bit, this should be done by software */
elessair 0:f269e3021894 493 base->RCSR &= ~I2S_RCSR_SR_MASK;
elessair 0:f269e3021894 494
elessair 0:f269e3021894 495 /* Reset all Rx register values */
elessair 0:f269e3021894 496 base->RCR2 = 0;
elessair 0:f269e3021894 497 base->RCR3 = 0;
elessair 0:f269e3021894 498 base->RCR4 = 0;
elessair 0:f269e3021894 499 base->RCR5 = 0;
elessair 0:f269e3021894 500 base->RMR = 0;
elessair 0:f269e3021894 501 }
elessair 0:f269e3021894 502
elessair 0:f269e3021894 503 void SAI_TxEnable(I2S_Type *base, bool enable)
elessair 0:f269e3021894 504 {
elessair 0:f269e3021894 505 if (enable)
elessair 0:f269e3021894 506 {
elessair 0:f269e3021894 507 /* If clock is sync with Rx, should enable RE bit. */
elessair 0:f269e3021894 508 if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) == 0x1U)
elessair 0:f269e3021894 509 {
elessair 0:f269e3021894 510 base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
elessair 0:f269e3021894 511 }
elessair 0:f269e3021894 512 base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
elessair 0:f269e3021894 513 }
elessair 0:f269e3021894 514 else
elessair 0:f269e3021894 515 {
elessair 0:f269e3021894 516 /* Should not close RE even sync with Rx */
elessair 0:f269e3021894 517 base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK));
elessair 0:f269e3021894 518 }
elessair 0:f269e3021894 519 }
elessair 0:f269e3021894 520
elessair 0:f269e3021894 521 void SAI_RxEnable(I2S_Type *base, bool enable)
elessair 0:f269e3021894 522 {
elessair 0:f269e3021894 523 if (enable)
elessair 0:f269e3021894 524 {
elessair 0:f269e3021894 525 /* If clock is sync with Tx, should enable TE bit. */
elessair 0:f269e3021894 526 if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) == 0x1U)
elessair 0:f269e3021894 527 {
elessair 0:f269e3021894 528 base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
elessair 0:f269e3021894 529 }
elessair 0:f269e3021894 530 base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
elessair 0:f269e3021894 531 }
elessair 0:f269e3021894 532 else
elessair 0:f269e3021894 533 {
elessair 0:f269e3021894 534 base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK));
elessair 0:f269e3021894 535 }
elessair 0:f269e3021894 536 }
elessair 0:f269e3021894 537
elessair 0:f269e3021894 538 void SAI_TxSetFormat(I2S_Type *base,
elessair 0:f269e3021894 539 sai_transfer_format_t *format,
elessair 0:f269e3021894 540 uint32_t mclkSourceClockHz,
elessair 0:f269e3021894 541 uint32_t bclkSourceClockHz)
elessair 0:f269e3021894 542 {
elessair 0:f269e3021894 543 uint32_t bclk = format->sampleRate_Hz * 32U * 2U;
elessair 0:f269e3021894 544
elessair 0:f269e3021894 545 /* Compute the mclk */
elessair 0:f269e3021894 546 #if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
elessair 0:f269e3021894 547 /* Check if master clock divider enabled, then set master clock divider */
elessair 0:f269e3021894 548 if (base->MCR & I2S_MCR_MOE_MASK)
elessair 0:f269e3021894 549 {
elessair 0:f269e3021894 550 SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
elessair 0:f269e3021894 551 }
elessair 0:f269e3021894 552 #endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
elessair 0:f269e3021894 553
elessair 0:f269e3021894 554 /* Set bclk if needed */
elessair 0:f269e3021894 555 if (base->TCR2 & I2S_TCR2_BCD_MASK)
elessair 0:f269e3021894 556 {
elessair 0:f269e3021894 557 base->TCR2 &= ~I2S_TCR2_DIV_MASK;
elessair 0:f269e3021894 558 base->TCR2 |= I2S_TCR2_DIV((bclkSourceClockHz / bclk) / 2U - 1U);
elessair 0:f269e3021894 559 }
elessair 0:f269e3021894 560
elessair 0:f269e3021894 561 /* Set bitWidth */
elessair 0:f269e3021894 562 if (format->protocol == kSAI_BusRightJustified)
elessair 0:f269e3021894 563 {
elessair 0:f269e3021894 564 base->TCR5 = I2S_TCR5_WNW(31U) | I2S_TCR5_W0W(31U) | I2S_TCR5_FBT(31U);
elessair 0:f269e3021894 565 }
elessair 0:f269e3021894 566 else
elessair 0:f269e3021894 567 {
elessair 0:f269e3021894 568 base->TCR5 = I2S_TCR5_WNW(31U) | I2S_TCR5_W0W(31U) | I2S_TCR5_FBT(format->bitWidth - 1);
elessair 0:f269e3021894 569 }
elessair 0:f269e3021894 570
elessair 0:f269e3021894 571 /* Set mono or stereo */
elessair 0:f269e3021894 572 base->TMR = (uint32_t)format->stereo;
elessair 0:f269e3021894 573
elessair 0:f269e3021894 574 /* Set data channel */
elessair 0:f269e3021894 575 base->TCR3 &= ~I2S_TCR3_TCE_MASK;
elessair 0:f269e3021894 576 base->TCR3 |= I2S_TCR3_TCE(1U << format->channel);
elessair 0:f269e3021894 577
elessair 0:f269e3021894 578 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 579 /* Set watermark */
elessair 0:f269e3021894 580 base->TCR1 = format->watermark;
elessair 0:f269e3021894 581 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 582 }
elessair 0:f269e3021894 583
elessair 0:f269e3021894 584 void SAI_RxSetFormat(I2S_Type *base,
elessair 0:f269e3021894 585 sai_transfer_format_t *format,
elessair 0:f269e3021894 586 uint32_t mclkSourceClockHz,
elessair 0:f269e3021894 587 uint32_t bclkSourceClockHz)
elessair 0:f269e3021894 588 {
elessair 0:f269e3021894 589 uint32_t bclk = format->sampleRate_Hz * 32U * 2U;
elessair 0:f269e3021894 590
elessair 0:f269e3021894 591 /* Compute the mclk */
elessair 0:f269e3021894 592 #if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
elessair 0:f269e3021894 593 /* Check if master clock divider enabled */
elessair 0:f269e3021894 594 if (base->MCR & I2S_MCR_MOE_MASK)
elessair 0:f269e3021894 595 {
elessair 0:f269e3021894 596 SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
elessair 0:f269e3021894 597 }
elessair 0:f269e3021894 598 #endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
elessair 0:f269e3021894 599
elessair 0:f269e3021894 600 /* Set bclk if needed */
elessair 0:f269e3021894 601 if (base->RCR2 & I2S_RCR2_BCD_MASK)
elessair 0:f269e3021894 602 {
elessair 0:f269e3021894 603 base->RCR2 &= ~I2S_RCR2_DIV_MASK;
elessair 0:f269e3021894 604 base->RCR2 |= I2S_RCR2_DIV((bclkSourceClockHz / bclk) / 2U - 1U);
elessair 0:f269e3021894 605 }
elessair 0:f269e3021894 606
elessair 0:f269e3021894 607 /* Set bitWidth */
elessair 0:f269e3021894 608 if (format->protocol == kSAI_BusRightJustified)
elessair 0:f269e3021894 609 {
elessair 0:f269e3021894 610 base->RCR5 = I2S_RCR5_WNW(31U) | I2S_RCR5_W0W(31U) | I2S_RCR5_FBT(31U);
elessair 0:f269e3021894 611 }
elessair 0:f269e3021894 612 else
elessair 0:f269e3021894 613 {
elessair 0:f269e3021894 614 base->RCR5 = I2S_RCR5_WNW(31U) | I2S_RCR5_W0W(31U) | I2S_RCR5_FBT(format->bitWidth - 1);
elessair 0:f269e3021894 615 }
elessair 0:f269e3021894 616
elessair 0:f269e3021894 617 /* Set mono or stereo */
elessair 0:f269e3021894 618 base->RMR = (uint32_t)format->stereo;
elessair 0:f269e3021894 619
elessair 0:f269e3021894 620 /* Set data channel */
elessair 0:f269e3021894 621 base->RCR3 &= ~I2S_RCR3_RCE_MASK;
elessair 0:f269e3021894 622 base->RCR3 |= I2S_RCR3_RCE(1U << format->channel);
elessair 0:f269e3021894 623
elessair 0:f269e3021894 624 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 625 /* Set watermark */
elessair 0:f269e3021894 626 base->RCR1 = format->watermark;
elessair 0:f269e3021894 627 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 628 }
elessair 0:f269e3021894 629
elessair 0:f269e3021894 630 void SAI_WriteBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
elessair 0:f269e3021894 631 {
elessair 0:f269e3021894 632 uint32_t i = 0;
elessair 0:f269e3021894 633 uint8_t bytesPerWord = bitWidth / 8U;
elessair 0:f269e3021894 634
elessair 0:f269e3021894 635 for (i = 0; i < size; i++)
elessair 0:f269e3021894 636 {
elessair 0:f269e3021894 637 /* Wait until it can write data */
elessair 0:f269e3021894 638 while (!(base->TCSR & I2S_TCSR_FWF_MASK))
elessair 0:f269e3021894 639 {
elessair 0:f269e3021894 640 }
elessair 0:f269e3021894 641
elessair 0:f269e3021894 642 SAI_WriteNonBlocking(base, channel, bitWidth, buffer, bytesPerWord);
elessair 0:f269e3021894 643 buffer += bytesPerWord;
elessair 0:f269e3021894 644 }
elessair 0:f269e3021894 645
elessair 0:f269e3021894 646 /* Wait until the last data is sent */
elessair 0:f269e3021894 647 while (!(base->TCSR & I2S_TCSR_FWF_MASK))
elessair 0:f269e3021894 648 {
elessair 0:f269e3021894 649 }
elessair 0:f269e3021894 650 }
elessair 0:f269e3021894 651
elessair 0:f269e3021894 652 void SAI_ReadBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
elessair 0:f269e3021894 653 {
elessair 0:f269e3021894 654 uint32_t i = 0;
elessair 0:f269e3021894 655 uint8_t bytesPerWord = bitWidth / 8U;
elessair 0:f269e3021894 656
elessair 0:f269e3021894 657 for (i = 0; i < size; i++)
elessair 0:f269e3021894 658 {
elessair 0:f269e3021894 659 /* Wait until data is received */
elessair 0:f269e3021894 660 while (!(base->RCSR & I2S_RCSR_FWF_MASK))
elessair 0:f269e3021894 661 {
elessair 0:f269e3021894 662 }
elessair 0:f269e3021894 663
elessair 0:f269e3021894 664 SAI_ReadNonBlocking(base, channel, bitWidth, buffer, bytesPerWord);
elessair 0:f269e3021894 665 buffer += bytesPerWord;
elessair 0:f269e3021894 666 }
elessair 0:f269e3021894 667 }
elessair 0:f269e3021894 668
elessair 0:f269e3021894 669 void SAI_TransferTxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
elessair 0:f269e3021894 670 {
elessair 0:f269e3021894 671 assert(handle);
elessair 0:f269e3021894 672
elessair 0:f269e3021894 673 s_saiHandle[SAI_GetInstance(base)][0] = handle;
elessair 0:f269e3021894 674
elessair 0:f269e3021894 675 handle->callback = callback;
elessair 0:f269e3021894 676 handle->userData = userData;
elessair 0:f269e3021894 677
elessair 0:f269e3021894 678 /* Set the isr pointer */
elessair 0:f269e3021894 679 s_saiTxIsr = SAI_TransferTxHandleIRQ;
elessair 0:f269e3021894 680
elessair 0:f269e3021894 681 /* Enable Tx irq */
elessair 0:f269e3021894 682 EnableIRQ(s_saiTxIRQ[SAI_GetInstance(base)]);
elessair 0:f269e3021894 683 }
elessair 0:f269e3021894 684
elessair 0:f269e3021894 685 void SAI_TransferRxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
elessair 0:f269e3021894 686 {
elessair 0:f269e3021894 687 assert(handle);
elessair 0:f269e3021894 688
elessair 0:f269e3021894 689 s_saiHandle[SAI_GetInstance(base)][1] = handle;
elessair 0:f269e3021894 690
elessair 0:f269e3021894 691 handle->callback = callback;
elessair 0:f269e3021894 692 handle->userData = userData;
elessair 0:f269e3021894 693
elessair 0:f269e3021894 694 /* Set the isr pointer */
elessair 0:f269e3021894 695 s_saiRxIsr = SAI_TransferRxHandleIRQ;
elessair 0:f269e3021894 696
elessair 0:f269e3021894 697 /* Enable Rx irq */
elessair 0:f269e3021894 698 EnableIRQ(s_saiRxIRQ[SAI_GetInstance(base)]);
elessair 0:f269e3021894 699 }
elessair 0:f269e3021894 700
elessair 0:f269e3021894 701 status_t SAI_TransferTxSetFormat(I2S_Type *base,
elessair 0:f269e3021894 702 sai_handle_t *handle,
elessair 0:f269e3021894 703 sai_transfer_format_t *format,
elessair 0:f269e3021894 704 uint32_t mclkSourceClockHz,
elessair 0:f269e3021894 705 uint32_t bclkSourceClockHz)
elessair 0:f269e3021894 706 {
elessair 0:f269e3021894 707 assert(handle);
elessair 0:f269e3021894 708
elessair 0:f269e3021894 709 if ((mclkSourceClockHz < format->sampleRate_Hz) || (bclkSourceClockHz < format->sampleRate_Hz))
elessair 0:f269e3021894 710 {
elessair 0:f269e3021894 711 return kStatus_InvalidArgument;
elessair 0:f269e3021894 712 }
elessair 0:f269e3021894 713
elessair 0:f269e3021894 714 /* Copy format to handle */
elessair 0:f269e3021894 715 handle->bitWidth = format->bitWidth;
elessair 0:f269e3021894 716 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 717 handle->watermark = format->watermark;
elessair 0:f269e3021894 718 #endif
elessair 0:f269e3021894 719 handle->channel = format->channel;
elessair 0:f269e3021894 720
elessair 0:f269e3021894 721 SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
elessair 0:f269e3021894 722
elessair 0:f269e3021894 723 return kStatus_Success;
elessair 0:f269e3021894 724 }
elessair 0:f269e3021894 725
elessair 0:f269e3021894 726 status_t SAI_TransferRxSetFormat(I2S_Type *base,
elessair 0:f269e3021894 727 sai_handle_t *handle,
elessair 0:f269e3021894 728 sai_transfer_format_t *format,
elessair 0:f269e3021894 729 uint32_t mclkSourceClockHz,
elessair 0:f269e3021894 730 uint32_t bclkSourceClockHz)
elessair 0:f269e3021894 731 {
elessair 0:f269e3021894 732 assert(handle);
elessair 0:f269e3021894 733
elessair 0:f269e3021894 734 if ((mclkSourceClockHz < format->sampleRate_Hz) || (bclkSourceClockHz < format->sampleRate_Hz))
elessair 0:f269e3021894 735 {
elessair 0:f269e3021894 736 return kStatus_InvalidArgument;
elessair 0:f269e3021894 737 }
elessair 0:f269e3021894 738
elessair 0:f269e3021894 739 /* Copy format to handle */
elessair 0:f269e3021894 740 handle->bitWidth = format->bitWidth;
elessair 0:f269e3021894 741 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 742 handle->watermark = format->watermark;
elessair 0:f269e3021894 743 #endif
elessair 0:f269e3021894 744 handle->channel = format->channel;
elessair 0:f269e3021894 745
elessair 0:f269e3021894 746 SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
elessair 0:f269e3021894 747
elessair 0:f269e3021894 748 return kStatus_Success;
elessair 0:f269e3021894 749 }
elessair 0:f269e3021894 750
elessair 0:f269e3021894 751 status_t SAI_TransferSendNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
elessair 0:f269e3021894 752 {
elessair 0:f269e3021894 753 assert(handle);
elessair 0:f269e3021894 754
elessair 0:f269e3021894 755 /* Check if the queue is full */
elessair 0:f269e3021894 756 if (handle->saiQueue[handle->queueUser].data)
elessair 0:f269e3021894 757 {
elessair 0:f269e3021894 758 return kStatus_SAI_QueueFull;
elessair 0:f269e3021894 759 }
elessair 0:f269e3021894 760
elessair 0:f269e3021894 761 /* Add into queue */
elessair 0:f269e3021894 762 handle->transferSize[handle->queueUser] = xfer->dataSize;
elessair 0:f269e3021894 763 handle->saiQueue[handle->queueUser].data = xfer->data;
elessair 0:f269e3021894 764 handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
elessair 0:f269e3021894 765 handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
elessair 0:f269e3021894 766
elessair 0:f269e3021894 767 /* Set the state to busy */
elessair 0:f269e3021894 768 handle->state = kSAI_Busy;
elessair 0:f269e3021894 769
elessair 0:f269e3021894 770 /* Enable interrupt */
elessair 0:f269e3021894 771 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 772 /* Use FIFO request interrupt and fifo error*/
elessair 0:f269e3021894 773 SAI_TxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
elessair 0:f269e3021894 774 #else
elessair 0:f269e3021894 775 SAI_TxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
elessair 0:f269e3021894 776 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 777
elessair 0:f269e3021894 778 /* Enable Tx transfer */
elessair 0:f269e3021894 779 SAI_TxEnable(base, true);
elessair 0:f269e3021894 780
elessair 0:f269e3021894 781 return kStatus_Success;
elessair 0:f269e3021894 782 }
elessair 0:f269e3021894 783
elessair 0:f269e3021894 784 status_t SAI_TransferReceiveNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
elessair 0:f269e3021894 785 {
elessair 0:f269e3021894 786 assert(handle);
elessair 0:f269e3021894 787
elessair 0:f269e3021894 788 /* Check if the queue is full */
elessair 0:f269e3021894 789 if (handle->saiQueue[handle->queueUser].data)
elessair 0:f269e3021894 790 {
elessair 0:f269e3021894 791 return kStatus_SAI_QueueFull;
elessair 0:f269e3021894 792 }
elessair 0:f269e3021894 793
elessair 0:f269e3021894 794 /* Add into queue */
elessair 0:f269e3021894 795 handle->transferSize[handle->queueUser] = xfer->dataSize;
elessair 0:f269e3021894 796 handle->saiQueue[handle->queueUser].data = xfer->data;
elessair 0:f269e3021894 797 handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
elessair 0:f269e3021894 798 handle->queueUser = (handle->queueUser + 1) % SAI_XFER_QUEUE_SIZE;
elessair 0:f269e3021894 799
elessair 0:f269e3021894 800 /* Set state to busy */
elessair 0:f269e3021894 801 handle->state = kSAI_Busy;
elessair 0:f269e3021894 802
elessair 0:f269e3021894 803 /* Enable interrupt */
elessair 0:f269e3021894 804 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 805 /* Use FIFO request interrupt and fifo error*/
elessair 0:f269e3021894 806 SAI_RxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
elessair 0:f269e3021894 807 #else
elessair 0:f269e3021894 808 SAI_RxEnableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
elessair 0:f269e3021894 809 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 810
elessair 0:f269e3021894 811 /* Enable Rx transfer */
elessair 0:f269e3021894 812 SAI_RxEnable(base, true);
elessair 0:f269e3021894 813
elessair 0:f269e3021894 814 return kStatus_Success;
elessair 0:f269e3021894 815 }
elessair 0:f269e3021894 816
elessair 0:f269e3021894 817 status_t SAI_TransferGetSendCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
elessair 0:f269e3021894 818 {
elessair 0:f269e3021894 819 assert(handle);
elessair 0:f269e3021894 820
elessair 0:f269e3021894 821 status_t status = kStatus_Success;
elessair 0:f269e3021894 822
elessair 0:f269e3021894 823 if (handle->state != kSAI_Busy)
elessair 0:f269e3021894 824 {
elessair 0:f269e3021894 825 status = kStatus_NoTransferInProgress;
elessair 0:f269e3021894 826 }
elessair 0:f269e3021894 827 else
elessair 0:f269e3021894 828 {
elessair 0:f269e3021894 829 *count = (handle->transferSize[handle->queueDriver] - handle->saiQueue[handle->queueDriver].dataSize);
elessair 0:f269e3021894 830 }
elessair 0:f269e3021894 831
elessair 0:f269e3021894 832 return status;
elessair 0:f269e3021894 833 }
elessair 0:f269e3021894 834
elessair 0:f269e3021894 835 status_t SAI_TransferGetReceiveCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
elessair 0:f269e3021894 836 {
elessair 0:f269e3021894 837 assert(handle);
elessair 0:f269e3021894 838
elessair 0:f269e3021894 839 status_t status = kStatus_Success;
elessair 0:f269e3021894 840
elessair 0:f269e3021894 841 if (handle->state != kSAI_Busy)
elessair 0:f269e3021894 842 {
elessair 0:f269e3021894 843 status = kStatus_NoTransferInProgress;
elessair 0:f269e3021894 844 }
elessair 0:f269e3021894 845 else
elessair 0:f269e3021894 846 {
elessair 0:f269e3021894 847 *count = (handle->transferSize[handle->queueDriver] - handle->saiQueue[handle->queueDriver].dataSize);
elessair 0:f269e3021894 848 }
elessair 0:f269e3021894 849
elessair 0:f269e3021894 850 return status;
elessair 0:f269e3021894 851 }
elessair 0:f269e3021894 852
elessair 0:f269e3021894 853 void SAI_TransferAbortSend(I2S_Type *base, sai_handle_t *handle)
elessair 0:f269e3021894 854 {
elessair 0:f269e3021894 855 assert(handle);
elessair 0:f269e3021894 856
elessair 0:f269e3021894 857 /* Stop Tx transfer and disable interrupt */
elessair 0:f269e3021894 858 SAI_TxEnable(base, false);
elessair 0:f269e3021894 859 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 860 /* Use FIFO request interrupt and fifo error */
elessair 0:f269e3021894 861 SAI_TxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
elessair 0:f269e3021894 862 #else
elessair 0:f269e3021894 863 SAI_TxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
elessair 0:f269e3021894 864 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 865
elessair 0:f269e3021894 866 handle->state = kSAI_Idle;
elessair 0:f269e3021894 867
elessair 0:f269e3021894 868 /* Clear the queue */
elessair 0:f269e3021894 869 memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * SAI_XFER_QUEUE_SIZE);
elessair 0:f269e3021894 870 handle->queueDriver = 0;
elessair 0:f269e3021894 871 handle->queueUser = 0;
elessair 0:f269e3021894 872 }
elessair 0:f269e3021894 873
elessair 0:f269e3021894 874 void SAI_TransferAbortReceive(I2S_Type *base, sai_handle_t *handle)
elessair 0:f269e3021894 875 {
elessair 0:f269e3021894 876 assert(handle);
elessair 0:f269e3021894 877
elessair 0:f269e3021894 878 /* Stop Tx transfer and disable interrupt */
elessair 0:f269e3021894 879 SAI_RxEnable(base, false);
elessair 0:f269e3021894 880 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 881 /* Use FIFO request interrupt and fifo error */
elessair 0:f269e3021894 882 SAI_RxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFORequestInterruptEnable);
elessair 0:f269e3021894 883 #else
elessair 0:f269e3021894 884 SAI_RxDisableInterrupts(base, kSAI_FIFOErrorInterruptEnable | kSAI_FIFOWarningInterruptEnable);
elessair 0:f269e3021894 885 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 886
elessair 0:f269e3021894 887 handle->state = kSAI_Idle;
elessair 0:f269e3021894 888
elessair 0:f269e3021894 889 /* Clear the queue */
elessair 0:f269e3021894 890 memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * SAI_XFER_QUEUE_SIZE);
elessair 0:f269e3021894 891 handle->queueDriver = 0;
elessair 0:f269e3021894 892 handle->queueUser = 0;
elessair 0:f269e3021894 893 }
elessair 0:f269e3021894 894
elessair 0:f269e3021894 895 void SAI_TransferTxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
elessair 0:f269e3021894 896 {
elessair 0:f269e3021894 897 assert(handle);
elessair 0:f269e3021894 898
elessair 0:f269e3021894 899 uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
elessair 0:f269e3021894 900 uint8_t dataSize = handle->bitWidth / 8U;
elessair 0:f269e3021894 901
elessair 0:f269e3021894 902 /* Handle Error */
elessair 0:f269e3021894 903 if (base->TCSR & I2S_TCSR_FEF_MASK)
elessair 0:f269e3021894 904 {
elessair 0:f269e3021894 905 /* Clear FIFO error flag to continue transfer */
elessair 0:f269e3021894 906 SAI_TxClearStatusFlags(base, kSAI_FIFOErrorFlag);
elessair 0:f269e3021894 907
elessair 0:f269e3021894 908 /* Call the callback */
elessair 0:f269e3021894 909 if (handle->callback)
elessair 0:f269e3021894 910 {
elessair 0:f269e3021894 911 (handle->callback)(base, handle, kStatus_SAI_TxError, handle->userData);
elessair 0:f269e3021894 912 }
elessair 0:f269e3021894 913 }
elessair 0:f269e3021894 914
elessair 0:f269e3021894 915 /* Handle transfer */
elessair 0:f269e3021894 916 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 917 if (base->TCSR & I2S_TCSR_FRF_MASK)
elessair 0:f269e3021894 918 {
elessair 0:f269e3021894 919 /* Judge if the data need to transmit is less than space */
elessair 0:f269e3021894 920 uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize),
elessair 0:f269e3021894 921 (size_t)((FSL_FEATURE_SAI_FIFO_COUNT - handle->watermark) * dataSize));
elessair 0:f269e3021894 922
elessair 0:f269e3021894 923 /* Copy the data from sai buffer to FIFO */
elessair 0:f269e3021894 924 SAI_WriteNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
elessair 0:f269e3021894 925
elessair 0:f269e3021894 926 /* Update the internal counter */
elessair 0:f269e3021894 927 handle->saiQueue[handle->queueDriver].dataSize -= size;
elessair 0:f269e3021894 928 handle->saiQueue[handle->queueDriver].data += size;
elessair 0:f269e3021894 929 }
elessair 0:f269e3021894 930 #else
elessair 0:f269e3021894 931 if (base->TCSR & I2S_TCSR_FWF_MASK)
elessair 0:f269e3021894 932 {
elessair 0:f269e3021894 933 uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
elessair 0:f269e3021894 934
elessair 0:f269e3021894 935 SAI_WriteNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
elessair 0:f269e3021894 936
elessair 0:f269e3021894 937 /* Update internal counter */
elessair 0:f269e3021894 938 handle->saiQueue[handle->queueDriver].dataSize -= size;
elessair 0:f269e3021894 939 handle->saiQueue[handle->queueDriver].data += size;
elessair 0:f269e3021894 940 }
elessair 0:f269e3021894 941 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 942
elessair 0:f269e3021894 943 /* If finished a blcok, call the callback function */
elessair 0:f269e3021894 944 if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
elessair 0:f269e3021894 945 {
elessair 0:f269e3021894 946 memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
elessair 0:f269e3021894 947 handle->queueDriver = (handle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
elessair 0:f269e3021894 948 if (handle->callback)
elessair 0:f269e3021894 949 {
elessair 0:f269e3021894 950 (handle->callback)(base, handle, kStatus_SAI_TxIdle, handle->userData);
elessair 0:f269e3021894 951 }
elessair 0:f269e3021894 952 }
elessair 0:f269e3021894 953
elessair 0:f269e3021894 954 /* If all data finished, just stop the transfer */
elessair 0:f269e3021894 955 if (handle->saiQueue[handle->queueDriver].data == NULL)
elessair 0:f269e3021894 956 {
elessair 0:f269e3021894 957 SAI_TransferAbortSend(base, handle);
elessair 0:f269e3021894 958 }
elessair 0:f269e3021894 959 }
elessair 0:f269e3021894 960
elessair 0:f269e3021894 961 void SAI_TransferRxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
elessair 0:f269e3021894 962 {
elessair 0:f269e3021894 963 assert(handle);
elessair 0:f269e3021894 964
elessair 0:f269e3021894 965 uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
elessair 0:f269e3021894 966 uint8_t dataSize = handle->bitWidth / 8U;
elessair 0:f269e3021894 967
elessair 0:f269e3021894 968 /* Handle Error */
elessair 0:f269e3021894 969 if (base->RCSR & I2S_RCSR_FEF_MASK)
elessair 0:f269e3021894 970 {
elessair 0:f269e3021894 971 /* Clear FIFO error flag to continue transfer */
elessair 0:f269e3021894 972 SAI_RxClearStatusFlags(base, kSAI_FIFOErrorFlag);
elessair 0:f269e3021894 973
elessair 0:f269e3021894 974 /* Call the callback */
elessair 0:f269e3021894 975 if (handle->callback)
elessair 0:f269e3021894 976 {
elessair 0:f269e3021894 977 (handle->callback)(base, handle, kStatus_SAI_RxError, handle->userData);
elessair 0:f269e3021894 978 }
elessair 0:f269e3021894 979 }
elessair 0:f269e3021894 980
elessair 0:f269e3021894 981 /* Handle transfer */
elessair 0:f269e3021894 982 #if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
elessair 0:f269e3021894 983 if (base->RCSR & I2S_RCSR_FRF_MASK)
elessair 0:f269e3021894 984 {
elessair 0:f269e3021894 985 /* Judge if the data need to transmit is less than space */
elessair 0:f269e3021894 986 uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), (handle->watermark * dataSize));
elessair 0:f269e3021894 987
elessair 0:f269e3021894 988 /* Copy the data from sai buffer to FIFO */
elessair 0:f269e3021894 989 SAI_ReadNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
elessair 0:f269e3021894 990
elessair 0:f269e3021894 991 /* Update the internal counter */
elessair 0:f269e3021894 992 handle->saiQueue[handle->queueDriver].dataSize -= size;
elessair 0:f269e3021894 993 handle->saiQueue[handle->queueDriver].data += size;
elessair 0:f269e3021894 994 }
elessair 0:f269e3021894 995 #else
elessair 0:f269e3021894 996 if (base->RCSR & I2S_RCSR_FWF_MASK)
elessair 0:f269e3021894 997 {
elessair 0:f269e3021894 998 uint8_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
elessair 0:f269e3021894 999
elessair 0:f269e3021894 1000 SAI_ReadNonBlocking(base, handle->channel, handle->bitWidth, buffer, size);
elessair 0:f269e3021894 1001
elessair 0:f269e3021894 1002 /* Update internal state */
elessair 0:f269e3021894 1003 handle->saiQueue[handle->queueDriver].dataSize -= size;
elessair 0:f269e3021894 1004 handle->saiQueue[handle->queueDriver].data += size;
elessair 0:f269e3021894 1005 }
elessair 0:f269e3021894 1006 #endif /* FSL_FEATURE_SAI_FIFO_COUNT */
elessair 0:f269e3021894 1007
elessair 0:f269e3021894 1008 /* If finished a blcok, call the callback function */
elessair 0:f269e3021894 1009 if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
elessair 0:f269e3021894 1010 {
elessair 0:f269e3021894 1011 memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
elessair 0:f269e3021894 1012 handle->queueDriver = (handle->queueDriver + 1) % SAI_XFER_QUEUE_SIZE;
elessair 0:f269e3021894 1013 if (handle->callback)
elessair 0:f269e3021894 1014 {
elessair 0:f269e3021894 1015 (handle->callback)(base, handle, kStatus_SAI_RxIdle, handle->userData);
elessair 0:f269e3021894 1016 }
elessair 0:f269e3021894 1017 }
elessair 0:f269e3021894 1018
elessair 0:f269e3021894 1019 /* If all data finished, just stop the transfer */
elessair 0:f269e3021894 1020 if (handle->saiQueue[handle->queueDriver].data == NULL)
elessair 0:f269e3021894 1021 {
elessair 0:f269e3021894 1022 SAI_TransferAbortReceive(base, handle);
elessair 0:f269e3021894 1023 }
elessair 0:f269e3021894 1024 }
elessair 0:f269e3021894 1025
elessair 0:f269e3021894 1026 #if defined(I2S0)
elessair 0:f269e3021894 1027 #if defined(FSL_FEATURE_SAI_INT_SOURCE_NUM) && (FSL_FEATURE_SAI_INT_SOURCE_NUM == 1)
elessair 0:f269e3021894 1028 void I2S0_DriverIRQHandler(void)
elessair 0:f269e3021894 1029 {
elessair 0:f269e3021894 1030 if ((s_saiHandle[0][1]) && ((I2S0->RCSR & kSAI_FIFOWarningFlag) || (I2S0->RCSR & kSAI_FIFOErrorFlag)))
elessair 0:f269e3021894 1031 {
elessair 0:f269e3021894 1032 s_saiRxIsr(I2S0, s_saiHandle[0][1]);
elessair 0:f269e3021894 1033 }
elessair 0:f269e3021894 1034 if ((s_saiHandle[0][0]) && ((I2S0->TCSR & kSAI_FIFOWarningFlag) || (I2S0->TCSR & kSAI_FIFOErrorFlag)))
elessair 0:f269e3021894 1035 {
elessair 0:f269e3021894 1036 s_saiTxIsr(I2S0, s_saiHandle[0][0]);
elessair 0:f269e3021894 1037 }
elessair 0:f269e3021894 1038 }
elessair 0:f269e3021894 1039 #else
elessair 0:f269e3021894 1040 void I2S0_Tx_DriverIRQHandler(void)
elessair 0:f269e3021894 1041 {
elessair 0:f269e3021894 1042 assert(s_saiHandle[0][0]);
elessair 0:f269e3021894 1043 s_saiTxIsr(I2S0, s_saiHandle[0][0]);
elessair 0:f269e3021894 1044 }
elessair 0:f269e3021894 1045
elessair 0:f269e3021894 1046 void I2S0_Rx_DriverIRQHandler(void)
elessair 0:f269e3021894 1047 {
elessair 0:f269e3021894 1048 assert(s_saiHandle[0][1]);
elessair 0:f269e3021894 1049 s_saiRxIsr(I2S0, s_saiHandle[0][1]);
elessair 0:f269e3021894 1050 }
elessair 0:f269e3021894 1051 #endif /* FSL_FEATURE_SAI_INT_SOURCE_NUM */
elessair 0:f269e3021894 1052 #endif /* I2S0*/
elessair 0:f269e3021894 1053
elessair 0:f269e3021894 1054 #if defined(I2S1)
elessair 0:f269e3021894 1055 void I2S1_Tx_DriverIRQHandler(void)
elessair 0:f269e3021894 1056 {
elessair 0:f269e3021894 1057 assert(s_saiHandle[1][0]);
elessair 0:f269e3021894 1058 s_saiTxIsr(I2S1, s_saiHandle[1][0]);
elessair 0:f269e3021894 1059 }
elessair 0:f269e3021894 1060
elessair 0:f269e3021894 1061 void I2S1_Rx_DriverIRQHandler(void)
elessair 0:f269e3021894 1062 {
elessair 0:f269e3021894 1063 assert(s_saiHandle[1][1]);
elessair 0:f269e3021894 1064 s_saiRxIsr(I2S1, s_saiHandle[1][1]);
elessair 0:f269e3021894 1065 }
elessair 0:f269e3021894 1066 #endif