blob: ab5abda8dca0186c91850ff0b9d555b16c0e084d [file] [log] [blame]
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
*
* 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 the copyright holder 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 Get the waterrmark value for this SPI instance.
*
* @param base SPI base pointer
* @return Watermark value for the SPI instance.
*/
static uint8_t SPI_GetWatermark(SPI_Type *base);
/*!
* @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 base SPI base pointer
* @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 base SPI base pointer
* @param handle Pointer to SPI master handle structure.
*/
static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle);
/*!
* @brief Common IRQ handler for SPI.
*
* @param base SPI base pointer.
* @param instance SPI instance number.
*/
static void SPI_CommonIRQHandler(SPI_Type *base, uint32_t instance);
/*******************************************************************************
* 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;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief Clock array name */
static const clock_ip_name_t s_spiClock[] = SPI_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/*! @brief Pointer to master IRQ handler for each instance. */
static spi_isr_t s_spiMasterIsr;
static spi_isr_t s_spiSlaveIsr;
/*******************************************************************************
* Code
******************************************************************************/
uint32_t SPI_GetInstance(SPI_Type *base)
{
uint32_t instance;
/* Find the instance index from base address mappings. */
for (instance = 0; instance < ARRAY_SIZE(s_spiBases); instance++)
{
if (s_spiBases[instance] == base)
{
break;
}
}
assert(instance < ARRAY_SIZE(s_spiBases));
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 uint8_t SPI_GetWatermark(SPI_Type *base)
{
uint8_t ret = 0;
#if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO
uint8_t rxSize = 0U;
/* Get the number to be sent if there is FIFO */
if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0)
{
rxSize = (base->C3 & SPI_C3_RNFULLF_MARK_MASK) >> SPI_C3_RNFULLF_MARK_SHIFT;
if (rxSize == 0U)
{
ret = FSL_FEATURE_SPI_FIFO_SIZEn(base) * 3U / 4U;
}
else
{
ret = FSL_FEATURE_SPI_FIFO_SIZEn(base) / 2U;
}
}
/* If no FIFO, just set the watermark to 1 */
else
{
ret = 1U;
}
#else
ret = 1U;
#endif /* FSL_FEATURE_SPI_HAS_FIFO */
return ret;
}
static void SPI_SendInitialTransfer(SPI_Type *base, spi_master_handle_t *handle)
{
uint8_t bytestoTransfer = handle->bytePerFrame;
#if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO)
if (handle->watermark > 1)
{
bytestoTransfer = 2 * handle->watermark;
}
#endif
SPI_WriteNonBlocking(base, handle->txData, bytestoTransfer);
/* Update handle information */
if (handle->txData)
{
handle->txData += bytestoTransfer;
}
handle->txRemainingBytes -= bytestoTransfer;
}
static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle)
{
uint8_t bytes = handle->bytePerFrame;
/* Read S register and ensure SPTEF is 1, otherwise the write would be ignored. */
if (handle->watermark == 1U)
{
/* 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 >= bytes))
{
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
{
uint8_t bytestoTransfer = handle->watermark * 2;
if (handle->txRemainingBytes < 8U)
{
bytestoTransfer = handle->txRemainingBytes;
}
SPI_WriteNonBlocking(base, handle->txData, bytestoTransfer);
/* Update handle information */
if (handle->txData)
{
handle->txData += bytestoTransfer;
}
handle->txRemainingBytes -= bytestoTransfer;
}
#endif
}
static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle)
{
uint8_t bytes = handle->bytePerFrame;
/* Read S register and ensure SPRF is 1, otherwise the write would be ignored. */
if (handle->watermark == 1U)
{
if (base->S & SPI_S_SPRF_MASK)
{
SPI_ReadNonBlocking(base, handle->rxData, bytes);
/* Update information in handle */
if (handle->rxData)
{
handle->rxData += bytes;
}
handle->rxRemainingBytes -= bytes;
}
}
#if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO)
/* If use FIFO */
else
{
/* While rx fifo not empty and remaining data can also trigger the last interrupt */
while ((base->S & SPI_S_RFIFOEF_MASK) == 0U)
{
SPI_ReadNonBlocking(base, handle->rxData, bytes);
/* Update information in handle */
if (handle->rxData)
{
handle->rxData += bytes;
}
handle->rxRemainingBytes -= bytes;
/* If the reamining data equals to watermark, leave to last interrupt */
if (handle->rxRemainingBytes == (handle->watermark * 2U))
{
break;
}
}
}
#endif
}
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);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Open clock gate for SPI and open interrupt */
CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/* 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);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Open clock gate for SPI and open interrupt */
CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/* 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;
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Gate the clock */
CLOCK_DisableClock(s_spiClock[SPI_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}
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);
/* Zero the handle */
memset(handle, 0, sizeof(*handle));
/* Initialize the handle */
s_spiHandle[instance] = handle;
handle->callback = callback;
handle->userData = userData;
s_spiMasterIsr = SPI_MasterTransferHandleIRQ;
handle->watermark = SPI_GetWatermark(base);
/* 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
handle->watermark = SPI_GetWatermark(base);
/* If the size of the transfer size less than watermark, set watermark to 1 */
if (xfer->dataSize < handle->watermark * 2U)
{
handle->watermark = 1U;
}
/* According to watermark size, enable interrupts */
if (handle->watermark > 1U)
{
SPI_EnableFIFO(base, true);
/* First send a piece of data to Tx Data or FIFO to start a SPI transfer */
while ((base->S & SPI_S_TNEAREF_MASK) != SPI_S_TNEAREF_MASK)
;
SPI_SendInitialTransfer(base, handle);
/* Enable Rx near full interrupt */
SPI_EnableInterrupts(base, kSPI_RxFifoNearFullInterruptEnable);
}
else
{
SPI_EnableFIFO(base, false);
while ((base->S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK)
;
/* First send a piece of data to Tx Data or FIFO to start a SPI transfer */
SPI_SendInitialTransfer(base, handle);
SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable);
}
#else
while ((base->S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK)
;
/* First send a piece of data to Tx Data or FIFO to start a SPI transfer */
SPI_SendInitialTransfer(base, handle);
SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable);
#endif
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_spiSlaveIsr = 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);
}
}
}
static void SPI_CommonIRQHandler(SPI_Type *base, uint32_t instance)
{
if (base->C1 & SPI_C1_MSTR_MASK)
{
s_spiMasterIsr(base, s_spiHandle[instance]);
}
else
{
s_spiSlaveIsr(base, s_spiHandle[instance]);
}
}
#if defined(SPI0)
void SPI0_DriverIRQHandler(void)
{
assert(s_spiHandle[0]);
SPI_CommonIRQHandler(SPI0, 0);
}
#endif
#if defined(SPI1)
void SPI1_DriverIRQHandler(void)
{
assert(s_spiHandle[1]);
SPI_CommonIRQHandler(SPI1, 1);
}
#endif
#if defined(SPI2)
void SPI2_DriverIRQHandler(void)
{
assert(s_spiHandle[2]);
SPI_CommonIRQHandler(SPI2, 2);
}
#endif