From ed46e1a38ae2de97b55c1843bad8b813bd4936e3 Mon Sep 17 00:00:00 2001 From: mindchasers Date: Sun, 7 Jul 2019 17:58:07 -0400 Subject: initial commit of private island ARM test suite --- drivers/fsl_dspi.c | 1807 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1807 insertions(+) create mode 100644 drivers/fsl_dspi.c (limited to 'drivers/fsl_dspi.c') diff --git a/drivers/fsl_dspi.c b/drivers/fsl_dspi.c new file mode 100644 index 0000000..620335b --- /dev/null +++ b/drivers/fsl_dspi.c @@ -0,0 +1,1807 @@ +/* + * The Clear BSD License + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) 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. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * 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_dspi.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.dspi" +#endif + +/*! @brief Typedef for master interrupt handler. */ +typedef void (*dspi_master_isr_t)(SPI_Type *base, dspi_master_handle_t *handle); + +/*! @brief Typedef for slave interrupt handler. */ +typedef void (*dspi_slave_isr_t)(SPI_Type *base, dspi_slave_handle_t *handle); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Configures the DSPI peripheral chip select polarity. + * + * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and + * configures the Pcs signal to operate with the desired characteristic. + * + * @param base DSPI peripheral address. + * @param pcs The particular peripheral chip select (parameter value is of type dspi_which_pcs_t) for which we wish to + * apply the active high or active low characteristic. + * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of + * type dspi_pcs_polarity_config_t. + */ +static void DSPI_SetOnePcsPolarity(SPI_Type *base, dspi_which_pcs_t pcs, dspi_pcs_polarity_config_t activeLowOrHigh); + +/*! + * @brief Master fill up the TX FIFO with data. + * This is not a public API. + */ +static void DSPI_MasterTransferFillUpTxFifo(SPI_Type *base, dspi_master_handle_t *handle); + +/*! + * @brief Master finish up a transfer. + * It would call back if there is callback function and set the state to idle. + * This is not a public API. + */ +static void DSPI_MasterTransferComplete(SPI_Type *base, dspi_master_handle_t *handle); + +/*! + * @brief Slave fill up the TX FIFO with data. + * This is not a public API. + */ +static void DSPI_SlaveTransferFillUpTxFifo(SPI_Type *base, dspi_slave_handle_t *handle); + +/*! + * @brief Slave finish up a transfer. + * It would call back if there is callback function and set the state to idle. + * This is not a public API. + */ +static void DSPI_SlaveTransferComplete(SPI_Type *base, dspi_slave_handle_t *handle); + +/*! + * @brief DSPI common interrupt handler. + * + * @param base DSPI peripheral address. + * @param handle pointer to g_dspiHandle which stores the transfer state. + */ +static void DSPI_CommonIRQHandler(SPI_Type *base, void *param); + +/*! + * @brief Master prepare the transfer. + * Basically it set up dspi_master_handle . + * This is not a public API. + */ +static void DSPI_MasterTransferPrepare(SPI_Type *base, dspi_master_handle_t *handle, dspi_transfer_t *transfer); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/ +static const uint32_t s_baudratePrescaler[] = {2, 3, 5, 7}; +static const uint32_t s_baudrateScaler[] = {2, 4, 6, 8, 16, 32, 64, 128, + 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}; + +static const uint32_t s_delayPrescaler[] = {1, 3, 5, 7}; +static const uint32_t s_delayScaler[] = {2, 4, 8, 16, 32, 64, 128, 256, + 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536}; + +/*! @brief Pointers to dspi bases for each instance. */ +static SPI_Type *const s_dspiBases[] = SPI_BASE_PTRS; + +/*! @brief Pointers to dspi IRQ number for each instance. */ +static IRQn_Type const s_dspiIRQ[] = SPI_IRQS; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to dspi clocks for each instance. */ +static clock_ip_name_t const s_dspiClock[] = DSPI_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointers to dspi handles for each instance. */ +static void *g_dspiHandle[ARRAY_SIZE(s_dspiBases)]; + +/*! @brief Pointer to master IRQ handler for each instance. */ +static dspi_master_isr_t s_dspiMasterIsr; + +/*! @brief Pointer to slave IRQ handler for each instance. */ +static dspi_slave_isr_t s_dspiSlaveIsr; + +/* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/ +volatile uint8_t g_dspiDummyData[ARRAY_SIZE(s_dspiBases)] = {0}; +/********************************************************************************************************************** +* Code +*********************************************************************************************************************/ +uint32_t DSPI_GetInstance(SPI_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_dspiBases); instance++) + { + if (s_dspiBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_dspiBases)); + + return instance; +} + +void DSPI_SetDummyData(SPI_Type *base, uint8_t dummyData) +{ + uint32_t instance = DSPI_GetInstance(base); + g_dspiDummyData[instance] = dummyData; +} + +void DSPI_MasterInit(SPI_Type *base, const dspi_master_config_t *masterConfig, uint32_t srcClock_Hz) +{ + assert(masterConfig); + + uint32_t temp; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* enable DSPI clock */ + CLOCK_EnableClock(s_dspiClock[DSPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + DSPI_Enable(base, true); + DSPI_StopTransfer(base); + + DSPI_SetMasterSlaveMode(base, kDSPI_Master); + + temp = base->MCR & (~(SPI_MCR_CONT_SCKE_MASK | SPI_MCR_MTFE_MASK | SPI_MCR_ROOE_MASK | SPI_MCR_SMPL_PT_MASK | + SPI_MCR_DIS_TXF_MASK | SPI_MCR_DIS_RXF_MASK)); + + base->MCR = temp | SPI_MCR_CONT_SCKE(masterConfig->enableContinuousSCK) | + SPI_MCR_MTFE(masterConfig->enableModifiedTimingFormat) | + SPI_MCR_ROOE(masterConfig->enableRxFifoOverWrite) | SPI_MCR_SMPL_PT(masterConfig->samplePoint) | + SPI_MCR_DIS_TXF(false) | SPI_MCR_DIS_RXF(false); + + DSPI_SetOnePcsPolarity(base, masterConfig->whichPcs, masterConfig->pcsActiveHighOrLow); + + if (0 == DSPI_MasterSetBaudRate(base, masterConfig->whichCtar, masterConfig->ctarConfig.baudRate, srcClock_Hz)) + { + assert(false); + } + + temp = base->CTAR[masterConfig->whichCtar] & + ~(SPI_CTAR_FMSZ_MASK | SPI_CTAR_CPOL_MASK | SPI_CTAR_CPHA_MASK | SPI_CTAR_LSBFE_MASK); + + base->CTAR[masterConfig->whichCtar] = + temp | SPI_CTAR_FMSZ(masterConfig->ctarConfig.bitsPerFrame - 1) | SPI_CTAR_CPOL(masterConfig->ctarConfig.cpol) | + SPI_CTAR_CPHA(masterConfig->ctarConfig.cpha) | SPI_CTAR_LSBFE(masterConfig->ctarConfig.direction); + + DSPI_MasterSetDelayTimes(base, masterConfig->whichCtar, kDSPI_PcsToSck, srcClock_Hz, + masterConfig->ctarConfig.pcsToSckDelayInNanoSec); + DSPI_MasterSetDelayTimes(base, masterConfig->whichCtar, kDSPI_LastSckToPcs, srcClock_Hz, + masterConfig->ctarConfig.lastSckToPcsDelayInNanoSec); + DSPI_MasterSetDelayTimes(base, masterConfig->whichCtar, kDSPI_BetweenTransfer, srcClock_Hz, + masterConfig->ctarConfig.betweenTransferDelayInNanoSec); + + DSPI_SetDummyData(base, DSPI_DUMMY_DATA); + DSPI_StartTransfer(base); +} + +void DSPI_MasterGetDefaultConfig(dspi_master_config_t *masterConfig) +{ + assert(masterConfig); + + masterConfig->whichCtar = kDSPI_Ctar0; + masterConfig->ctarConfig.baudRate = 500000; + masterConfig->ctarConfig.bitsPerFrame = 8; + masterConfig->ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh; + masterConfig->ctarConfig.cpha = kDSPI_ClockPhaseFirstEdge; + masterConfig->ctarConfig.direction = kDSPI_MsbFirst; + + masterConfig->ctarConfig.pcsToSckDelayInNanoSec = 1000; + masterConfig->ctarConfig.lastSckToPcsDelayInNanoSec = 1000; + masterConfig->ctarConfig.betweenTransferDelayInNanoSec = 1000; + + masterConfig->whichPcs = kDSPI_Pcs0; + masterConfig->pcsActiveHighOrLow = kDSPI_PcsActiveLow; + + masterConfig->enableContinuousSCK = false; + masterConfig->enableRxFifoOverWrite = false; + masterConfig->enableModifiedTimingFormat = false; + masterConfig->samplePoint = kDSPI_SckToSin0Clock; +} + +void DSPI_SlaveInit(SPI_Type *base, const dspi_slave_config_t *slaveConfig) +{ + assert(slaveConfig); + + uint32_t temp = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* enable DSPI clock */ + CLOCK_EnableClock(s_dspiClock[DSPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + DSPI_Enable(base, true); + DSPI_StopTransfer(base); + + DSPI_SetMasterSlaveMode(base, kDSPI_Slave); + + temp = base->MCR & (~(SPI_MCR_CONT_SCKE_MASK | SPI_MCR_MTFE_MASK | SPI_MCR_ROOE_MASK | SPI_MCR_SMPL_PT_MASK | + SPI_MCR_DIS_TXF_MASK | SPI_MCR_DIS_RXF_MASK)); + + base->MCR = temp | SPI_MCR_CONT_SCKE(slaveConfig->enableContinuousSCK) | + SPI_MCR_MTFE(slaveConfig->enableModifiedTimingFormat) | + SPI_MCR_ROOE(slaveConfig->enableRxFifoOverWrite) | SPI_MCR_SMPL_PT(slaveConfig->samplePoint) | + SPI_MCR_DIS_TXF(false) | SPI_MCR_DIS_RXF(false); + + DSPI_SetOnePcsPolarity(base, kDSPI_Pcs0, kDSPI_PcsActiveLow); + + temp = base->CTAR[slaveConfig->whichCtar] & + ~(SPI_CTAR_FMSZ_MASK | SPI_CTAR_CPOL_MASK | SPI_CTAR_CPHA_MASK | SPI_CTAR_LSBFE_MASK); + + base->CTAR[slaveConfig->whichCtar] = temp | SPI_CTAR_SLAVE_FMSZ(slaveConfig->ctarConfig.bitsPerFrame - 1) | + SPI_CTAR_SLAVE_CPOL(slaveConfig->ctarConfig.cpol) | + SPI_CTAR_SLAVE_CPHA(slaveConfig->ctarConfig.cpha); + + DSPI_SetDummyData(base, DSPI_DUMMY_DATA); + + DSPI_StartTransfer(base); +} + +void DSPI_SlaveGetDefaultConfig(dspi_slave_config_t *slaveConfig) +{ + assert(slaveConfig); + + slaveConfig->whichCtar = kDSPI_Ctar0; + slaveConfig->ctarConfig.bitsPerFrame = 8; + slaveConfig->ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh; + slaveConfig->ctarConfig.cpha = kDSPI_ClockPhaseFirstEdge; + + slaveConfig->enableContinuousSCK = false; + slaveConfig->enableRxFifoOverWrite = false; + slaveConfig->enableModifiedTimingFormat = false; + slaveConfig->samplePoint = kDSPI_SckToSin0Clock; +} + +void DSPI_Deinit(SPI_Type *base) +{ + DSPI_StopTransfer(base); + DSPI_Enable(base, false); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* disable DSPI clock */ + CLOCK_DisableClock(s_dspiClock[DSPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +static void DSPI_SetOnePcsPolarity(SPI_Type *base, dspi_which_pcs_t pcs, dspi_pcs_polarity_config_t activeLowOrHigh) +{ + uint32_t temp; + + temp = base->MCR; + + if (activeLowOrHigh == kDSPI_PcsActiveLow) + { + temp |= SPI_MCR_PCSIS(pcs); + } + else + { + temp &= ~SPI_MCR_PCSIS(pcs); + } + + base->MCR = temp; +} + +uint32_t DSPI_MasterSetBaudRate(SPI_Type *base, + dspi_ctar_selection_t whichCtar, + uint32_t baudRate_Bps, + uint32_t srcClock_Hz) +{ + /* for master mode configuration, if slave mode detected, return 0*/ + if (!DSPI_IsMaster(base)) + { + return 0; + } + uint32_t temp; + uint32_t prescaler, bestPrescaler; + uint32_t scaler, bestScaler; + uint32_t dbr, bestDbr; + uint32_t realBaudrate, bestBaudrate; + uint32_t diff, min_diff; + uint32_t baudrate = baudRate_Bps; + + /* find combination of prescaler and scaler resulting in baudrate closest to the requested value */ + min_diff = 0xFFFFFFFFU; + bestPrescaler = 0; + bestScaler = 0; + bestDbr = 1; + bestBaudrate = 0; /* required to avoid compilation warning */ + + /* In all for loops, if min_diff = 0, the exit for loop*/ + for (prescaler = 0; (prescaler < 4) && min_diff; prescaler++) + { + for (scaler = 0; (scaler < 16) && min_diff; scaler++) + { + for (dbr = 1; (dbr < 3) && min_diff; dbr++) + { + realBaudrate = ((srcClock_Hz * dbr) / (s_baudratePrescaler[prescaler] * (s_baudrateScaler[scaler]))); + + /* 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 (baudrate >= realBaudrate) + { + diff = baudrate - realBaudrate; + if (min_diff > diff) + { + /* a better match found */ + min_diff = diff; + bestPrescaler = prescaler; + bestScaler = scaler; + bestBaudrate = realBaudrate; + bestDbr = dbr; + } + } + } + } + } + + /* write the best dbr, prescalar, and baud rate scalar to the CTAR */ + temp = base->CTAR[whichCtar] & ~(SPI_CTAR_DBR_MASK | SPI_CTAR_PBR_MASK | SPI_CTAR_BR_MASK); + + base->CTAR[whichCtar] = temp | ((bestDbr - 1) << SPI_CTAR_DBR_SHIFT) | (bestPrescaler << SPI_CTAR_PBR_SHIFT) | + (bestScaler << SPI_CTAR_BR_SHIFT); + + /* return the actual calculated baud rate */ + return bestBaudrate; +} + +void DSPI_MasterSetDelayScaler( + SPI_Type *base, dspi_ctar_selection_t whichCtar, uint32_t prescaler, uint32_t scaler, dspi_delay_type_t whichDelay) +{ + /* these settings are only relevant in master mode */ + if (DSPI_IsMaster(base)) + { + switch (whichDelay) + { + case kDSPI_PcsToSck: + base->CTAR[whichCtar] = (base->CTAR[whichCtar] & (~SPI_CTAR_PCSSCK_MASK) & (~SPI_CTAR_CSSCK_MASK)) | + SPI_CTAR_PCSSCK(prescaler) | SPI_CTAR_CSSCK(scaler); + break; + case kDSPI_LastSckToPcs: + base->CTAR[whichCtar] = (base->CTAR[whichCtar] & (~SPI_CTAR_PASC_MASK) & (~SPI_CTAR_ASC_MASK)) | + SPI_CTAR_PASC(prescaler) | SPI_CTAR_ASC(scaler); + break; + case kDSPI_BetweenTransfer: + base->CTAR[whichCtar] = (base->CTAR[whichCtar] & (~SPI_CTAR_PDT_MASK) & (~SPI_CTAR_DT_MASK)) | + SPI_CTAR_PDT(prescaler) | SPI_CTAR_DT(scaler); + break; + default: + break; + } + } +} + +uint32_t DSPI_MasterSetDelayTimes(SPI_Type *base, + dspi_ctar_selection_t whichCtar, + dspi_delay_type_t whichDelay, + uint32_t srcClock_Hz, + uint32_t delayTimeInNanoSec) +{ + /* for master mode configuration, if slave mode detected, return 0 */ + if (!DSPI_IsMaster(base)) + { + return 0; + } + + uint32_t prescaler, bestPrescaler; + uint32_t scaler, bestScaler; + uint32_t realDelay, bestDelay; + uint32_t diff, min_diff; + uint32_t initialDelayNanoSec; + + /* find combination of prescaler and scaler resulting in the delay closest to the + * requested value + */ + min_diff = 0xFFFFFFFFU; + /* Initialize prescaler and scaler to their max values to generate the max delay */ + bestPrescaler = 0x3; + bestScaler = 0xF; + bestDelay = (((1000000000U * 4) / srcClock_Hz) * s_delayPrescaler[bestPrescaler] * s_delayScaler[bestScaler]) / 4; + + /* First calculate the initial, default delay */ + initialDelayNanoSec = 1000000000U / srcClock_Hz * 2; + + /* If the initial, default delay is already greater than the desired delay, then + * set the delays to their initial value (0) and return the delay. In other words, + * there is no way to decrease the delay value further. + */ + if (initialDelayNanoSec >= delayTimeInNanoSec) + { + DSPI_MasterSetDelayScaler(base, whichCtar, 0, 0, whichDelay); + return initialDelayNanoSec; + } + + /* In all for loops, if min_diff = 0, the exit for loop */ + for (prescaler = 0; (prescaler < 4) && min_diff; prescaler++) + { + for (scaler = 0; (scaler < 16) && min_diff; scaler++) + { + realDelay = ((4000000000U / srcClock_Hz) * s_delayPrescaler[prescaler] * s_delayScaler[scaler]) / 4; + + /* calculate the delay difference based on the conditional statement + * that states that the calculated delay must not be less then the desired delay + */ + if (realDelay >= delayTimeInNanoSec) + { + diff = realDelay - delayTimeInNanoSec; + if (min_diff > diff) + { + /* a better match found */ + min_diff = diff; + bestPrescaler = prescaler; + bestScaler = scaler; + bestDelay = realDelay; + } + } + } + } + + /* write the best dbr, prescalar, and baud rate scalar to the CTAR */ + DSPI_MasterSetDelayScaler(base, whichCtar, bestPrescaler, bestScaler, whichDelay); + + /* return the actual calculated baud rate */ + return bestDelay; +} + +void DSPI_GetDefaultDataCommandConfig(dspi_command_data_config_t *command) +{ + assert(command); + + command->isPcsContinuous = false; + command->whichCtar = kDSPI_Ctar0; + command->whichPcs = kDSPI_Pcs0; + command->isEndOfQueue = false; + command->clearTransferCount = false; +} + +void DSPI_MasterWriteDataBlocking(SPI_Type *base, dspi_command_data_config_t *command, uint16_t data) +{ + assert(command); + + /* First, clear Transmit Complete Flag (TCF) */ + DSPI_ClearStatusFlags(base, kDSPI_TxCompleteFlag); + + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + base->PUSHR = SPI_PUSHR_CONT(command->isPcsContinuous) | SPI_PUSHR_CTAS(command->whichCtar) | + SPI_PUSHR_PCS(command->whichPcs) | SPI_PUSHR_EOQ(command->isEndOfQueue) | + SPI_PUSHR_CTCNT(command->clearTransferCount) | SPI_PUSHR_TXDATA(data); + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + /* Wait till TCF sets */ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxCompleteFlag)) + { + } +} + +void DSPI_MasterWriteCommandDataBlocking(SPI_Type *base, uint32_t data) +{ + /* First, clear Transmit Complete Flag (TCF) */ + DSPI_ClearStatusFlags(base, kDSPI_TxCompleteFlag); + + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + base->PUSHR = data; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + /* Wait till TCF sets */ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxCompleteFlag)) + { + } +} + +void DSPI_SlaveWriteDataBlocking(SPI_Type *base, uint32_t data) +{ + /* First, clear Transmit Complete Flag (TCF) */ + DSPI_ClearStatusFlags(base, kDSPI_TxCompleteFlag); + + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + base->PUSHR_SLAVE = data; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + /* Wait till TCF sets */ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxCompleteFlag)) + { + } +} + +void DSPI_EnableInterrupts(SPI_Type *base, uint32_t mask) +{ + if (mask & SPI_RSER_TFFF_RE_MASK) + { + base->RSER &= ~SPI_RSER_TFFF_DIRS_MASK; + } + if (mask & SPI_RSER_RFDF_RE_MASK) + { + base->RSER &= ~SPI_RSER_RFDF_DIRS_MASK; + } + base->RSER |= mask; +} + +/*Transactional APIs -- Master*/ + +void DSPI_MasterTransferCreateHandle(SPI_Type *base, + dspi_master_handle_t *handle, + dspi_master_transfer_callback_t callback, + void *userData) +{ + assert(handle); + + /* Zero the handle. */ + memset(handle, 0, sizeof(*handle)); + + g_dspiHandle[DSPI_GetInstance(base)] = handle; + + handle->callback = callback; + handle->userData = userData; +} + +status_t DSPI_MasterTransferBlocking(SPI_Type *base, dspi_transfer_t *transfer) +{ + assert(transfer); + + uint16_t wordToSend = 0; + uint16_t wordReceived = 0; + uint8_t dummyData = g_dspiDummyData[DSPI_GetInstance(base)]; + uint8_t bitsPerFrame; + + uint32_t command; + uint32_t lastCommand; + + uint8_t *txData; + uint8_t *rxData; + uint32_t remainingSendByteCount; + uint32_t remainingReceiveByteCount; + + uint32_t fifoSize; + dspi_command_data_config_t commandStruct; + + /* If the transfer count is zero, then return immediately.*/ + if (transfer->dataSize == 0) + { + return kStatus_InvalidArgument; + } + + DSPI_StopTransfer(base); + DSPI_DisableInterrupts(base, kDSPI_AllInterruptEnable); + DSPI_FlushFifo(base, true, true); + DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag); + + /*Calculate the command and lastCommand*/ + commandStruct.whichPcs = + (dspi_which_pcs_t)(1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT)); + commandStruct.isEndOfQueue = false; + commandStruct.clearTransferCount = false; + commandStruct.whichCtar = + (dspi_ctar_selection_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT); + commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterPcsContinuous); + + command = DSPI_MasterGetFormattedCommand(&(commandStruct)); + + commandStruct.isEndOfQueue = true; + commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterActiveAfterTransfer); + lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct)); + + /*Calculate the bitsPerFrame*/ + bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1; + + txData = transfer->txData; + rxData = transfer->rxData; + remainingSendByteCount = transfer->dataSize; + remainingReceiveByteCount = transfer->dataSize; + + if ((base->MCR & SPI_MCR_DIS_RXF_MASK) || (base->MCR & SPI_MCR_DIS_TXF_MASK)) + { + fifoSize = 1; + } + else + { + fifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(base); + } + + DSPI_StartTransfer(base); + + if (bitsPerFrame <= 8) + { + while (remainingSendByteCount > 0) + { + if (remainingSendByteCount == 1) + { + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + if (txData != NULL) + { + base->PUSHR = (*txData) | (lastCommand); + txData++; + } + else + { + base->PUSHR = (lastCommand) | (dummyData); + } + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + remainingSendByteCount--; + + while (remainingReceiveByteCount > 0) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + if (rxData != NULL) + { + /* Read data from POPR*/ + *(rxData) = DSPI_ReadData(base); + rxData++; + } + else + { + DSPI_ReadData(base); + } + remainingReceiveByteCount--; + + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + else + { + /*Wait until Tx Fifo is not full*/ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + if (txData != NULL) + { + base->PUSHR = command | (uint16_t)(*txData); + txData++; + } + else + { + base->PUSHR = command | dummyData; + } + remainingSendByteCount--; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + while ((remainingReceiveByteCount - remainingSendByteCount) >= fifoSize) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + if (rxData != NULL) + { + *(rxData) = DSPI_ReadData(base); + rxData++; + } + else + { + DSPI_ReadData(base); + } + remainingReceiveByteCount--; + + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + } + } + else + { + while (remainingSendByteCount > 0) + { + if (remainingSendByteCount <= 2) + { + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + if (txData != NULL) + { + wordToSend = *(txData); + ++txData; + + if (remainingSendByteCount > 1) + { + wordToSend |= (unsigned)(*(txData)) << 8U; + ++txData; + } + } + else + { + wordToSend = dummyData; + } + + base->PUSHR = lastCommand | wordToSend; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + remainingSendByteCount = 0; + + while (remainingReceiveByteCount > 0) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + wordReceived = DSPI_ReadData(base); + + if (remainingReceiveByteCount != 1) + { + if (rxData != NULL) + { + *(rxData) = wordReceived; + ++rxData; + *(rxData) = wordReceived >> 8; + ++rxData; + } + remainingReceiveByteCount -= 2; + } + else + { + if (rxData != NULL) + { + *(rxData) = wordReceived; + ++rxData; + } + remainingReceiveByteCount--; + } + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + else + { + /*Wait until Tx Fifo is not full*/ + while (!(DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } + + if (txData != NULL) + { + wordToSend = *(txData); + ++txData; + wordToSend |= (unsigned)(*(txData)) << 8U; + ++txData; + } + else + { + wordToSend = dummyData; + } + base->PUSHR = command | wordToSend; + remainingSendByteCount -= 2; + + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + while (((remainingReceiveByteCount - remainingSendByteCount) / 2) >= fifoSize) + { + if (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + wordReceived = DSPI_ReadData(base); + + if (rxData != NULL) + { + *rxData = wordReceived; + ++rxData; + *rxData = wordReceived >> 8; + ++rxData; + } + remainingReceiveByteCount -= 2; + + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + } + } + } + } + } + + return kStatus_Success; +} + +static void DSPI_MasterTransferPrepare(SPI_Type *base, dspi_master_handle_t *handle, dspi_transfer_t *transfer) +{ + assert(handle); + assert(transfer); + + dspi_command_data_config_t commandStruct; + + DSPI_StopTransfer(base); + DSPI_FlushFifo(base, true, true); + DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag); + + commandStruct.whichPcs = + (dspi_which_pcs_t)(1U << ((transfer->configFlags & DSPI_MASTER_PCS_MASK) >> DSPI_MASTER_PCS_SHIFT)); + commandStruct.isEndOfQueue = false; + commandStruct.clearTransferCount = false; + commandStruct.whichCtar = + (dspi_ctar_selection_t)((transfer->configFlags & DSPI_MASTER_CTAR_MASK) >> DSPI_MASTER_CTAR_SHIFT); + commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterPcsContinuous); + handle->command = DSPI_MasterGetFormattedCommand(&(commandStruct)); + + commandStruct.isEndOfQueue = true; + commandStruct.isPcsContinuous = (bool)(transfer->configFlags & kDSPI_MasterActiveAfterTransfer); + handle->lastCommand = DSPI_MasterGetFormattedCommand(&(commandStruct)); + + handle->bitsPerFrame = ((base->CTAR[commandStruct.whichCtar] & SPI_CTAR_FMSZ_MASK) >> SPI_CTAR_FMSZ_SHIFT) + 1; + + if ((base->MCR & SPI_MCR_DIS_RXF_MASK) || (base->MCR & SPI_MCR_DIS_TXF_MASK)) + { + handle->fifoSize = 1; + } + else + { + handle->fifoSize = FSL_FEATURE_DSPI_FIFO_SIZEn(base); + } + handle->txData = transfer->txData; + handle->rxData = transfer->rxData; + handle->remainingSendByteCount = transfer->dataSize; + handle->remainingReceiveByteCount = transfer->dataSize; + handle->totalByteCount = transfer->dataSize; +} + +status_t DSPI_MasterTransferNonBlocking(SPI_Type *base, dspi_master_handle_t *handle, dspi_transfer_t *transfer) +{ + assert(handle); + assert(transfer); + + /* If the transfer count is zero, then return immediately.*/ + if (transfer->dataSize == 0) + { + return kStatus_InvalidArgument; + } + + /* Check that we're not busy.*/ + if (handle->state == kDSPI_Busy) + { + return kStatus_DSPI_Busy; + } + + handle->state = kDSPI_Busy; + + /* Disable the NVIC for DSPI peripheral. */ + DisableIRQ(s_dspiIRQ[DSPI_GetInstance(base)]); + + DSPI_MasterTransferPrepare(base, handle, transfer); + + /* RX FIFO Drain request: RFDF_RE to enable RFDF interrupt + * Since SPI is a synchronous interface, we only need to enable the RX interrupt. + * The IRQ handler will get the status of RX and TX interrupt flags. + */ + s_dspiMasterIsr = DSPI_MasterTransferHandleIRQ; + + DSPI_EnableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable); + DSPI_StartTransfer(base); + + /* Fill up the Tx FIFO to trigger the transfer. */ + DSPI_MasterTransferFillUpTxFifo(base, handle); + + /* Enable the NVIC for DSPI peripheral. */ + EnableIRQ(s_dspiIRQ[DSPI_GetInstance(base)]); + + return kStatus_Success; +} + +status_t DSPI_MasterHalfDuplexTransferBlocking(SPI_Type *base, dspi_half_duplex_transfer_t *xfer) +{ + assert(xfer); + + dspi_transfer_t tempXfer = {0}; + status_t status; + + if (xfer->isTransmitFirst) + { + tempXfer.txData = xfer->txData; + tempXfer.rxData = NULL; + tempXfer.dataSize = xfer->txDataSize; + } + else + { + tempXfer.txData = NULL; + tempXfer.rxData = xfer->rxData; + tempXfer.dataSize = xfer->rxDataSize; + } + /* If the pcs pin keep assert between transmit and receive. */ + if (xfer->isPcsAssertInTransfer) + { + tempXfer.configFlags = (xfer->configFlags) | kDSPI_MasterActiveAfterTransfer; + } + else + { + tempXfer.configFlags = (xfer->configFlags) & (uint32_t)(~kDSPI_MasterActiveAfterTransfer); + } + + status = DSPI_MasterTransferBlocking(base, &tempXfer); + if (status != kStatus_Success) + { + return status; + } + + if (xfer->isTransmitFirst) + { + tempXfer.txData = NULL; + tempXfer.rxData = xfer->rxData; + tempXfer.dataSize = xfer->rxDataSize; + } + else + { + tempXfer.txData = xfer->txData; + tempXfer.rxData = NULL; + tempXfer.dataSize = xfer->txDataSize; + } + tempXfer.configFlags = xfer->configFlags; + + /* DSPI transfer blocking. */ + status = DSPI_MasterTransferBlocking(base, &tempXfer); + + return status; +} + +status_t DSPI_MasterHalfDuplexTransferNonBlocking(SPI_Type *base, + dspi_master_handle_t *handle, + dspi_half_duplex_transfer_t *xfer) +{ + assert(xfer); + assert(handle); + dspi_transfer_t tempXfer = {0}; + status_t status; + + if (xfer->isTransmitFirst) + { + tempXfer.txData = xfer->txData; + tempXfer.rxData = NULL; + tempXfer.dataSize = xfer->txDataSize; + } + else + { + tempXfer.txData = NULL; + tempXfer.rxData = xfer->rxData; + tempXfer.dataSize = xfer->rxDataSize; + } + /* If the pcs pin keep assert between transmit and receive. */ + if (xfer->isPcsAssertInTransfer) + { + tempXfer.configFlags = (xfer->configFlags) | kDSPI_MasterActiveAfterTransfer; + } + else + { + tempXfer.configFlags = (xfer->configFlags) & (uint32_t)(~kDSPI_MasterActiveAfterTransfer); + } + + status = DSPI_MasterTransferBlocking(base, &tempXfer); + if (status != kStatus_Success) + { + return status; + } + + if (xfer->isTransmitFirst) + { + tempXfer.txData = NULL; + tempXfer.rxData = xfer->rxData; + tempXfer.dataSize = xfer->rxDataSize; + } + else + { + tempXfer.txData = xfer->txData; + tempXfer.rxData = NULL; + tempXfer.dataSize = xfer->txDataSize; + } + tempXfer.configFlags = xfer->configFlags; + + status = DSPI_MasterTransferNonBlocking(base, handle, &tempXfer); + + return status; +} + +status_t DSPI_MasterTransferGetCount(SPI_Type *base, dspi_master_handle_t *handle, size_t *count) +{ + assert(handle); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state != kDSPI_Busy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + *count = handle->totalByteCount - handle->remainingReceiveByteCount; + return kStatus_Success; +} + +static void DSPI_MasterTransferComplete(SPI_Type *base, dspi_master_handle_t *handle) +{ + assert(handle); + + /* Disable interrupt requests*/ + DSPI_DisableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable); + + status_t status = 0; + if (handle->state == kDSPI_Error) + { + status = kStatus_DSPI_Error; + } + else + { + status = kStatus_Success; + } + + handle->state = kDSPI_Idle; + + if (handle->callback) + { + handle->callback(base, handle, status, handle->userData); + } +} + +static void DSPI_MasterTransferFillUpTxFifo(SPI_Type *base, dspi_master_handle_t *handle) +{ + assert(handle); + + uint16_t wordToSend = 0; + uint8_t dummyData = g_dspiDummyData[DSPI_GetInstance(base)]; + + /* If bits/frame is greater than one byte */ + if (handle->bitsPerFrame > 8) + { + /* Fill the fifo until it is full or until the send word count is 0 or until the difference + * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth. + * The reason for checking the difference is to ensure we only send as much as the + * RX FIFO can receive. + * For this case where bitsPerFrame > 8, each entry in the FIFO contains 2 bytes of the + * send data, hence the difference between the remainingReceiveByteCount and + * remainingSendByteCount must be divided by 2 to convert this difference into a + * 16-bit (2 byte) value. + */ + while ((DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag) && + ((handle->remainingReceiveByteCount - handle->remainingSendByteCount) / 2 < handle->fifoSize)) + { + if (handle->remainingSendByteCount <= 2) + { + if (handle->txData) + { + if (handle->remainingSendByteCount == 1) + { + wordToSend = *(handle->txData); + } + else + { + wordToSend = *(handle->txData); + ++handle->txData; /* increment to next data byte */ + wordToSend |= (unsigned)(*(handle->txData)) << 8U; + } + } + else + { + wordToSend = dummyData; + } + handle->remainingSendByteCount = 0; + base->PUSHR = handle->lastCommand | wordToSend; + } + /* For all words except the last word */ + else + { + if (handle->txData) + { + wordToSend = *(handle->txData); + ++handle->txData; /* increment to next data byte */ + wordToSend |= (unsigned)(*(handle->txData)) << 8U; + ++handle->txData; /* increment to next data byte */ + } + else + { + wordToSend = dummyData; + } + handle->remainingSendByteCount -= 2; /* decrement remainingSendByteCount by 2 */ + base->PUSHR = handle->command | wordToSend; + } + + /* Try to clear the TFFF; if the TX FIFO is full this will clear */ + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + /* exit loop if send count is zero, else update local variables for next loop. + * If this is the first time write to the PUSHR, write only once. + */ + if ((handle->remainingSendByteCount == 0) || (handle->remainingSendByteCount == handle->totalByteCount - 2)) + { + break; + } + } /* End of TX FIFO fill while loop */ + } + /* Optimized for bits/frame less than or equal to one byte. */ + else + { + /* Fill the fifo until it is full or until the send word count is 0 or until the difference + * between the remainingReceiveByteCount and remainingSendByteCount equals the FIFO depth. + * The reason for checking the difference is to ensure we only send as much as the + * RX FIFO can receive. + */ + while ((DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag) && + ((handle->remainingReceiveByteCount - handle->remainingSendByteCount) < handle->fifoSize)) + { + if (handle->txData) + { + wordToSend = *(handle->txData); + ++handle->txData; + } + else + { + wordToSend = dummyData; + } + + if (handle->remainingSendByteCount == 1) + { + base->PUSHR = handle->lastCommand | wordToSend; + } + else + { + base->PUSHR = handle->command | wordToSend; + } + + /* Try to clear the TFFF; if the TX FIFO is full this will clear */ + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + --handle->remainingSendByteCount; + + /* exit loop if send count is zero, else update local variables for next loop + * If this is the first time write to the PUSHR, write only once. + */ + if ((handle->remainingSendByteCount == 0) || (handle->remainingSendByteCount == handle->totalByteCount - 1)) + { + break; + } + } + } +} + +void DSPI_MasterTransferAbort(SPI_Type *base, dspi_master_handle_t *handle) +{ + assert(handle); + + DSPI_StopTransfer(base); + + /* Disable interrupt requests*/ + DSPI_DisableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable); + + handle->state = kDSPI_Idle; +} + +void DSPI_MasterTransferHandleIRQ(SPI_Type *base, dspi_master_handle_t *handle) +{ + assert(handle); + + /* RECEIVE IRQ handler: Check read buffer only if there are remaining bytes to read. */ + if (handle->remainingReceiveByteCount) + { + /* Check read buffer.*/ + uint16_t wordReceived; /* Maximum supported data bit length in master mode is 16-bits */ + + /* If bits/frame is greater than one byte */ + if (handle->bitsPerFrame > 8) + { + while (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + wordReceived = DSPI_ReadData(base); + /* clear the rx fifo drain request, needed for non-DMA applications as this flag + * will remain set even if the rx fifo is empty. By manually clearing this flag, it + * either remain clear if no more data is in the fifo, or it will set if there is + * more data in the fifo. + */ + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + + /* Store read bytes into rx buffer only if a buffer pointer was provided */ + if (handle->rxData) + { + /* For the last word received, if there is an extra byte due to the odd transfer + * byte count, only save the last byte and discard the upper byte + */ + if (handle->remainingReceiveByteCount == 1) + { + *handle->rxData = wordReceived; /* Write first data byte */ + --handle->remainingReceiveByteCount; + } + else + { + *handle->rxData = wordReceived; /* Write first data byte */ + ++handle->rxData; /* increment to next data byte */ + *handle->rxData = wordReceived >> 8; /* Write second data byte */ + ++handle->rxData; /* increment to next data byte */ + handle->remainingReceiveByteCount -= 2; + } + } + else + { + if (handle->remainingReceiveByteCount == 1) + { + --handle->remainingReceiveByteCount; + } + else + { + handle->remainingReceiveByteCount -= 2; + } + } + if (handle->remainingReceiveByteCount == 0) + { + break; + } + } /* End of RX FIFO drain while loop */ + } + /* Optimized for bits/frame less than or equal to one byte. */ + else + { + while (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + wordReceived = DSPI_ReadData(base); + /* clear the rx fifo drain request, needed for non-DMA applications as this flag + * will remain set even if the rx fifo is empty. By manually clearing this flag, it + * either remain clear if no more data is in the fifo, or it will set if there is + * more data in the fifo. + */ + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + + /* Store read bytes into rx buffer only if a buffer pointer was provided */ + if (handle->rxData) + { + *handle->rxData = wordReceived; + ++handle->rxData; + } + + --handle->remainingReceiveByteCount; + + if (handle->remainingReceiveByteCount == 0) + { + break; + } + } /* End of RX FIFO drain while loop */ + } + } + + /* Check write buffer. We always have to send a word in order to keep the transfer + * moving. So if the caller didn't provide a send buffer, we just send a zero. + */ + if (handle->remainingSendByteCount) + { + DSPI_MasterTransferFillUpTxFifo(base, handle); + } + + /* Check if we're done with this transfer.*/ + if ((handle->remainingSendByteCount == 0) && (handle->remainingReceiveByteCount == 0)) + { + /* Complete the transfer and disable the interrupts */ + DSPI_MasterTransferComplete(base, handle); + } +} + +/*Transactional APIs -- Slave*/ +void DSPI_SlaveTransferCreateHandle(SPI_Type *base, + dspi_slave_handle_t *handle, + dspi_slave_transfer_callback_t callback, + void *userData) +{ + assert(handle); + + /* Zero the handle. */ + memset(handle, 0, sizeof(*handle)); + + g_dspiHandle[DSPI_GetInstance(base)] = handle; + + handle->callback = callback; + handle->userData = userData; +} + +status_t DSPI_SlaveTransferNonBlocking(SPI_Type *base, dspi_slave_handle_t *handle, dspi_transfer_t *transfer) +{ + assert(handle); + assert(transfer); + + /* If receive length is zero */ + if (transfer->dataSize == 0) + { + return kStatus_InvalidArgument; + } + + /* If both send buffer and receive buffer is null */ + if ((!(transfer->txData)) && (!(transfer->rxData))) + { + return kStatus_InvalidArgument; + } + + /* Check that we're not busy.*/ + if (handle->state == kDSPI_Busy) + { + return kStatus_DSPI_Busy; + } + handle->state = kDSPI_Busy; + + /* Enable the NVIC for DSPI peripheral. */ + EnableIRQ(s_dspiIRQ[DSPI_GetInstance(base)]); + + /* Store transfer information */ + handle->txData = transfer->txData; + handle->rxData = transfer->rxData; + handle->remainingSendByteCount = transfer->dataSize; + handle->remainingReceiveByteCount = transfer->dataSize; + handle->totalByteCount = transfer->dataSize; + + handle->errorCount = 0; + + uint8_t whichCtar = (transfer->configFlags & DSPI_SLAVE_CTAR_MASK) >> DSPI_SLAVE_CTAR_SHIFT; + handle->bitsPerFrame = + (((base->CTAR_SLAVE[whichCtar]) & SPI_CTAR_SLAVE_FMSZ_MASK) >> SPI_CTAR_SLAVE_FMSZ_SHIFT) + 1; + + DSPI_StopTransfer(base); + + DSPI_FlushFifo(base, true, true); + DSPI_ClearStatusFlags(base, kDSPI_AllStatusFlag); + + s_dspiSlaveIsr = DSPI_SlaveTransferHandleIRQ; + + /* Enable RX FIFO drain request, the slave only use this interrupt */ + DSPI_EnableInterrupts(base, kDSPI_RxFifoDrainRequestInterruptEnable); + + if (handle->rxData) + { + /* RX FIFO overflow request enable */ + DSPI_EnableInterrupts(base, kDSPI_RxFifoOverflowInterruptEnable); + } + if (handle->txData) + { + /* TX FIFO underflow request enable */ + DSPI_EnableInterrupts(base, kDSPI_TxFifoUnderflowInterruptEnable); + } + + DSPI_StartTransfer(base); + + /* Prepare data to transmit */ + DSPI_SlaveTransferFillUpTxFifo(base, handle); + + return kStatus_Success; +} + +status_t DSPI_SlaveTransferGetCount(SPI_Type *base, dspi_slave_handle_t *handle, size_t *count) +{ + assert(handle); + + if (!count) + { + return kStatus_InvalidArgument; + } + + /* Catch when there is not an active transfer. */ + if (handle->state != kDSPI_Busy) + { + *count = 0; + return kStatus_NoTransferInProgress; + } + + *count = handle->totalByteCount - handle->remainingReceiveByteCount; + return kStatus_Success; +} + +static void DSPI_SlaveTransferFillUpTxFifo(SPI_Type *base, dspi_slave_handle_t *handle) +{ + assert(handle); + + uint16_t transmitData = 0; + uint8_t dummyPattern = g_dspiDummyData[DSPI_GetInstance(base)]; + + /* Service the transmitter, if transmit buffer provided, transmit the data, + * else transmit dummy pattern + */ + while (DSPI_GetStatusFlags(base) & kDSPI_TxFifoFillRequestFlag) + { + /* Transmit data */ + if (handle->remainingSendByteCount > 0) + { + /* Have data to transmit, update the transmit data and push to FIFO */ + if (handle->bitsPerFrame <= 8) + { + /* bits/frame is 1 byte */ + if (handle->txData) + { + /* Update transmit data and transmit pointer */ + transmitData = *handle->txData; + handle->txData++; + } + else + { + transmitData = dummyPattern; + } + + /* Decrease remaining dataSize */ + --handle->remainingSendByteCount; + } + /* bits/frame is 2 bytes */ + else + { + /* With multibytes per frame transmission, the transmit frame contains data from + * transmit buffer until sent dataSize matches user request. Other bytes will set to + * dummy pattern value. + */ + if (handle->txData) + { + /* Update first byte of transmit data and transmit pointer */ + transmitData = *handle->txData; + handle->txData++; + + if (handle->remainingSendByteCount == 1) + { + /* Decrease remaining dataSize */ + --handle->remainingSendByteCount; + /* Update second byte of transmit data to second byte of dummy pattern */ + transmitData = transmitData | (uint16_t)(((uint16_t)dummyPattern) << 8); + } + else + { + /* Update second byte of transmit data and transmit pointer */ + transmitData = transmitData | (uint16_t)((uint16_t)(*handle->txData) << 8); + handle->txData++; + handle->remainingSendByteCount -= 2; + } + } + else + { + if (handle->remainingSendByteCount == 1) + { + --handle->remainingSendByteCount; + } + else + { + handle->remainingSendByteCount -= 2; + } + transmitData = (uint16_t)((uint16_t)(dummyPattern) << 8) | dummyPattern; + } + } + } + else + { + break; + } + + /* Write the data to the DSPI data register */ + base->PUSHR_SLAVE = transmitData; + + /* Try to clear TFFF by writing a one to it; it will not clear if TX FIFO not full */ + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + } +} + +static void DSPI_SlaveTransferComplete(SPI_Type *base, dspi_slave_handle_t *handle) +{ + assert(handle); + + /* Disable interrupt requests */ + DSPI_DisableInterrupts(base, kDSPI_TxFifoUnderflowInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable | + kDSPI_RxFifoOverflowInterruptEnable | kDSPI_RxFifoDrainRequestInterruptEnable); + + /* The transfer is complete. */ + handle->txData = NULL; + handle->rxData = NULL; + handle->remainingReceiveByteCount = 0; + handle->remainingSendByteCount = 0; + + status_t status = 0; + if (handle->state == kDSPI_Error) + { + status = kStatus_DSPI_Error; + } + else + { + status = kStatus_Success; + } + + handle->state = kDSPI_Idle; + + if (handle->callback) + { + handle->callback(base, handle, status, handle->userData); + } +} + +void DSPI_SlaveTransferAbort(SPI_Type *base, dspi_slave_handle_t *handle) +{ + assert(handle); + + DSPI_StopTransfer(base); + + /* Disable interrupt requests */ + DSPI_DisableInterrupts(base, kDSPI_TxFifoUnderflowInterruptEnable | kDSPI_TxFifoFillRequestInterruptEnable | + kDSPI_RxFifoOverflowInterruptEnable | kDSPI_RxFifoDrainRequestInterruptEnable); + + handle->state = kDSPI_Idle; + handle->remainingSendByteCount = 0; + handle->remainingReceiveByteCount = 0; +} + +void DSPI_SlaveTransferHandleIRQ(SPI_Type *base, dspi_slave_handle_t *handle) +{ + assert(handle); + + uint8_t dummyPattern = g_dspiDummyData[DSPI_GetInstance(base)]; + uint32_t dataReceived; + uint32_t dataSend = 0; + + /* Because SPI protocol is synchronous, the number of bytes that that slave received from the + * master is the actual number of bytes that the slave transmitted to the master. So we only + * monitor the received dataSize to know when the transfer is complete. + */ + if (handle->remainingReceiveByteCount > 0) + { + while (DSPI_GetStatusFlags(base) & kDSPI_RxFifoDrainRequestFlag) + { + /* Have received data in the buffer. */ + dataReceived = base->POPR; + /*Clear the rx fifo drain request, needed for non-DMA applications as this flag + * will remain set even if the rx fifo is empty. By manually clearing this flag, it + * either remain clear if no more data is in the fifo, or it will set if there is + * more data in the fifo. + */ + DSPI_ClearStatusFlags(base, kDSPI_RxFifoDrainRequestFlag); + + /* If bits/frame is one byte */ + if (handle->bitsPerFrame <= 8) + { + if (handle->rxData) + { + /* Receive buffer is not null, store data into it */ + *handle->rxData = dataReceived; + ++handle->rxData; + } + /* Descrease remaining receive byte count */ + --handle->remainingReceiveByteCount; + + if (handle->remainingSendByteCount > 0) + { + if (handle->txData) + { + dataSend = *handle->txData; + ++handle->txData; + } + else + { + dataSend = dummyPattern; + } + + --handle->remainingSendByteCount; + /* Write the data to the DSPI data register */ + base->PUSHR_SLAVE = dataSend; + } + } + else /* If bits/frame is 2 bytes */ + { + /* With multibytes frame receiving, we only receive till the received dataSize + * matches user request. Other bytes will be ignored. + */ + if (handle->rxData) + { + /* Receive buffer is not null, store first byte into it */ + *handle->rxData = dataReceived; + ++handle->rxData; + + if (handle->remainingReceiveByteCount == 1) + { + /* Decrease remaining receive byte count */ + --handle->remainingReceiveByteCount; + } + else + { + /* Receive buffer is not null, store second byte into it */ + *handle->rxData = dataReceived >> 8; + ++handle->rxData; + handle->remainingReceiveByteCount -= 2; + } + } + /* If no handle->rxData*/ + else + { + if (handle->remainingReceiveByteCount == 1) + { + /* Decrease remaining receive byte count */ + --handle->remainingReceiveByteCount; + } + else + { + handle->remainingReceiveByteCount -= 2; + } + } + + if (handle->remainingSendByteCount > 0) + { + if (handle->txData) + { + dataSend = *handle->txData; + ++handle->txData; + + if (handle->remainingSendByteCount == 1) + { + --handle->remainingSendByteCount; + dataSend |= (uint16_t)((uint16_t)(dummyPattern) << 8); + } + else + { + dataSend |= (uint32_t)(*handle->txData) << 8; + ++handle->txData; + handle->remainingSendByteCount -= 2; + } + } + /* If no handle->txData*/ + else + { + if (handle->remainingSendByteCount == 1) + { + --handle->remainingSendByteCount; + } + else + { + handle->remainingSendByteCount -= 2; + } + dataSend = (uint16_t)((uint16_t)(dummyPattern) << 8) | dummyPattern; + } + /* Write the data to the DSPI data register */ + base->PUSHR_SLAVE = dataSend; + } + } + /* Try to clear TFFF by writing a one to it; it will not clear if TX FIFO not full */ + DSPI_ClearStatusFlags(base, kDSPI_TxFifoFillRequestFlag); + + if (handle->remainingReceiveByteCount == 0) + { + break; + } + } + } + /* Check if remaining receive byte count matches user request */ + if ((handle->remainingReceiveByteCount == 0) || (handle->state == kDSPI_Error)) + { + /* Other cases, stop the transfer. */ + DSPI_SlaveTransferComplete(base, handle); + return; + } + + /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */ + if ((DSPI_GetStatusFlags(base) & kDSPI_TxFifoUnderflowFlag) && (base->RSER & SPI_RSER_TFUF_RE_MASK)) + { + DSPI_ClearStatusFlags(base, kDSPI_TxFifoUnderflowFlag); + /* Change state to error and clear flag */ + if (handle->txData) + { + handle->state = kDSPI_Error; + } + handle->errorCount++; + } + /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */ + if ((DSPI_GetStatusFlags(base) & kDSPI_RxFifoOverflowFlag) && (base->RSER & SPI_RSER_RFOF_RE_MASK)) + { + DSPI_ClearStatusFlags(base, kDSPI_RxFifoOverflowFlag); + /* Change state to error and clear flag */ + if (handle->txData) + { + handle->state = kDSPI_Error; + } + handle->errorCount++; + } +} + +static void DSPI_CommonIRQHandler(SPI_Type *base, void *param) +{ + if (DSPI_IsMaster(base)) + { + s_dspiMasterIsr(base, (dspi_master_handle_t *)param); + } + else + { + s_dspiSlaveIsr(base, (dspi_slave_handle_t *)param); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#if defined(SPI0) +void SPI0_DriverIRQHandler(void) +{ + assert(g_dspiHandle[0]); + DSPI_CommonIRQHandler(SPI0, g_dspiHandle[0]); +} +#endif + +#if defined(SPI1) +void SPI1_DriverIRQHandler(void) +{ + assert(g_dspiHandle[1]); + DSPI_CommonIRQHandler(SPI1, g_dspiHandle[1]); +} +#endif + +#if defined(SPI2) +void SPI2_DriverIRQHandler(void) +{ + assert(g_dspiHandle[2]); + DSPI_CommonIRQHandler(SPI2, g_dspiHandle[2]); +} +#endif + +#if defined(SPI3) +void SPI3_DriverIRQHandler(void) +{ + assert(g_dspiHandle[3]); + DSPI_CommonIRQHandler(SPI3, g_dspiHandle[3]); +} +#endif + +#if defined(SPI4) +void SPI4_DriverIRQHandler(void) +{ + assert(g_dspiHandle[4]); + DSPI_CommonIRQHandler(SPI4, g_dspiHandle[4]); +} +#endif + +#if defined(SPI5) +void SPI5_DriverIRQHandler(void) +{ + assert(g_dspiHandle[5]); + DSPI_CommonIRQHandler(SPI5, g_dspiHandle[5]); +} +#endif + +#if (FSL_FEATURE_SOC_DSPI_COUNT > 6) +#error "Should write the SPIx_DriverIRQHandler function that instance greater than 5 !" +#endif -- cgit v1.2.3-8-gadcc