This section describes the programming interface of the SPI slave mode peripheral driver.
SPI Overview
The SPI slave peripheral driver provides an easy way to use an SPI peripheral in slave mode. It supports transferring buffers of data with a single function call. When the SPI is configured for slave mode operations, it must first be set up to perform a transfer and then wait for the master to initiate the transfer. The driver is separated into two implementations: interrupt-driven and DMA-driven. The interrupt-driven driver uses interrupts to alert the CPU that the SPI module needs to service the SPI data transmit and receive operations. The DMA-driven driver uses the DMA module to transfer data between the buffers located in memory and the SPI module transmit/receive buffers/FIFOs. Note that some SPI modules may not support DMA transfers and this is distinguished in the driver using the feature name "FSL_FEATURE_SPI_HAS_DMA_SUPPORT". The interrupt-driven and DMA-driven driver APIs are distinguished by the keyword "dma" in the source file name and by the keyword "Dma" in the API name. Each set of drivers have the same API functionality and are described in the following sections. Note that the DMA-driven driver also uses interrupts to alert the CPU that the DMA has completed its transfer or that one final piece of data still needs to be received which is handled by the IRQ handler in the DMA-driven driver. In both the interrupt and DMA drivers, the SPI module interrupts are enabled in the NVIC. In addition, the DMA-driven driver requests channels from the DMA module. Also, subsequent sections refer to either set of drivers simply as the "SPI slave driver" when discussing items that pertain to either driver. Note, when using the DMA-driven SPI driver, initialize the DMA module. An example is shown later under the Initialization section. The following is a basic step-by-step overview of how to setup the SPI for SPI slave mode operations. For API specific examples, refer to the examples below. The following uses the interrupt-driven APIs and a blocking transfer to illustrate a high-level step-by-step usage. The usage of DMA driver is similar to interrupt-driven driver. Keep in mind that using interrupt and DMA drivers in the same runtime application is not normally recommended because the SPI interrupt handler needs to be changed. The interrupt driver calls SPI_DRV_IRQHandler() and DMA driver calls SPI_DRV_DmaIRQHandler(). Refer to files fsl_spi_irq.c and fsl_spi_dma_irq.c for an example of these function calls.
Note that it is not normally recommended to mix interrupt and DMA-driven drivers in the same application. However, should the user decide to do so, they can separately set up and initialize another instance for DMA operations. The user can also de-init the current interrupt-driven SPI instance and re-initialize it for DMA operations. Note that since the DMA-driven driver also uses interrupts, the user must take care to direct the IRQ handler from the vector table to the desired driver's IRQ handler. Refer to files fsl_spi_irq.c and fsl_spi_dma_irq.c for examples on how to re-direct the IRQ handlers from the vector table to the interrupt-driven and DMA-driven driver IRQ handlers. Such files need to be included in the applications project in order to direct the SPI interrupt vectors to the proper IRQ handlers. There are also two other files, fsl_spi_shared_function.c and fsl_spi_dma_shared_function.c that direct the interrupts from the vector table to the appropriate master or slave driver interrupt handler by checking the SPI mode via the HAL function SPI_HAL_IsMaster(baseAddr).
SPI Runtime state of the SPI slave driver
The SPI slave driver uses a run-time state structure to track the ongoing data transfers. The state structure for the interrupt-driven driver is called spi_slave_state_t while the state structure for the DMA-driven driver is called spi_dma_slave_state_t. The structure holds data that the SPI slave peripheral driver uses to communicate between the transfer function and the interrupt handler and other driver functions. The interrupt handler also uses this information to keep track of its progress. The user is only responsible to pass the memory for this run-time state structure and the SPI slave driver fills out the members.
SPI User configuration structures
The SPI slave driver uses instances of the user configuration structure for the SPI slave driver. The user configuration structure for the interrupt-driven driver is called spi_slave_user_config_t while the user configuration structure for the DMA-driven driver is called spi_dma_slave_user_config_t. For this reason, the user can configure the most common settings of the SPI peripheral with a single function call.
SPI Setup and Initialization
To initialize the SPI slave driver, first create and fill in a spi_slave_user_config_t structure for the interrupt-driven driver or spi_dma_slave_user_config_t structure for the DMA-driven driver. This structure defines the data format settings for the SPI peripheral. The structure is not required after the driver is initialized and can be allocated on the stack. The user also must pass the memory for the run-time state structure. Note that some SPI modules may not support DMA transfers and this is distinguished in the driver using the feature name "FSL_FEATURE_SPI_HAS_DMA_SUPPORT".
This is an example code to initialize and configure the driver for interrupt and DMA operations:
uint32_t instance = 1;
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
#endif
#if FSL_FEATURE_SPI_HAS_DMA_SUPPORT
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
#endif
#endif
SPI Blocking and non-blocking
The SPI slave driver has two types of transfer functions, blocking and non-blocking calls. With non-blocking calls, the user starts the transfer and then waits for event flags are set. kSpiTransferDone indicates the transmission and reception are done. With the blocking call, the function only returns after the related process is all done.
Hear is an example of blocking and non-blocking call (interrupt-driven)
sendBuffer,
receiveBuffer,
transferSize,
10000);
sendBuffer,
receiveBuffer,
transferSize);
Additionally, some SPI modules support DMA transfers. To use the SPI with DMA, see the following example:
sendBuffer,
receiveBuffer,
transferSize,
10000);
sendBuffer,
receiveBuffer,
transferSize);
SPI De-initialization
To de-initialize and shut down the SPI module, call the function:
|
SPI_Type *const | g_spiBase [SPI_INSTANCE_COUNT] |
| Table of base pointers for SPI instances. More...
|
|
const IRQn_Type | g_spiIrqId [SPI_INSTANCE_COUNT] |
| Table to save SPI IRQ enumeration numbers defined in CMSIS header file. More...
|
|
SPI_Type *const | g_spiBase [SPI_INSTANCE_COUNT] |
| Table of base pointers for SPI instances. More...
|
|
const IRQn_Type | g_spiIrqId [SPI_INSTANCE_COUNT] |
| Table to save SPI IRQ enumeration numbers defined in the CMSIS header file. More...
|
|
struct spi_dma_slave_user_config_t |
struct spi_dma_slave_state_t |
This structure holds data that is used by the SPI slave peripheral driver to communicate between the transfer function and the interrupt handler. The user needs to pass in the memory for this structure and the driver fills out the members.
volatile bool spi_dma_slave_state_t::isTransferInProgress |
volatile int32_t spi_dma_slave_state_t::remainingSendByteCount |
volatile int32_t spi_dma_slave_state_t::remainingReceiveByteCount |
volatile int32_t spi_dma_slave_state_t::transferredByteCount |
struct spi_slave_user_config_t |
This structure holds data that is used by the SPI slave peripheral driver to communicate between the transfer function and the interrupt handler. The user needs to pass in the memory for this structure and the driver fills out the members.
volatile bool spi_slave_state_t::isTransferInProgress |
volatile int32_t spi_slave_state_t::remainingSendByteCount |
volatile int32_t spi_slave_state_t::remainingReceiveByteCount |
volatile int32_t spi_slave_state_t::transferredByteCount |
This function un-gates the clock to the SPI module, initializes the SPI for slave mode. Once initialized, the SPI module is configured in slave mode and user can start transmit, receive data by calls send, receive, transfer functions. This function indicates SPI slave uses an interrupt mechanism.
- Parameters
-
instance | The instance number of the SPI peripheral. |
spiState | The pointer to the SPI slave driver state structure. |
slaveConfig | The configuration structure spi_slave_user_config_t which configures the data bus format. |
- Returns
- An error code or kStatus_SPI_Success.
Disables the SPI module, gates its clock, change SPI slave driver state to NonInit for SPI slave module which is initialized with interrupt mechanism. After de-initialized, user can re-initialize SPI slave module with other mechanisms.
- Parameters
-
instance | The instance number of the SPI peripheral. |
- Returns
- kStatus_SPI_Success indicating successful de-initialization
spi_status_t SPI_DRV_DmaSlaveTransferBlocking |
( |
uint32_t |
instance, |
|
|
const uint8_t * |
sendBuffer, |
|
|
uint8_t * |
receiveBuffer, |
|
|
uint32_t |
transferByteCount, |
|
|
uint32_t |
timeout |
|
) |
| |
This function check driver status, mechanism and transmit/receive data through SPI bus. If sendBuffer is NULL, transmit process is ignored. If the receiveBuffer is NULL, the receive process is ignored. If both the receiveBuffer and the sendBuffer are available, the transmit and the receive progress are processed. If only the receiveBuffer available, the receive is processed. Otherwise, the transmit is processed. This function returns when its processes are completed. This function uses interrupt mechanism.
- Parameters
-
instance | The instance number of SPI peripheral |
sendBuffer | The pointer to data that user wants to transmit. |
receiveBuffer | The pointer to data that user wants to store received data. |
transferByteCount | The number of bytes to send and receive. |
timeout | The maximum number of milliseconds that function waits before timed out reached. |
- Returns
- kStatus_SPI_Success if driver starts to send/receive data successfully. kStatus_SPI_Error if driver is error and needs to clean error. kStatus_SPI_Busy if driver is receiving/transmitting data and not available. kStatus_SPI_Timeout if time out reached while transferring is in progress.
spi_status_t SPI_DRV_DmaSlaveTransfer |
( |
uint32_t |
instance, |
|
|
const uint8_t * |
sendBuffer, |
|
|
uint8_t * |
receiveBuffer, |
|
|
uint32_t |
transferByteCount |
|
) |
| |
This function checks the driver status then set buffer pointers to receive and transmit SPI data. If the sendBuffer is NULL, the transmit process is ignored. If the receiveBuffer is NULL, the receive process is ignored. If both the receiveBuffer and the sendBuffer available, transfer is done when the kDspiTxDone and kDspiRxDone are set. If only the receiveBuffer is available, the transfer is done when the kDspiRxDone flag is set. Otherwise, the transfer is done when the kDspiTxDone was set. This function uses an interrupt mechanism.
- Parameters
-
instance | The instance number of SPI peripheral |
sendBuffer | The pointer to data that user wants to transmit. |
receiveBuffer | The pointer to data that user wants to store received data. |
transferByteCount | The number of bytes to send and receive. |
- Returns
- kStatus_SPI_Success if driver starts to send/receive data successfully. kStatus_SPI_Error if driver is error and needs to clean error. kStatus_SPI_Busy if driver is receiving/transmitting data and not available.
spi_status_t SPI_DRV_DmaSlaveAbortTransfer |
( |
uint32_t |
instance | ) |
|
This function stops the transfer which was started by the SPI_DRV_SlaveTransfer() function.
- Parameters
-
instance | The instance number of SPI peripheral |
- Returns
- kStatus_SPI_Success if everything is OK. kStatus_SPI_InvalidMechanism if the current transaction does not use interrupt mechanism.
spi_status_t SPI_DRV_DmaSlaveGetTransferStatus |
( |
uint32_t |
instance, |
|
|
uint32_t * |
framesTransferred |
|
) |
| |
When performing an a-sync transfer, the user can call this function to ascertain the state of the current transfer: in progress (or busy) or complete (success). In addition, if the transfer is still in progress, the user can get the number of words that have been transferred up to now.
- Parameters
-
instance | The instance number of the SPI peripheral. |
framesTransferred | Pointer to value that is filled in with the number of frames that have been sent in the active transfer. A frame is defined as the number of bits per frame. |
- Returns
- kStatus_SPI_Success The transfer has completed successfully, or kStatus_SPI_Busy The transfer is still in progress. framesTransferred is filled with the number of words that have been transferred so far.
void SPI_DRV_DmaSlaveIRQHandler |
( |
uint32_t |
instance | ) |
|
This handler is used when the hasExtraByte flag is set to retrieve the received last byte.
- Parameters
-
instance | The instance number of the SPI peripheral. |
This function un-gates the clock to the SPI module, initializes the SPI for slave mode. After it is initialized, the SPI module is configured in slave mode and the user can start transmitting and receiving data by calling send, receive, and transfer functions. This function indicates SPI slave uses an interrupt mechanism.
- Parameters
-
instance | The instance number of the SPI peripheral. |
spiState | The pointer to the SPI slave driver state structure. |
slaveConfig | The configuration structure spi_slave_user_config_t which configures the data bus format. |
- Returns
- An error code or kStatus_SPI_Success.
Disables the SPI module, gates its clock, and changes the SPI slave driver state to NonInit for the SPI slave module which is initialized with interrupt mechanism. After de-initialization, the user can re-initialize the SPI slave module with other mechanisms.
- Parameters
-
instance | The instance number of the SPI peripheral. |
- Returns
- An error code or kStatus_SPI_Success.
spi_status_t SPI_DRV_SlaveTransferBlocking |
( |
uint32_t |
instance, |
|
|
const uint8_t * |
sendBuffer, |
|
|
uint8_t * |
receiveBuffer, |
|
|
uint32_t |
transferByteCount, |
|
|
uint32_t |
timeout |
|
) |
| |
This function checks the driver status and mechanism, and transmits/receives data through the SPI bus. If the sendBuffer is NULL, the transmit process is ignored. If the receiveBuffer is NULL, the receive process is ignored. If both the receiveBuffer and the sendBuffer are available, the transmit and the receive progress is processed. If only the receiveBuffer is available, the receive is processed. Otherwise, the transmit is processed. This function only returns when the processes are completed. This function uses an interrupt mechanism.
- Parameters
-
instance | The instance number of SPI peripheral |
sendBuffer | The pointer to data that user wants to transmit. |
receiveBuffer | The pointer to data that user wants to store received data. |
transferByteCount | The number of bytes to send and receive. |
timeout | The maximum number of milliseconds that function waits before timed out reached. |
- Returns
- kStatus_SPI_Success if driver starts to send/receive data successfully. kStatus_SPI_Error if driver is error and needs to clean error. kStatus_SPI_Busy if driver is receiving/transmitting data and not available. kStatus_SPI_Timeout if time out reached while transferring is in progress.
spi_status_t SPI_DRV_SlaveTransfer |
( |
uint32_t |
instance, |
|
|
const uint8_t * |
sendBuffer, |
|
|
uint8_t * |
receiveBuffer, |
|
|
uint32_t |
transferByteCount |
|
) |
| |
This function checks the driver status and sets buffer pointers to receive and transmit SPI data. If the sendBuffer is NULL, the transmit process is ignored. If the receiveBuffer is NULL, the receive process is ignored. If both the receiveBuffer and the sendBuffer are available, the transfer is done when the kDspiTxDone and kDspiRxDone are set. If only the receiveBuffer is available, the transfer is done when the kDspiRxDone flag is set. Otherwise, the transfer is done when the kDspiTxDone was set. This function uses an interrupt mechanism.
- Parameters
-
instance | The instance number of SPI peripheral |
sendBuffer | The pointer to data that user wants to transmit. |
receiveBuffer | The pointer to data that user wants to store received data. |
transferByteCount | The number of bytes to send and receive. |
- Returns
- kStatus_SPI_Success if driver starts to send/receive data successfully. kStatus_SPI_Error if driver is error and needs to clean error. kStatus_SPI_Busy if driver is receiving/transmitting data and not available.
spi_status_t SPI_DRV_SlaveAbortTransfer |
( |
uint32_t |
instance | ) |
|
This function stops the transfer which was started by the calling the SPI_DRV_SlaveTransfer() function.
- Parameters
-
instance | The instance number of SPI peripheral |
- Returns
- kStatus_SPI_Success if everything is OK. kStatus_SPI_InvalidMechanism if the current transaction does not use interrupt mechanism.
spi_status_t SPI_DRV_SlaveGetTransferStatus |
( |
uint32_t |
instance, |
|
|
uint32_t * |
framesTransferred |
|
) |
| |
When performing an a-sync transfer, the user can call this function to ascertain the state of the current transfer: in progress (or busy) or complete (success). In addition, if the transfer is still in progress, the user can get the number of words that have been transferred up to now.
- Parameters
-
instance | The instance number of the SPI peripheral. |
framesTransferred | Pointer to value that is filled in with the number of frames that have been sent in the active transfer. A frame is defined as the number of bits per frame. |
- Returns
- kStatus_SPI_Success The transfer has completed successfully, or kStatus_SPI_Busy The transfer is still in progress. framesTransferred is filled with the number of words that have been transferred so far.
void SPI_DRV_SlaveIRQHandler |
( |
uint32_t |
instance | ) |
|
- Parameters
-
instance | Instance number of the SPI module. |
SPI_Type* const g_spiBase[SPI_INSTANCE_COUNT] |
const IRQn_Type g_spiIrqId[SPI_INSTANCE_COUNT] |
SPI_Type* const g_spiBase[SPI_INSTANCE_COUNT] |
const IRQn_Type g_spiIrqId[SPI_INSTANCE_COUNT] |