/* * 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