/*! * @brief Finish up a transfer. * Cleans up after a transfer is complete. Interrupts are disabled, and the SPI module * is disabled. This is not a public API as it is called from other driver functions. */ static void SPI_DRV_MasterCompleteTransfer(uint32_t instance) { /* instantiate local variable of type spi_master_state_t and point to global state */ spi_master_state_t * spiState = (spi_master_state_t *)g_spiStatePtr[instance]; SPI_Type *base = g_spiBase[instance]; /* The transfer is complete.*/ spiState->isTransferInProgress = false; /* Disable interrupts */ SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, false); SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, false); #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (g_spiFifoSize[instance] != 0) { /* Now disable the SPI FIFO interrupts */ SPI_HAL_SetFifoIntCmd(base, kSpiTxFifoNearEmptyInt, false); SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, false); } #endif if (spiState->isTransferBlocking) { /* Signal the synchronous completion object */ OSA_SemaPost(&spiState->irqSync); } }
/*FUNCTION********************************************************************** * * Function Name : SPI_DRV_MasterTransferBlocking * Description : Performs a blocking SPI master mode transfer. * This function simultaneously sends and receives data on the SPI bus, as SPI is naturally * a full-duplex bus. The function will not return until the transfer is complete. * *END**************************************************************************/ spi_status_t SPI_DRV_MasterTransferBlocking(uint32_t instance, const spi_master_user_config_t * device, const uint8_t * sendBuffer, uint8_t * receiveBuffer, size_t transferByteCount, uint32_t timeout) { /* instantiate local variable of type spi_master_state_t and point to global state */ spi_master_state_t * spiState = (spi_master_state_t *)g_spiStatePtr[instance]; spi_status_t errorStatus = kStatus_SPI_Success; SPI_Type *base = g_spiBase[instance]; /* fill in members of the run-time state struct*/ spiState->isTransferBlocking = true; /* Indicates this is a blocking transfer */ spiState->sendBuffer = (const uint8_t *)sendBuffer; spiState->receiveBuffer = (uint8_t *)receiveBuffer; spiState->remainingSendByteCount = transferByteCount; spiState->remainingReceiveByteCount = transferByteCount; /* start the transfer process*/ errorStatus = SPI_DRV_MasterStartTransfer(instance, device); if (errorStatus != kStatus_SPI_Success) { return errorStatus; } /* As this is a synchronous transfer, wait until the transfer is complete.*/ osa_status_t syncStatus; do { syncStatus = OSA_SemaWait(&spiState->irqSync, timeout); }while(syncStatus == kStatus_OSA_Idle); /* If a timeout occurs, stop the transfer by setting the isTransferInProgress to false and * disabling interrupts, then return the timeout error status. */ if (syncStatus != kStatus_OSA_Success) { /* The transfer is complete.*/ spiState->isTransferInProgress = false; /* Disable interrupts */ SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, false); SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, false); #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (g_spiFifoSize[instance] != 0) { /* Now disable the SPI FIFO interrupts */ SPI_HAL_SetFifoIntCmd(base, kSpiTxFifoNearEmptyInt, false); SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, false); } #endif errorStatus = kStatus_SPI_Timeout; } return errorStatus; }
/*FUNCTION********************************************************************** * * Function Name : SPI_DRV_DmaSlaveCompleteTransfer * Description : Finish up a transfer. * Cleans up after a transfer is complete. Interrupts are disabled, and the SPI module * is disabled. This is not a public API as it is called from other driver functions. * *END**************************************************************************/ static void SPI_DRV_DmaSlaveCompleteTransfer(uint32_t instance) { spi_dma_slave_state_t * spiState = (spi_dma_slave_state_t *)g_spiStatePtr[instance]; SPI_Type *base = g_spiBase[instance]; /* Disable DMA requests and interrupts. */ SPI_HAL_SetRxDmaCmd(base, false); SPI_HAL_SetTxDmaCmd(base, false); SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, false); /* Stop DMA channels */ DMA_DRV_StopChannel(&spiState->dmaTransmit); DMA_DRV_StopChannel(&spiState->dmaReceive); /* Disable interrupts */ SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, false); #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (g_spiFifoSize[instance] != 0) { /* Now disable the SPI FIFO interrupts */ SPI_HAL_SetFifoIntCmd(base, kSpiTxFifoNearEmptyInt, false); SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, false); } /* Receive extra byte if remaining receive byte is 0 */ if ((spiState->hasExtraByte) && (!spiState->remainingReceiveByteCount) && (spiState->receiveBuffer)) { spiState->receiveBuffer[spiState->remainingReceiveByteCount] = SPI_HAL_ReadDataLow(base); } #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ if (spiState->isSync) { /* Signal the synchronous completion object */ OSA_EventSet(&spiState->event, kSpiDmaTransferDone); } /* The transfer is complete, update the state structure */ spiState->isTransferInProgress = false; spiState->status = kStatus_SPI_Success; spiState->errorCount = 0; spiState->sendBuffer = NULL; spiState->receiveBuffer = NULL; spiState->remainingSendByteCount = 0; spiState->remainingReceiveByteCount = 0; }
/*FUNCTION********************************************************************** * * Function Name : SPI_DRV_DmaSlaveDeinit * Description : De-initializes the device. * Clears the control register and turns off the clock to the module. * *END**************************************************************************/ spi_status_t SPI_DRV_DmaSlaveDeinit(uint32_t instance) { spi_dma_slave_state_t * spiState = (spi_dma_slave_state_t *)g_spiStatePtr[instance]; SPI_Type *base = g_spiBase[instance]; assert(instance < SPI_INSTANCE_COUNT); /* Disable SPI interrupt */ INT_SYS_DisableIRQ(g_spiIrqId[instance]); /* Reset the SPI module to its default settings including disabling SPI and its interrupts */ SPI_HAL_Init(base); #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (g_spiFifoSize[instance] != 0) { SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, false); } /* disable transmit interrupt */ SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, false); #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ /* Free DMA channels */ DMA_DRV_FreeChannel(&spiState->dmaReceive); DMA_DRV_FreeChannel(&spiState->dmaTransmit); /* Disable clock for SPI */ CLOCK_SYS_DisableSpiClock(instance); /* Destroy the event */ OSA_EventDestroy(&spiState->event); /* Clear state pointer */ g_spiStatePtr[instance] = NULL; return kStatus_SPI_Success; }
/*! * @brief Initiate (start) a transfer. This is not a public API as it is called from other * driver functions */ static spi_status_t SPI_DRV_MasterStartTransfer(uint32_t instance, const spi_master_user_config_t * device) { /* instantiate local variable of type spi_master_state_t and point to global state */ spi_master_state_t * spiState = (spi_master_state_t *)g_spiStatePtr[instance]; uint32_t calculatedBaudRate; SPI_Type *base = g_spiBase[instance]; /* Check that we're not busy.*/ if (spiState->isTransferInProgress) { return kStatus_SPI_Busy; } /* Configure bus for this device. If NULL is passed, we assume the caller has * preconfigured the bus using SPI_DRV_MasterConfigureBus(). * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate * then they can call this function separately. */ if (device) { SPI_DRV_MasterConfigureBus(instance, device, &calculatedBaudRate); } /* In order to flush any remaining data in the shift register, disable then enable the SPI */ SPI_HAL_Disable(base); SPI_HAL_Enable(base); #if FSL_FEATURE_SPI_16BIT_TRANSFERS spi_data_bitcount_mode_t bitCount; bitCount = SPI_HAL_Get8or16BitMode(base); /* Check the transfer byte count. If bits/frame > 8, meaning 2 bytes if bits/frame > 8, and if * the transfer byte count is an odd count we'll have to increase the transfer byte count * by one and assert a flag to indicate to the receive function that it will need to handle * an extra byte so that it does not inadverently over-write an another byte to the receive * buffer. For sending the extra byte, we don't care if we read past the send buffer since we * are only reading from it and the absolute last byte (that completes the final 16-bit word) * is a don't care byte anyway. */ if ((bitCount == kSpi16BitMode) && (spiState->remainingSendByteCount & 1UL)) { spiState->remainingSendByteCount += 1; spiState->remainingReceiveByteCount += 1; spiState->extraByte = true; } else { spiState->extraByte = false; } #endif /* If the byte count is zero, then return immediately.*/ if (spiState->remainingSendByteCount == 0) { SPI_DRV_MasterCompleteTransfer(instance); return kStatus_SPI_Success; } /* Save information about the transfer for use by the ISR.*/ spiState->isTransferInProgress = true; spiState->transferredByteCount = 0; /* Make sure TX data register (or FIFO) is empty. If not, return appropriate * error status. This also causes a read of the status * register which is required before writing to the data register below. */ if (SPI_HAL_IsTxBuffEmptyPending(base) != 1) { return kStatus_SPI_TxBufferNotEmpty; } #if FSL_FEATURE_SPI_16BIT_TRANSFERS /* If the module/instance contains a FIFO (and if enabled), proceed with FIFO usage for either * 8- or 16-bit transfers, else bypass to non-FIFO usage. */ if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base))) { /* First fill the FIFO with data */ SPI_DRV_MasterFillupTxFifo(instance); /* If the remaining RX byte count is less than the RX FIFO watermark, enable * the TX FIFO empty interrupt. Once the TX FIFO is empty, we are ensured * that the transmission is complete and can then drain the RX FIFO. * Else, enable the RX FIFO interrupt based on the watermark. In the IRQ * handler, another check will be made to see if the remaining RX byte count * is less than the RX FIFO watermark. */ if (spiState->remainingReceiveByteCount < g_spiFifoSize[instance]) { SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); /* TX FIFO empty interrupt */ } else { SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, true); } } /* Modules that support 16-bit transfers but without FIFO support */ else { uint8_t byteToSend = 0; /* SPI configured for 16-bit transfers, no FIFO */ if (bitCount == kSpi16BitMode) { uint8_t byteToSendLow = 0; uint8_t byteToSendHigh = 0; if (spiState->sendBuffer) { byteToSendLow = *(spiState->sendBuffer); ++spiState->sendBuffer; /* If the extraByte flag is set and these are the last 2 bytes, then skip this */ if (!((spiState->extraByte) && (spiState->remainingSendByteCount == 2))) { byteToSendHigh = *(spiState->sendBuffer); ++spiState->sendBuffer; } } SPI_HAL_WriteDataLow(base, byteToSendLow); SPI_HAL_WriteDataHigh(base, byteToSendHigh); spiState->remainingSendByteCount -= 2; /* decrement by 2 */ spiState->transferredByteCount += 2; /* increment by 2 */ } /* SPI configured for 8-bit transfers, no FIFO */ else { if (spiState->sendBuffer) { byteToSend = *(spiState->sendBuffer); ++spiState->sendBuffer; } SPI_HAL_WriteDataLow(base, byteToSend); --spiState->remainingSendByteCount; ++spiState->transferredByteCount; } /* Only enable the receive interrupt. This should be ok since SPI is a synchronous * protocol, so every RX interrupt we get, we should be ready to send. However, since * the SPI has a shift register and data buffer (for transmit and receive), things may not * be cycle-to-cycle synchronous. To compensate for this, enabling the RX interrupt only * ensures that we do indeed receive data before sending out the next data word. In the * ISR we make sure to first check for the RX data buffer full before checking the TX * data register empty flag. */ SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, true); } #else /* For SPI modules that do not support 16-bit transfers */ /* Start the transfer by writing the first byte. If a send buffer was provided, the byte * comes from there. Otherwise we just send a zero byte. Note that before writing to the * data register, the status register must first be read, which was already performed above. */ uint8_t byteToSend = 0; if (spiState->sendBuffer) { byteToSend = *(spiState->sendBuffer); ++spiState->sendBuffer; } SPI_HAL_WriteData(base, byteToSend); --spiState->remainingSendByteCount; ++spiState->transferredByteCount; /* Only enable the receive interrupt. This should be ok since SPI is a synchronous * protocol, so every RX interrupt we get, we should be ready to send. However, since * the SPI has a shift register and data buffer (for transmit and receive), things may not * be cycle-to-cycle synchronous. To compensate for this, enabling the RX interrupt only * ensures that we do indeed receive data before sending out the next data word. In the * ISR we make sure to first check for the RX data buffer full before checking the TX * data register empty flag. */ SPI_HAL_SetIntMode(base, kSpiRxFullAndModfInt, true); #endif return kStatus_SPI_Success; }