void SpiFormat(Spi_t *obj, int8_t bits, int8_t cpol, int8_t cpha, int8_t slave) { spi_clock_polarity_t clockPolarity; spi_clock_phase_t clockPhase; spi_data_bitcount_mode_t bitCount; /* Disable Spi module */ SPI_HAL_Disable(obj->Spi); clockPolarity = ((cpol != 1) ? kSpiClockPolarity_ActiveHigh : kSpiClockPolarity_ActiveLow); clockPhase = ((cpha != 1) ? kSpiClockPhase_FirstEdge : kSpiClockPhase_SecondEdge); bitCount = ((bits != 8) ? kSpi16BitMode : kSpi8BitMode); if (obj->isSlave) { /* Set SPI to master mode */ SPI_HAL_SetMasterSlave(obj->Spi, kSpiSlave); } else { /* Set SPI to master mode */ SPI_HAL_SetMasterSlave(obj->Spi, kSpiMaster); // Set slave select to automatic output mode SPI_HAL_SetSlaveSelectOutputMode(obj->Spi, kSpiSlaveSelect_AutomaticOutput); } SPI_HAL_SetDataFormat(obj->Spi, clockPolarity, clockPhase, kSpiMsbFirst); SPI_HAL_Set8or16BitMode(obj->Spi, bitCount); /* Enable Spi module */ SPI_HAL_Enable(obj->Spi); }
void SpiDeInit(Spi_t *obj) { /* Disable Spi module */ SPI_HAL_Disable(obj->Spi); /* Disable clock for SPI.*/ CLOCK_SYS_DisableSpiClock(obj->instance); GpioInit(&obj->Mosi, obj->Mosi.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0); GpioInit(&obj->Miso, obj->Miso.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_DOWN, 0); GpioInit(&obj->Sclk, obj->Sclk.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0); GpioInit(&obj->Nss, obj->Nss.pin, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1); }
void SpiFrequency(Spi_t *obj, uint32_t hz) { uint32_t spiSourceClock; spiSourceClock = CLOCK_SYS_GetSpiFreq(obj->instance); /* Disable Spi module */ SPI_HAL_Disable(obj->Spi); SPI_HAL_SetBaud(obj->Spi, hz, spiSourceClock); /* Enable Spi module */ SPI_HAL_Enable(obj->Spi); }
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_DmaSlaveStartTransfer * Description : Starts the transfer with information passed. * *END**************************************************************************/ static spi_status_t SPI_DRV_DmaSlaveStartTransfer(uint32_t instance) { spi_dma_slave_state_t * spiState = (spi_dma_slave_state_t *)g_spiStatePtr[instance]; /* For temporarily storing DMA register channel */ void * param; SPI_Type *base = g_spiBase[instance]; uint32_t transferSizeInBytes; /* DMA transfer size in bytes */ /* Initialize s_byteToSend */ s_byteToSend = spiState->dummyPattern; /* If the transfer count is zero, then return immediately. */ if (spiState->remainingSendByteCount == 0) { /* Signal the synchronous completion object if the transfer wasn't async. * Otherwise, when we return the the sync function we'll get stuck in the sync wait loop. */ if (spiState->isSync) { /* Signal the synchronous completion object */ OSA_EventSet(&spiState->event, kSpiDmaTransferDone); } return kStatus_SPI_Success; } /* In order to flush any remaining data in the shift register, disable then enable the SPI */ SPI_HAL_Disable(base); SPI_HAL_Enable(base); /* First, set the DMA transfer size in bytes */ #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (SPI_HAL_Get8or16BitMode(base) == kSpi16BitMode) { transferSizeInBytes = 2; /* If bits/frame > 8, meaning 2 bytes, then the transfer byte count must not be an odd * count. If so, drop the last odd byte. This odd byte will be transferred in when dma * completed */ if (spiState->remainingSendByteCount % 2 != 0) { spiState->remainingSendByteCount ++; spiState->remainingReceiveByteCount --; spiState->hasExtraByte = true; } else { spiState->hasExtraByte = false; } } else { transferSizeInBytes = 1; } #else transferSizeInBytes = 1; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ param = (void *)(instance); /* For DMA callback, set "param" as the SPI instance number */ /* Save information about the transfer for use by the ISR. */ spiState->isTransferInProgress = true; /************************************************************************************ * Set up the RX DMA channel Transfer Control Descriptor (TCD) * Note, if there is no receive buffer (if user passes in NULL), then bypass RX DMA * set up. ************************************************************************************/ /* If no receive buffer then disable incrementing the destination and set the destination * to a temporary location */ if ((spiState->remainingReceiveByteCount > 0) || (spiState->hasExtraByte)) { uint32_t receiveSize = spiState->remainingReceiveByteCount; if ((!spiState->receiveBuffer) || (!spiState->remainingReceiveByteCount)) { if (!spiState->remainingReceiveByteCount) { /* If receive count is 0, always receive 1 frame (2 bytes) */ receiveSize = 2; } /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiState->dmaReceive, kDmaPeripheralToPeripheral, transferSizeInBytes, SPI_HAL_GetDataRegAddr(base), /* src is data register */ (uint32_t)(&s_rxBuffIfNull), /* dest is temporary location */ (uint32_t)(receiveSize)); } else { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiState->dmaReceive, kDmaPeripheralToMemory, transferSizeInBytes, SPI_HAL_GetDataRegAddr(base), /* src is data register */ (uint32_t)(spiState->receiveBuffer), /* dest is rx buffer */ (uint32_t)(receiveSize)); } /* Destination size is only one byte */ DMA_DRV_SetDestTransferSize(&spiState->dmaReceive, 1U); /* Enable the DMA peripheral request */ DMA_DRV_StartChannel(&spiState->dmaReceive); /* Register callback for DMA interrupt */ DMA_DRV_RegisterCallback(&spiState->dmaReceive, SPI_DRV_DmaSlaveCallback, param); } /************************************************************************************ * Set up the TX DMA channel Transfer Control Descriptor (TCD) * Note, if there is no source buffer (if user passes in NULL), then send zeros ************************************************************************************/ /* Per the reference manual, before enabling the SPI transmit DMA request, we first need * to read the status register and then write to the SPI data register. Afterwards, we need * to decrement the sendByteCount and perform other driver maintenance functions. */ /* Read the SPI Status register */ SPI_HAL_IsTxBuffEmptyPending(base); /* Start the transfer by writing the first byte/word to the SPI data register. * If a send buffer was provided, the byte/word comes from there. Otherwise we just send zeros. */ #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (transferSizeInBytes == 2) /* 16-bit transfers for SPI16 module */ { if (spiState->sendBuffer) { s_byteToSend = *(spiState->sendBuffer); SPI_HAL_WriteDataLow(base, s_byteToSend); ++spiState->sendBuffer; s_byteToSend = *(spiState->sendBuffer); SPI_HAL_WriteDataHigh(base, s_byteToSend); ++spiState->sendBuffer; } else /* Else, if no send buffer, write zeros */ { SPI_HAL_WriteDataLow(base, s_byteToSend); SPI_HAL_WriteDataHigh(base, s_byteToSend); } spiState->remainingSendByteCount -= 2; /* Decrement the send byte count by 2 */ } else /* 8-bit transfers for SPI16 module */ { if (spiState->sendBuffer) { s_byteToSend = *(spiState->sendBuffer); ++spiState->sendBuffer; } SPI_HAL_WriteDataLow(base, s_byteToSend); /* If no send buffer, s_byteToSend=0 */ --spiState->remainingSendByteCount; /* Decrement the send byte count for use in DMA setup */ } #else /* For SPI modules that do not support 16-bit transfers */ if (spiState->sendBuffer) { s_byteToSend = *(spiState->sendBuffer); ++spiState->sendBuffer; } SPI_HAL_WriteData(base, s_byteToSend); /* If no send buffer, s_byteToSend=0 */ --spiState->remainingSendByteCount; /* Decrement the send byte count for use in DMA setup */ #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ /* If there are no more bytes to send then return without setting up the TX DMA channel. * Else, set up the TX DMA channel and enable the TX DMA request. */ if (!spiState->remainingSendByteCount) /* No more bytes to send */ { if ((spiState->remainingReceiveByteCount) || (spiState->hasExtraByte)) { /* Enable the RX DMA channel request now */ SPI_HAL_SetRxDmaCmd(base, true); return kStatus_SPI_Success; } else /* If RX DMA chan not setup then enable the interrupt to get the received byte */ { SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); return kStatus_SPI_Success; } } else /* Since there are more bytes to send, set up the TX DMA channel */ { /* If there is a send buffer, data comes from there, else send 0 */ if (spiState->sendBuffer) { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiState->dmaTransmit, kDmaMemoryToPeripheral, transferSizeInBytes, (uint32_t)(spiState->sendBuffer), SPI_HAL_GetDataRegAddr(base), (uint32_t)(spiState->remainingSendByteCount)); } else /* Configure TX DMA channel to send zeros */ { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiState->dmaTransmit, kDmaPeripheralToPeripheral, transferSizeInBytes, (uint32_t)(&s_byteToSend), SPI_HAL_GetDataRegAddr(base), (uint32_t)(spiState->remainingSendByteCount)); } /* Source size is only one byte */ DMA_DRV_SetSourceTransferSize(&spiState->dmaTransmit, 1U); /* Enable the SPI TX DMA Request */ SPI_HAL_SetTxDmaCmd(base, true); /* Enable the SPI RX DMA request also. */ SPI_HAL_SetRxDmaCmd(base, true); /* Enable the DMA peripheral request */ DMA_DRV_StartChannel(&spiState->dmaTransmit); } return kStatus_SPI_Success; }
/*! * @brief Initiate (start) a transfer using DMA. This is not a public API as it is called from * other driver functions */ spi_status_t SPI_DRV_DmaMasterStartTransfer(uint32_t instance, const spi_dma_master_user_config_t * device) { /* instantiate local variable of type spi_dma_master_state_t and point to global state */ spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance]; /* For temporarily storing DMA register channel */ void * param; uint32_t calculatedBaudRate; SPI_Type *base = g_spiBase[instance]; uint32_t transferSizeInBytes; /* DMA transfer size in bytes */ /* Initialize s_byteToSend */ s_byteToSend = 0; /* If the transfer count is zero, then return immediately.*/ if (spiDmaState->remainingSendByteCount == 0) { /* Signal the synchronous completion object if the transfer wasn't async. * Otherwise, when we return the the sync function we'll get stuck in the sync wait loop. */ if (spiDmaState->isTransferBlocking) { OSA_SemaPost(&spiDmaState->irqSync); } return kStatus_SPI_Success; } /* Configure bus for this device. If NULL is passed, we assume the caller has * preconfigured the bus using SPI_DRV_DmaMasterConfigureBus(). * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate * then they can call this function separately. */ if (device) { SPI_DRV_DmaMasterConfigureBus(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 /* Check the transfer byte count. If bits/frame > 8, meaning 2 bytes, and if * the transfer byte count is an odd count we'll have to round down the RX transfer byte count * to the next lowest even number by one and assert a flag to indicate in the interrupt handler * that we take care of sending and receiving this last byte. We'll round up TX byte count. */ if (SPI_HAL_Get8or16BitMode(base) == kSpi16BitMode) /* Applies to 16-bit transfers */ { /* Odd byte count for 16-bit transfers, set the extraByte flag */ if (spiDmaState->remainingSendByteCount & 1UL) /* If odd byte count */ { transferSizeInBytes = 2; /* Set transfer size to two bytes for the DMA operation */ spiDmaState->extraByte = true; /* Set the extraByte flag */ /* Round up TX byte count so when DMA completes, all data would've been sent */ spiDmaState->remainingSendByteCount += 1U; /* Round down RX byte count which means at the end of the RX DMA transfer, we'll need * to set up an interrupt to get the last byte. */ spiDmaState->remainingReceiveByteCount &= ~1U; /* Store the transfer byte count to the run-time state struct * for later use in the interrupt handler. */ spiDmaState->transferByteCnt = spiDmaState->remainingSendByteCount; } /* Even byte count for 16-bit transfers, clear the extraByte flag */ else { transferSizeInBytes = 2; /* Set transfer size to two bytes for the DMA operation */ spiDmaState->extraByte = false; /* Clear the extraByte flag */ } } else /* For 8-bit transfers */ { transferSizeInBytes = 1; spiDmaState->extraByte = false; } #else transferSizeInBytes = 1; #endif param = (void *)(instance); /* For DMA callback, set "param" as the SPI instance number */ /* Check that we're not busy.*/ if (spiDmaState->isTransferInProgress) { return kStatus_SPI_Busy; } /* Save information about the transfer for use by the ISR.*/ spiDmaState->isTransferInProgress = true; /************************************************************************************ * Set up the RX DMA channel Transfer Control Descriptor (TCD) * Note, if there is no receive byte count, then bypass RX DMA set up. ***********************************************************************************/ if (spiDmaState->remainingReceiveByteCount) { /* If no receive buffer then disable incrementing the destination and set the destination * to a temporary location */ if (!spiDmaState->receiveBuffer) { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiDmaState->dmaReceive, kDmaPeripheralToPeripheral, transferSizeInBytes, SPI_HAL_GetDataRegAddr(base), /* src is data register */ (uint32_t)(&s_rxBuffIfNull), /* dest is temporary location */ (uint32_t)(spiDmaState->remainingReceiveByteCount)); } else { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiDmaState->dmaReceive, kDmaPeripheralToMemory, transferSizeInBytes, SPI_HAL_GetDataRegAddr(base), /* src is data register */ (uint32_t)(spiDmaState->receiveBuffer),/* dest is rx buffer */ (uint32_t)(spiDmaState->remainingReceiveByteCount)); } /* Dest size is always 1 byte on each transfer */ DMA_DRV_SetDestTransferSize(&spiDmaState->dmaReceive, 1U); /* Enable the DMA peripheral request */ DMA_DRV_StartChannel(&spiDmaState->dmaReceive); /* Register callback for DMA interrupt */ DMA_DRV_RegisterCallback(&spiDmaState->dmaReceive, SPI_DRV_DmaMasterCallback, param); } /************************************************************************************ * Set up the TX DMA channel Transfer Control Descriptor (TCD) * Note, if there is no source buffer (if user passes in NULL), then send zeros ***********************************************************************************/ /* Per the reference manual, before enabling the SPI transmit DMA request, we first need * to read the status register and then write to the SPI data register. Afterwards, we need * to decrement the sendByteCount and perform other driver maintenance functions. */ /* Read the SPI Status register */ SPI_HAL_IsTxBuffEmptyPending(base); /* Start the transfer by writing the first byte/word to the SPI data register. * If a send buffer was provided, the byte/word comes from there. Otherwise we just send zeros. * This will cause an immeidate transfer which in some cases may cause the RX DMA channel to * complete before having the chance to completely set up the TX DMA channel. As such, we'll * enable the RX DMA channel last. */ #if FSL_FEATURE_SPI_16BIT_TRANSFERS if (transferSizeInBytes == 2) /* 16-bit transfers for SPI16 module */ { if (spiDmaState->sendBuffer) { s_byteToSend = *(spiDmaState->sendBuffer); SPI_HAL_WriteDataLow(base, s_byteToSend); ++spiDmaState->sendBuffer; s_byteToSend = *(spiDmaState->sendBuffer); SPI_HAL_WriteDataHigh(base, s_byteToSend); ++spiDmaState->sendBuffer; } else /* Else, if no send buffer, write zeros */ { SPI_HAL_WriteDataLow(base, s_byteToSend); SPI_HAL_WriteDataHigh(base, s_byteToSend); } spiDmaState->remainingSendByteCount -= 2; /* Decrement the send byte count by 2 */ } else /* 8-bit transfers for SPI16 module */ { if (spiDmaState->sendBuffer) { s_byteToSend = *(spiDmaState->sendBuffer); ++spiDmaState->sendBuffer; } SPI_HAL_WriteDataLow(base, s_byteToSend); /* If no send buffer, s_byteToSend=0 */ --spiDmaState->remainingSendByteCount; /* Decrement the send byte count */ } #else /* For SPI modules that do not support 16-bit transfers */ if (spiDmaState->sendBuffer) { s_byteToSend = *(spiDmaState->sendBuffer); ++spiDmaState->sendBuffer; } SPI_HAL_WriteData(base, s_byteToSend); /* If no send buffer, s_byteToSend=0 */ --spiDmaState->remainingSendByteCount; /* Decrement the send byte count */ #endif /* If there are no more bytes to send then return without setting up the TX DMA channel * and let the receive DMA channel complete the transfer if the RX DMA channel was setup. * If the RX DMA channel was not set up (due to odd byte count of 1 in 16-bit mode), enable * the interrupt to get the received byte. */ if (!spiDmaState->remainingSendByteCount) /* No more bytes to send */ { if (spiDmaState->remainingReceiveByteCount) { /* Enable the RX DMA channel request now */ SPI_HAL_SetRxDmaCmd(base, true); return kStatus_SPI_Success; } else /* If RX DMA chan not setup then enable the interrupt to get the received byte */ { SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true); return kStatus_SPI_Success; } } /* Else, since there are more bytes to send, go ahead and set up the TX DMA channel */ else { /* If there is a send buffer, data comes from there, else send 0 */ if (spiDmaState->sendBuffer) { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiDmaState->dmaTransmit, kDmaMemoryToPeripheral, transferSizeInBytes, (uint32_t)(spiDmaState->sendBuffer), SPI_HAL_GetDataRegAddr(base), (uint32_t)(spiDmaState->remainingSendByteCount)); } else /* Configure TX DMA channel to send zeros */ { /* Set up this channel's control which includes enabling the DMA interrupt */ DMA_DRV_ConfigTransfer(&spiDmaState->dmaTransmit, kDmaPeripheralToPeripheral, transferSizeInBytes, (uint32_t)(&s_byteToSend), SPI_HAL_GetDataRegAddr(base), (uint32_t)(spiDmaState->remainingSendByteCount)); } /* Source size is only one byte on each transfer */ DMA_DRV_SetSourceTransferSize(&spiDmaState->dmaTransmit, 1U); /* Enable the SPI TX DMA Request */ SPI_HAL_SetTxDmaCmd(base, true); /* Enable the SPI RX DMA Request after the TX DMA request is enabled. This is done to * make sure that the RX DMA channel does not end prematurely before we've completely set * up the TX DMA channel since part of the TX DMA set up involves placing 1 or 2 bytes of * data into the send data register which causes an immediate transfer. */ SPI_HAL_SetRxDmaCmd(base, true); /* Enable the DMA peripheral request */ DMA_DRV_StartChannel(&spiDmaState->dmaTransmit); } 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; }
/*! * @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]); } } }