/*! * @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; }
int main (void) { uint8_t loopCount = 0; uint32_t j; uint32_t failCount = 0; uint32_t calculatedBaudRate; spi_master_state_t spiMasterState; spi_master_user_config_t userConfig = { #if FSL_FEATURE_SPI_16BIT_TRANSFERS .bitCount = kSpi8BitMode, #endif .polarity = kSpiClockPolarity_ActiveHigh, .phase = kSpiClockPhase_FirstEdge, .direction = kSpiMsbFirst, .bitsPerSec = TRANSFER_BAUDRATE }; // Init hardware hardware_init(); // Init OSA layer. OSA_Init(); PRINTF("\r\nSPI board to board blocking example"); PRINTF("\r\nThis example run on instance %d", (uint32_t)SPI_MASTER_INSTANCE); PRINTF("\r\nBe sure master's SPI%d and slave's SPI%d are connected\r\n", (uint32_t)SPI_MASTER_INSTANCE, (uint32_t)SPI_MASTER_INSTANCE); // Init and setup baudrate for the master SPI_DRV_MasterInit(SPI_MASTER_INSTANCE, &spiMasterState); SPI_DRV_MasterConfigureBus(SPI_MASTER_INSTANCE, &userConfig, &calculatedBaudRate); // Check if the configuration is correct if (calculatedBaudRate > userConfig.bitsPerSec) { PRINTF("\r**Something failed in the master bus config \r\n"); return -1; } else { PRINTF("\r\nBaud rate in Hz is: %d\r\n", calculatedBaudRate); } while(1) { // Initialize the source buffer for (j = 0; j < TRANSFER_SIZE; j++) { s_spiSourceBuffer[j] = j+loopCount; } // Reset the sink buffer for (j = 0; j < TRANSFER_SIZE; j++) { s_spiSinkBuffer[j] = 0; } // Start transfer data to slave if (SPI_DRV_MasterTransferBlocking(SPI_MASTER_INSTANCE, NULL, s_spiSourceBuffer, NULL, TRANSFER_SIZE, MASTER_TRANSFER_TIMEOUT) == kStatus_SPI_Timeout) { PRINTF("\r\n**Sync transfer timed-out \r\n"); } // Delay sometime to wait slave receive and send back data OSA_TimeDelay(500U); // Start receive data from slave by transmit NULL bytes if (SPI_DRV_MasterTransferBlocking(SPI_MASTER_INSTANCE, NULL, NULL, s_spiSinkBuffer, TRANSFER_SIZE, MASTER_TRANSFER_TIMEOUT) == kStatus_SPI_Timeout) { PRINTF("\r\n**Sync transfer timed-out \r\n"); } // Verify the contents of the master sink buffer // refer to the slave driver for the expected data pattern failCount = 0; // reset failCount variable for (j = 0; j < TRANSFER_SIZE; j++) { if (s_spiSinkBuffer[j] != s_spiSourceBuffer[j]) { failCount++; } } // Print out transmit buffer. PRINTF("\r\nMaster transmit:"); for (j = 0; j < TRANSFER_SIZE; j++) { // Print 16 numbers in a line. if ((j & 0x0F) == 0) { PRINTF("\r\n "); } PRINTF(" %02X", s_spiSourceBuffer[j]); } // Print out receive buffer. PRINTF("\r\nMaster 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]); } if (failCount == 0) { PRINTF("\r\n Spi master transfer succeed! \r\n"); } else { PRINTF("\r\n **failures detected in Spi master transfer! \r\n"); } // Wait for press any key. PRINTF("\r\nPress any key to run again\r\n"); GETCHAR(); loopCount++; } }