/*FUNCTION********************************************************************** * * Function Name : SPI_DRV_DmaSlaveIRQHandler * Description : Interrupt handler for SPI master mode. * This handler is used when the hasExtraByte flag is set to retrieve the received last byte. * *END**************************************************************************/ void SPI_DRV_DmaSlaveIRQHandler(uint32_t instance) { #if FSL_FEATURE_SPI_16BIT_TRANSFERS /* instantiate local variable of type spi_master_state_t and point to global state */ spi_dma_slave_state_t * spiDmaState = (spi_dma_slave_state_t *)g_spiStatePtr[instance]; SPI_Type *base = g_spiBase[instance]; /* If the SPI module contains a FIFO (and if it is enabled), check the FIFO empty flag */ if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base))) { if (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0) { /* If there is a receive buffer, copy the final byte from the SPI data register * to the receive buffer */ if (spiDmaState->receiveBuffer) { spiDmaState->receiveBuffer[spiDmaState->remainingReceiveByteCount] = SPI_HAL_ReadDataLow(base); } /* Else, read out the data register and throw away the bytes read */ else { /* Read and throw away the lower data buffer to clear it out */ s_rxBuffIfNull = SPI_HAL_ReadDataLow(base); } /* Read and throw away the upper data buffer to clear it out */ s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base); SPI_DRV_DmaSlaveCompleteTransfer(instance); } } else /* Check the read pending flag */ { if (SPI_HAL_IsReadBuffFullPending(base) == 1) { /* If there is a receive buffer, copy the final byte from the SPI data register * to the receive buffer */ if (spiDmaState->receiveBuffer) { spiDmaState->receiveBuffer[spiDmaState->remainingReceiveByteCount] = SPI_HAL_ReadDataLow(base); } /* Else, read out the data register and throw away the bytes read */ else { /* Read and throw away the lower data buffer to clear it out */ s_rxBuffIfNull = SPI_HAL_ReadDataLow(base); } /* Read and throw away the upper data buffer to clear it out */ s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base); SPI_DRV_DmaSlaveCompleteTransfer(instance); } } #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ }
uint16_t SpiInOut(Spi_t *obj, uint16_t outData) { uint16_t data; if ((obj == NULL) || (obj->Spi) == NULL) { while (1) { } } // Disable module to clear the shift register SPI_HAL_Disable(obj->Spi); SPI_HAL_Enable(obj->Spi); SPI_HAL_WriteDataBlocking(obj->Spi, kSpi8BitMode, 0, (uint8_t)(outData & 0xFF)); // Wait for slave send data back while (SPI_HAL_IsReadBuffFullPending(obj->Spi) == 0) { } data = SPI_HAL_ReadDataLow(obj->Spi); return data; }
/*FUNCTION********************************************************************** * * Function Name : SPI_DRV_DmaMasterCallback * Description : This function is called when the DMA generates an interrupt. * The DMA generates an interrupt when the channel is "done", meaning that the * expected number of bytes have been transferred. When the interrupt occurs, * the DMA will jump to this callback as it was registered in the DMA register * callback service function. The user will defined their own callback function * to take whatever action they deem necessary for handling the end of a transfer. * For example, the user may simply want their callback function to set a global * flag to indicate that the transfer is complete. The user defined callback * is passed in through the "param" parameter. * The parameter chanStatus is currently not used. * *END**************************************************************************/ void SPI_DRV_DmaMasterCallback(void *param, dma_channel_status_t chanStatus) { uint32_t instance = (uint32_t)(param); /* instantiate local variable of type spi_master_state_t and point to global state */ spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance]; SPI_Type *base = g_spiBase[instance]; /* If the extraByte flag was set, need to enable the TX empty interrupt to get the last byte */ if (spiDmaState->extraByte) { SPI_HAL_SetTxDmaCmd(base, false); /* If the TX buffer is already empty then it may not generate an interrupt so soon * after the TX DMA is disabled, therefore read the RX data and put into RX buffer. */ if (SPI_HAL_GetIntStatusFlag(base, kSpiTxBufferEmptyFlag)) { #if FSL_FEATURE_SPI_16BIT_TRANSFERS /* If the SPI module contains a FIFO (and if it is enabled), check the FIFO empty flag */ if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base))) { /* Wait till the rx buffer has data */ while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 1) {} } else /* Check the read pending flag */ { /* Wait till the rx buffer has data */ while (SPI_HAL_IsReadBuffFullPending(base) == 0) {} } /* If there is a receive buffer, copy the final byte from the SPI data register * to the receive buffer */ if (spiDmaState->receiveBuffer) { spiDmaState->receiveBuffer[spiDmaState->transferByteCnt-2] = SPI_HAL_ReadDataLow(base); } /* Else, read out the data register and throw away the bytes read */ else { /* Read and throw away the lower data buffer to clear it out */ s_rxBuffIfNull = SPI_HAL_ReadDataLow(base); } /* Read and throw away the upper data buffer to clear it out */ s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base); SPI_DRV_DmaMasterCompleteTransfer(instance); #endif } else { /* Else, if the TX buffer is not empty, enable the interrupt and handle the * receive in the ISR */ SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); } } else /* If no extra byte is needing to be receive, complete the transfer */ { SPI_DRV_DmaMasterCompleteTransfer(instance); } }
/*FUNCTION********************************************************************** * * Function Name : SPI_DRV_MasterIRQHandler * Description : Interrupt handler for SPI master mode. * This handler uses the buffers stored in the spi_master_state_t structs to transfer data. * *END**************************************************************************/ void SPI_DRV_MasterIRQHandler(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]; /* Exit the ISR if no transfer is happening for this instance.*/ if (!spiState->isTransferInProgress) { return; } /* RECEIVE IRQ handler: Check read buffer only if there are remaining bytes to read. */ if (spiState->remainingReceiveByteCount) { #if FSL_FEATURE_SPI_16BIT_TRANSFERS uint8_t byteReceivedLow, byteReceivedHigh; spi_data_bitcount_mode_t bitCntRx = SPI_HAL_Get8or16BitMode(base); /* If the SPI module contains a FIFO (and if it's enabled), drain the FIFO until it is empty * or until the remainingSendByteCount reaches 0. */ if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base))) { /* Clear the RX near full interrupt */ SPI_HAL_ClearFifoIntUsingBitWrite(base, kSpiRxNearFullClearInt); /* Architectural note: When developing the RX FIFO drain code, it was found that to * achieve more efficient run-time performance, it was better to first check the * bits/frame setting and then proceed with the FIFO fill management process, rather * than to clutter the drain process with continual checks of the bits/frame setting. */ /* Optimized for bit count = 16 with FIFO support */ if (bitCntRx == kSpi16BitMode) { /* Do this while the RX FIFO is not empty */ while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0) { /* Read the bytes from the RX FIFO */ byteReceivedLow = SPI_HAL_ReadDataLow(base); byteReceivedHigh = SPI_HAL_ReadDataHigh(base); /* Store read bytes into rx buffer only if a buffer pointer was provided */ if (spiState->receiveBuffer) { *spiState->receiveBuffer = byteReceivedLow; ++spiState->receiveBuffer; /* If the extraByte flag is set and these are the last 2 bytes, then skip. * This will avoid over-writing the rx buffer with another un-needed byte. */ if (!((spiState->extraByte) && (spiState->remainingReceiveByteCount == 2))) { *spiState->receiveBuffer = byteReceivedHigh; ++spiState->receiveBuffer; } } spiState->remainingReceiveByteCount -= 2; /* decrement the rx byte count by 2 */ /* If there is no more data to receive, break */ if (spiState->remainingReceiveByteCount == 0) { break; } } } /* Optimized for bit count = 8 with FIFO support */ else { while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0) { /* Read the bytes from the RX FIFO */ byteReceivedLow = SPI_HAL_ReadDataLow(base); /* Store read bytes into rx buffer only if a buffer pointer was provided */ if (spiState->receiveBuffer) { *spiState->receiveBuffer = byteReceivedLow; ++spiState->receiveBuffer; } --spiState->remainingReceiveByteCount; /* decrement the rx byte count by 1 */ /* If there is no more data to receive, break */ if (spiState->remainingReceiveByteCount == 0) { break; } } } /* 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. */ if (spiState->remainingReceiveByteCount < g_spiFifoSize[instance]) { SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); /* TX FIFO empty interrupt */ } } /* For SPI modules that do not have a FIFO (or if disabled), but have 16-bit transfer * capability */ else { if (SPI_HAL_IsReadBuffFullPending(base)) { /* For 16-bit transfers w/o FIFO support */ if (bitCntRx == kSpi16BitMode) { /* Read the bytes from the RX FIFO */ byteReceivedLow = SPI_HAL_ReadDataLow(base); byteReceivedHigh = SPI_HAL_ReadDataHigh(base); /* Store read bytes into rx buffer only if a buffer pointer was provided */ if (spiState->receiveBuffer) { *spiState->receiveBuffer = byteReceivedLow; ++spiState->receiveBuffer; /* If the extraByte flag is set and these are the last 2 bytes, then skip. * This will avoid over-writing the rx buffer with another un-needed byte. */ if (!((spiState->extraByte) && (spiState->remainingReceiveByteCount == 2))) { *spiState->receiveBuffer = byteReceivedHigh; ++spiState->receiveBuffer; } } spiState->remainingReceiveByteCount -= 2; /* decrement the rx byte count by 2 */ } /* For 8-bit transfers w/o FIFO support */ else { /* Read the bytes from the RX FIFO */ byteReceivedLow = SPI_HAL_ReadDataLow(base); /* Store read bytes into rx buffer only if a buffer pointer was provided */ if (spiState->receiveBuffer) { *spiState->receiveBuffer = byteReceivedLow; ++spiState->receiveBuffer; } --spiState->remainingReceiveByteCount; /* decrement the rx byte count by 1 */ } } } #else /* For SPI modules that do not support 16-bit transfers and don't have FIFO */ uint8_t byteReceived; /* For SPI modules without 16-bit transfer capability or FIFO support */ if (SPI_HAL_IsReadBuffFullPending(base)) { /* Read the bytes from the RX FIFO */ byteReceived = SPI_HAL_ReadData(base); /* Store read bytes into rx buffer only if a buffer pointer was provided */ if (spiState->receiveBuffer) { *spiState->receiveBuffer = byteReceived; ++spiState->receiveBuffer; } --spiState->remainingReceiveByteCount; /* decrement the rx byte count by 1 */ } #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ } /* TRANSMIT IRQ handler * Check write buffer. We always have to send a byte in order to keep the transfer * moving. So if the caller didn't provide a send buffer, we just send a zero byte. */ uint8_t byteToSend = 0; if (spiState->remainingSendByteCount) { #if FSL_FEATURE_SPI_16BIT_TRANSFERS uint8_t byteToSendLow = 0; uint8_t byteToSendHigh = 0; spi_data_bitcount_mode_t bitCntTx = SPI_HAL_Get8or16BitMode(base); /* If SPI module has a FIFO and if it is enabled */ if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base))) { if (SPI_HAL_GetFifoStatusFlag(base, kSpiTxNearEmpty)) { /* Fill of the TX FIFO with ongoing data */ SPI_DRV_MasterFillupTxFifo(instance); } } else { if (SPI_HAL_IsTxBuffEmptyPending(base)) { if (bitCntTx == kSpi16BitMode) { if (spiState->sendBuffer) { byteToSendLow = *(spiState->sendBuffer); ++spiState->sendBuffer; 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 */ } else /* SPI configured for 8-bit transfers */ { if (spiState->sendBuffer) { byteToSend = *(spiState->sendBuffer); ++spiState->sendBuffer; } SPI_HAL_WriteDataLow(base, byteToSend); --spiState->remainingSendByteCount; ++spiState->transferredByteCount; } } } #else /* For SPI modules that do not support 16-bit transfers */ if (SPI_HAL_IsTxBuffEmptyPending(base)) { if (spiState->sendBuffer) { byteToSend = *(spiState->sendBuffer); ++spiState->sendBuffer; } SPI_HAL_WriteData(base, byteToSend); --spiState->remainingSendByteCount; ++spiState->transferredByteCount; } #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ } /* Check if we're done with this transfer. The transfer is complete when all of the * expected data is received. */ if ((spiState->remainingSendByteCount == 0) && (spiState->remainingReceiveByteCount == 0)) { /* Complete the transfer. This disables the interrupts, so we don't wind up in * the ISR again. */ SPI_DRV_MasterCompleteTransfer(instance); } }
/*! * @brief SPI slave polling. * * This function sends back received buffer from master through SPI interface. */ int main (void) { uint32_t j; SPI_Type * spiBaseAddr = g_spiBase[SPI_SLAVE_INSTANCE]; // init the hardware, this also sets up up the SPI pins for each specific SoC hardware_init(); OSA_Init(); PRINTF("\r\nSPI board to board polling example"); PRINTF("\r\nThis example run on instance %d", (uint32_t)SPI_SLAVE_INSTANCE); PRINTF("\r\nBe sure master's SPI%d and slave's SPI%d are connected", (uint32_t)SPI_SLAVE_INSTANCE, (uint32_t)SPI_SLAVE_INSTANCE); // Enable clock for SPI CLOCK_SYS_EnableSpiClock(SPI_SLAVE_INSTANCE); // Reset the SPI module to its default settings including disabling SPI SPI_HAL_Init(spiBaseAddr); // Set SPI to slave mode SPI_HAL_SetMasterSlave(spiBaseAddr, kSpiSlave); // Set the SPI pin mode to normal mode SPI_HAL_SetPinMode(spiBaseAddr, kSpiPinMode_Normal); #if FSL_FEATURE_SPI_FIFO_SIZE if (g_spiFifoSize[SPI_SLAVE_INSTANCE] != 0) { // If SPI module contains a FIFO, disable it and set watermarks to half full/empty SPI_HAL_SetFifoMode(spiBaseAddr, false, kSpiTxFifoOneHalfEmpty, kSpiRxFifoOneHalfFull); } #endif //USER CONFIGURABLE OPTION FOR 8 or 16-BIT MODE (if applicable) #if FSL_FEATURE_SPI_16BIT_TRANSFERS SPI_HAL_Set8or16BitMode(spiBaseAddr, kSpi8BitMode); #endif // SPI system Enable SPI_HAL_Enable(spiBaseAddr); // Setup format as same as master SPI_HAL_SetDataFormat(spiBaseAddr, kSpiClockPolarity_ActiveHigh, kSpiClockPhase_FirstEdge, kSpiMsbFirst); while(1) { PRINTF("\r\nSlave example is running...\r\n"); // Reset the sink buffer for (j = 0; j < TRANSFER_SIZE; j++) { s_spiSinkBuffer[j] = 0; } SPI_HAL_Disable(spiBaseAddr); SPI_HAL_Enable(spiBaseAddr); // Disable module to clear shift register for (j = 0; j <TRANSFER_SIZE; j++) { // Check if data received while(SPI_HAL_IsReadBuffFullPending(spiBaseAddr)==0){} #if FSL_FEATURE_SPI_16BIT_TRANSFERS // Read data from data register s_spiSinkBuffer[j] = SPI_HAL_ReadDataLow(spiBaseAddr); #else s_spiSinkBuffer[j] = SPI_HAL_ReadData(spiBaseAddr); #endif } // Disable module to clear shift register SPI_HAL_Disable(spiBaseAddr); SPI_HAL_Enable(spiBaseAddr); // Send data back to master for (j = 0; j <TRANSFER_SIZE; j++) { #if FSL_FEATURE_SPI_16BIT_TRANSFERS SPI_HAL_WriteDataBlocking(spiBaseAddr, kSpi8BitMode, 0, s_spiSinkBuffer[j]); #else SPI_HAL_WriteDataBlocking(spiBaseAddr, s_spiSinkBuffer[j]); #endif } // Print out receive buffer PRINTF("\r\nSlave receive:"); for (j = 0; j < TRANSFER_SIZE; j++) { // Print 16 numbers in a line. if ((j & 0x0F) == 0) { PRINTF("\r\n "); } PRINTF(" %02X", s_spiSinkBuffer[j]); } } }