/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * o Neither the name of Freescale Semiconductor, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "fsl_spi.h" /******************************************************************************* * Definitons ******************************************************************************/ /*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */ enum _spi_transfer_states_t { kSPI_Idle = 0x0, /*!< SPI is idle state */ kSPI_Busy /*!< SPI is busy tranferring data. */ }; /*! @brief Typedef for spi master interrupt handler. spi master and slave handle is the same. */ typedef void (*spi_isr_t)(SPI_Type *base, spi_master_handle_t *spiHandle); /******************************************************************************* * Prototypes ******************************************************************************/ /*! * @brief Get the instance for SPI module. * * @param base SPI base address */ uint32_t SPI_GetInstance(SPI_Type *base); /*! * @brief Sends a buffer of data bytes in non-blocking way. * * @param base SPI base pointer * @param buffer The data bytes to send * @param size The number of data bytes to send */ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); /*! * @brief Receive a buffer of data bytes in non-blocking way. * * @param base SPI base pointer * @param buffer The data bytes to send * @param size The number of data bytes to send */ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); /*! * @brief Send a piece of data for SPI. * * This function computes the number of data to be written into D register or Tx FIFO, * and write the data into it. At the same time, this function updates the values in * master handle structure. * * @param handle Pointer to SPI master handle structure. */ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle); /*! * @brief Receive a piece of data for SPI master. * * This function computes the number of data to receive from D register or Rx FIFO, * and write the data to destination address. At the same time, this function updates * the values in master handle structure. * * @param handle Pointer to SPI master handle structure. */ static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle); /******************************************************************************* * Variables ******************************************************************************/ /*! @brief SPI internal handle pointer array */ static spi_master_handle_t *s_spiHandle[FSL_FEATURE_SOC_SPI_COUNT]; /*! @brief Base pointer array */ static SPI_Type *const s_spiBases[] = SPI_BASE_PTRS; /*! @brief IRQ name array */ static const IRQn_Type s_spiIRQ[] = SPI_IRQS; /*! @brief Clock array name */ static const clock_ip_name_t s_spiClock[] = SPI_CLOCKS; /*! @brief Pointer to master IRQ handler for each instance. */ static spi_isr_t s_spiIsr; /******************************************************************************* * Code ******************************************************************************/ uint32_t SPI_GetInstance(SPI_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ for (instance = 0; instance < FSL_FEATURE_SOC_SPI_COUNT; instance++) { if (s_spiBases[instance] == base) { break; } } assert(instance < FSL_FEATURE_SOC_SPI_COUNT); return instance; } static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /* Check if 16 bits or 8 bits */ bytesPerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #endif while (i < size) { if (buffer != NULL) { #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /*16 bit mode*/ if (base->C2 & SPI_C2_SPIMODE_MASK) { base->DL = *buffer++; base->DH = *buffer++; } /* 8 bit mode */ else { base->DL = *buffer++; } #else base->D = *buffer++; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ } /* Send dummy data */ else { SPI_WriteData(base, SPI_DUMMYDATA); } i += bytesPerFrame; } } static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /* Check if 16 bits or 8 bits */ bytesPerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #endif while (i < size) { if (buffer != NULL) { #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /*16 bit mode*/ if (base->C2 & SPI_C2_SPIMODE_MASK) { *buffer++ = base->DL; *buffer++ = base->DH; } /* 8 bit mode */ else { *buffer++ = base->DL; } #else *buffer++ = base->D; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ } else { SPI_ReadData(base); } i += bytesPerFrame; } } static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) { uint8_t bytes = MIN((handle->watermark * 2U), handle->txRemainingBytes); /* Read S register and ensure SPTEF is 1, otherwise the write would be ignored. */ if (handle->watermark == 1U) { if (bytes != 0U) { bytes = handle->bytePerFrame; } /* Send data */ if (base->C1 & SPI_C1_MSTR_MASK) { /* As a master, only write once */ if (base->S & SPI_S_SPTEF_MASK) { SPI_WriteNonBlocking(base, handle->txData, bytes); /* Update handle information */ if (handle->txData) { handle->txData += bytes; } handle->txRemainingBytes -= bytes; } } else { /* As a slave, send data until SPTEF cleared */ while ((base->S & SPI_S_SPTEF_MASK) && (handle->txRemainingBytes > 0)) { SPI_WriteNonBlocking(base, handle->txData, bytes); /* Update handle information */ if (handle->txData) { handle->txData += bytes; } handle->txRemainingBytes -= bytes; } } } #if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO) /* If use FIFO */ else { if (base->S & SPI_S_TNEAREF_MASK) { SPI_WriteNonBlocking(base, handle->txData, bytes); /* Update handle information */ if (handle->txData) { handle->txData += bytes; } handle->txRemainingBytes -= bytes; } } #endif } static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle) { uint8_t bytes = MIN((handle->watermark * 2U), handle->rxRemainingBytes); uint8_t val = 1U; /* Read S register and ensure SPRF is 1, otherwise the write would be ignored. */ if (handle->watermark == 1U) { val = base->S & SPI_S_SPRF_MASK; if (bytes != 0U) { bytes = handle->bytePerFrame; } } if (val) { SPI_ReadNonBlocking(base, handle->rxData, bytes); /* Update information in handle */ if (handle->rxData) { handle->rxData += bytes; } handle->rxRemainingBytes -= bytes; } } void SPI_MasterGetDefaultConfig(spi_master_config_t *config) { config->enableMaster = true; config->enableStopInWaitMode = false; config->polarity = kSPI_ClockPolarityActiveHigh; config->phase = kSPI_ClockPhaseFirstEdge; config->direction = kSPI_MsbFirst; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS config->dataMode = kSPI_8BitMode; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO config->txWatermark = kSPI_TxFifoOneHalfEmpty; config->rxWatermark = kSPI_RxFifoOneHalfFull; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ config->pinMode = kSPI_PinModeNormal; config->outputMode = kSPI_SlaveSelectAutomaticOutput; config->baudRate_Bps = 500000U; } void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz) { assert(config && srcClock_Hz); /* Open clock gate for SPI and open interrupt */ CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]); /* Disable SPI before configuration */ base->C1 &= ~SPI_C1_SPE_MASK; /* Configure clock polarity and phase, set SPI to master */ base->C1 = SPI_C1_MSTR(1U) | SPI_C1_CPOL(config->polarity) | SPI_C1_CPHA(config->phase) | SPI_C1_SSOE(config->outputMode & 1U) | SPI_C1_LSBFE(config->direction); /* Set data mode, and also pin mode and mode fault settings */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS base->C2 = SPI_C2_MODFEN(config->outputMode >> 1U) | SPI_C2_BIDIROE(config->pinMode >> 1U) | SPI_C2_SPISWAI(config->enableStopInWaitMode) | SPI_C2_SPC0(config->pinMode & 1U) | SPI_C2_SPIMODE(config->dataMode); #else base->C2 = SPI_C2_MODFEN(config->outputMode >> 1U) | SPI_C2_BIDIROE(config->pinMode >> 1U) | SPI_C2_SPISWAI(config->enableStopInWaitMode) | SPI_C2_SPC0(config->pinMode & 1U); #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ /* Set watermark, FIFO is enabled */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) { base->C3 = SPI_C3_TNEAREF_MARK(config->txWatermark) | SPI_C3_RNFULLF_MARK(config->rxWatermark) | SPI_C3_INTCLR(0U) | SPI_C3_FIFOMODE(1U); } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ /* Set baud rate */ SPI_MasterSetBaudRate(base, config->baudRate_Bps, srcClock_Hz); /* Enable SPI */ if (config->enableMaster) { base->C1 |= SPI_C1_SPE_MASK; } } void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config) { config->enableSlave = true; config->polarity = kSPI_ClockPolarityActiveHigh; config->phase = kSPI_ClockPhaseFirstEdge; config->direction = kSPI_MsbFirst; config->enableStopInWaitMode = false; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS config->dataMode = kSPI_8BitMode; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO config->txWatermark = kSPI_TxFifoOneHalfEmpty; config->rxWatermark = kSPI_RxFifoOneHalfFull; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) { assert(config); /* Open clock gate for SPI and open interrupt */ CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]); /* Disable SPI before configuration */ base->C1 &= ~SPI_C1_SPE_MASK; /* Configure master and clock polarity and phase */ base->C1 = SPI_C1_MSTR(0U) | SPI_C1_CPOL(config->polarity) | SPI_C1_CPHA(config->phase) | SPI_C1_LSBFE(config->direction); /* Configure data mode if needed */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS base->C2 = SPI_C2_SPIMODE(config->dataMode) | SPI_C2_SPISWAI(config->enableStopInWaitMode); #else base->C2 = SPI_C2_SPISWAI(config->enableStopInWaitMode); #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ /* Set watermark */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0U) { base->C3 = SPI_C3_TNEAREF_MARK(config->txWatermark) | SPI_C3_RNFULLF_MARK(config->rxWatermark) | SPI_C3_INTCLR(0U) | SPI_C3_FIFOMODE(1U); } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ /* Enable SPI */ if (config->enableSlave) { base->C1 |= SPI_C1_SPE_MASK; } } void SPI_Deinit(SPI_Type *base) { /* Disable SPI module before shutting down */ base->C1 &= ~SPI_C1_SPE_MASK; /* Gate the clock */ CLOCK_DisableClock(s_spiClock[SPI_GetInstance(base)]); } uint32_t SPI_GetStatusFlags(SPI_Type *base) { #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) { return ((base->S) | (((uint32_t)base->CI) << 8U)); } else { return (base->S); } #else return (base->S); #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } void SPI_EnableInterrupts(SPI_Type *base, uint32_t mask) { /* Rx full interrupt */ if (mask & kSPI_RxFullAndModfInterruptEnable) { base->C1 |= SPI_C1_SPIE_MASK; } /* Tx empty interrupt */ if (mask & kSPI_TxEmptyInterruptEnable) { base->C1 |= SPI_C1_SPTIE_MASK; } /* Data match interrupt */ if (mask & kSPI_MatchInterruptEnable) { base->C2 |= SPI_C2_SPMIE_MASK; } /* FIFO related interrupts */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) { /* Rx FIFO near full interrupt */ if (mask & kSPI_RxFifoNearFullInterruptEnable) { base->C3 |= SPI_C3_RNFULLIEN_MASK; } /* Tx FIFO near empty interrupt */ if (mask & kSPI_TxFifoNearEmptyInterruptEnable) { base->C3 |= SPI_C3_TNEARIEN_MASK; } } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } void SPI_DisableInterrupts(SPI_Type *base, uint32_t mask) { /* Rx full interrupt */ if (mask & kSPI_RxFullAndModfInterruptEnable) { base->C1 &= (~SPI_C1_SPIE_MASK); } /* Tx empty interrupt */ if (mask & kSPI_TxEmptyInterruptEnable) { base->C1 &= (~SPI_C1_SPTIE_MASK); } /* Data match interrupt */ if (mask & kSPI_MatchInterruptEnable) { base->C2 &= (~SPI_C2_SPMIE_MASK); } #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) { /* Rx FIFO near full interrupt */ if (mask & kSPI_RxFifoNearFullInterruptEnable) { base->C3 &= ~SPI_C3_RNFULLIEN_MASK; } /* Tx FIFO near empty interrupt */ if (mask & kSPI_TxFifoNearEmptyInterruptEnable) { base->C3 &= ~SPI_C3_TNEARIEN_MASK; } } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) { uint32_t prescaler; uint32_t bestPrescaler; uint32_t rateDivisor; uint32_t bestDivisor; uint32_t rateDivisorValue; uint32_t realBaudrate; uint32_t diff; uint32_t min_diff; uint32_t freq = baudRate_Bps; /* Find combination of prescaler and scaler resulting in baudrate closest to the requested value */ min_diff = 0xFFFFFFFFU; /* Set the maximum divisor bit settings for each of the following divisors */ bestPrescaler = 7U; bestDivisor = 8U; /* In all for loops, if min_diff = 0, the exit for loop*/ for (prescaler = 0; (prescaler <= 7) && min_diff; prescaler++) { /* Initialize to div-by-2 */ rateDivisorValue = 2U; for (rateDivisor = 0; (rateDivisor <= 8U) && min_diff; rateDivisor++) { /* Calculate actual baud rate, note need to add 1 to prescaler */ realBaudrate = ((srcClock_Hz) / ((prescaler + 1) * rateDivisorValue)); /* Calculate the baud rate difference based on the conditional statement ,that states that the calculated baud rate must not exceed the desired baud rate */ if (freq >= realBaudrate) { diff = freq - realBaudrate; if (min_diff > diff) { /* A better match found */ min_diff = diff; bestPrescaler = prescaler; bestDivisor = rateDivisor; } } /* Multiply by 2 for each iteration, possible divisor values: 2, 4, 8, 16, ... 512 */ rateDivisorValue *= 2U; } } /* Write the best prescalar and baud rate scalar */ base->BR = SPI_BR_SPR(bestDivisor) | SPI_BR_SPPR(bestPrescaler); } void SPI_WriteBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /* Check if 16 bits or 8 bits */ bytesPerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #endif while (i < size) { while ((base->S & SPI_S_SPTEF_MASK) == 0) { } /* Send a frame of data */ SPI_WriteNonBlocking(base, buffer, bytesPerFrame); i += bytesPerFrame; buffer += bytesPerFrame; } } #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO void SPI_EnableFIFO(SPI_Type *base, bool enable) { if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0U) { if (enable) { base->C3 |= SPI_C3_FIFOMODE_MASK; } else { base->C3 &= ~SPI_C3_FIFOMODE_MASK; } } } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ void SPI_WriteData(SPI_Type *base, uint16_t data) { #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) base->DL = data & 0xFFU; base->DH = (data >> 8U) & 0xFFU; #else base->D = data & 0xFFU; #endif } uint16_t SPI_ReadData(SPI_Type *base) { uint16_t val = 0; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) val = base->DL; val |= (uint16_t)((uint16_t)(base->DH) << 8U); #else val = base->D; #endif return val; } status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) { assert(xfer); uint8_t bytesPerFrame = 1U; /* Check if the argument is legal */ if ((xfer->txData == NULL) && (xfer->rxData == NULL)) { return kStatus_InvalidArgument; } #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /* Check if 16 bits or 8 bits */ bytesPerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #endif /* Disable SPI and then enable it, this is used to clear S register */ base->C1 &= ~SPI_C1_SPE_MASK; base->C1 |= SPI_C1_SPE_MASK; #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO /* Disable FIFO, as the FIFO may cause data loss if the data size is not integer times of 2bytes. As SPI cannot set watermark to 0, only can set to 1/2 FIFO size or 3/4 FIFO size. */ if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) { base->C3 &= ~SPI_C3_FIFOMODE_MASK; } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ /* Begin the polling transfer until all data sent */ while (xfer->dataSize > 0) { /* Data send */ while ((base->S & SPI_S_SPTEF_MASK) == 0U) { } SPI_WriteNonBlocking(base, xfer->txData, bytesPerFrame); if (xfer->txData) { xfer->txData += bytesPerFrame; } while ((base->S & SPI_S_SPRF_MASK) == 0U) { } SPI_ReadNonBlocking(base, xfer->rxData, bytesPerFrame); if (xfer->rxData) { xfer->rxData += bytesPerFrame; } /* Decrease the number */ xfer->dataSize -= bytesPerFrame; } return kStatus_Success; } void SPI_MasterTransferCreateHandle(SPI_Type *base, spi_master_handle_t *handle, spi_master_callback_t callback, void *userData) { assert(handle); uint8_t instance = SPI_GetInstance(base); /* Initialize the handle */ s_spiHandle[instance] = handle; handle->callback = callback; handle->userData = userData; s_spiIsr = SPI_MasterTransferHandleIRQ; #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO uint8_t txSize = 0U; /* Get the number to be sent if there is FIFO */ if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) { txSize = (base->C3 & SPI_C3_TNEAREF_MARK_MASK) >> SPI_C3_TNEAREF_MARK_SHIFT; if (txSize == 0U) { handle->watermark = FSL_FEATURE_SPI_FIFO_SIZEn(base) * 3U / 4U; } else { handle->watermark = FSL_FEATURE_SPI_FIFO_SIZEn(base) / 2U; } } /* If no FIFO, just set the watermark to 1 */ else { handle->watermark = 1U; } #else handle->watermark = 1U; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ /* Get the bytes per frame */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) handle->bytePerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #else handle->bytePerFrame = 1U; #endif /* Enable SPI NVIC */ EnableIRQ(s_spiIRQ[instance]); } status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer) { assert(handle && xfer); /* Check if SPI is busy */ if (handle->state == kSPI_Busy) { return kStatus_SPI_Busy; } /* Check if the input arguments valid */ if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U)) { return kStatus_InvalidArgument; } /* Set the handle information */ handle->txData = xfer->txData; handle->rxData = xfer->rxData; handle->transferSize = xfer->dataSize; handle->txRemainingBytes = xfer->dataSize; handle->rxRemainingBytes = xfer->dataSize; /* Set the SPI state to busy */ handle->state = kSPI_Busy; /* Disable SPI and then enable it, this is used to clear S register*/ base->C1 &= ~SPI_C1_SPE_MASK; base->C1 |= SPI_C1_SPE_MASK; /* Enable Interrupt, only enable Rx interrupt, use rx interrupt to driver SPI transfer */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (handle->watermark > 1U) { /* Enable Rx near full interrupt */ SPI_EnableInterrupts(base, kSPI_RxFifoNearFullInterruptEnable); } else { SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); } #else SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); #endif /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ SPI_SendTransfer(base, handle); return kStatus_Success; } status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count) { assert(handle); status_t status = kStatus_Success; if (handle->state != kStatus_SPI_Busy) { status = kStatus_NoTransferInProgress; } else { /* Return remaing bytes in different cases */ if (handle->rxData) { *count = handle->transferSize - handle->rxRemainingBytes; } else { *count = handle->transferSize - handle->txRemainingBytes; } } return status; } void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle) { assert(handle); /* Stop interrupts */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO if (handle->watermark > 1U) { SPI_DisableInterrupts(base, kSPI_RxFifoNearFullInterruptEnable | kSPI_RxFullAndModfInterruptEnable); } else { SPI_DisableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); } #else SPI_DisableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); #endif /* Transfer finished, set the state to Done*/ handle->state = kSPI_Idle; /* Clear the internal state */ handle->rxRemainingBytes = 0; handle->txRemainingBytes = 0; } void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle) { assert(handle); /* If needs to receive data, do a receive */ if (handle->rxRemainingBytes) { SPI_ReceiveTransfer(base, handle); } /* We always need to send a data to make the SPI run */ if (handle->txRemainingBytes) { SPI_SendTransfer(base, handle); } /* All the transfer finished */ if ((handle->txRemainingBytes == 0) && (handle->rxRemainingBytes == 0)) { /* Complete the transfer */ SPI_MasterTransferAbort(base, handle); if (handle->callback) { (handle->callback)(base, handle, kStatus_SPI_Idle, handle->userData); } } } void SPI_SlaveTransferCreateHandle(SPI_Type *base, spi_slave_handle_t *handle, spi_slave_callback_t callback, void *userData) { assert(handle); /* Slave create handle share same logic with master create handle, the only difference is the Isr pointer. */ SPI_MasterTransferCreateHandle(base, handle, callback, userData); s_spiIsr = SPI_SlaveTransferHandleIRQ; } void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle) { assert(handle); /* Do data send first in case of data missing. */ if (handle->txRemainingBytes) { SPI_SendTransfer(base, handle); } /* If needs to receive data, do a receive */ if (handle->rxRemainingBytes) { SPI_ReceiveTransfer(base, handle); } /* All the transfer finished */ if ((handle->txRemainingBytes == 0) && (handle->rxRemainingBytes == 0)) { /* Complete the transfer */ SPI_SlaveTransferAbort(base, handle); if (handle->callback) { (handle->callback)(base, handle, kStatus_SPI_Idle, handle->userData); } } } #if defined(SPI0) void SPI0_DriverIRQHandler(void) { assert(s_spiHandle[0]); s_spiIsr(SPI0, s_spiHandle[0]); } #endif #if defined(SPI1) void SPI1_DriverIRQHandler(void) { assert(s_spiHandle[1]); s_spiIsr(SPI1, s_spiHandle[1]); } #endif #if defined(SPI2) void SPI2_DriverIRQHandler(void) { assert(s_spiHandle[2]); s_spiIsr(SPI0, s_spiHandle[2]); } #endif