SPI Drivers
The Embedded SDK includes drivers for SPI communications for the microcontrollers that contain an SPI peripheral. The SPI drivers are
provided with a common public API so that they can be used across any of the supported
platforms. The SPI drivers do not preallocate any memory or other resources; therefore unused ports will not
use any resources unless explicitly opened by the application.
Opening A Port
The code snippet below demonstrates how to initialize the driver and open an SPI port.
#include "mcu_spi.h"
#include <assert.h>
static SPI spi; /* Allocate an instance of the driver */
void APP_Function(void)
{
STATUS status;
status = SPI_Open(&spi, /* Open an SPI port */
0, /* Port number (0 in this case) */
1000000, /* Clock frequency, in hertz */
SPI_DEFAULT); /* Clock phase options */
assert(status == SUCCESS);
}
Selecting a Target
The provided drivers include the ability to select and deselect a target chip. When a chip is selected, the driver also
acquires exclusive access to the port by acquiring an underlying mutex that exists within the driver. The calling thread
will have exclusive access until the port is released by deselecting the target.
The code snippet below shows a typical pattern that is used to activate a target chip-select on a pin (P2.21) and then
later deactivates the same chip-select.
#include "mcu_spi.h"
#include <assert.h>
void APP_Function(void)
{
STATUS status;
status = SPI_Select(&spi, /* Select the target chip */
P2_21, /* The pin to drive the chip-select (P2.21) */
INFINITE); /* Max time to wait to acquire exclusive access to the bus */
assert(status == SUCCESS);
/* Perform I/O operations here...
This thread also has exclusive
access to the bus */
status = SPI_Deselect(&spi, /* Deselect the target chip (release exclusive access) */
P2_21); /* The pin to be deselected (P2.21) */
assert(status == SUCCESS);
}
Transferring Data
The provided drivers either use interrupts or DMA to actually perform the transfer. When a calling thread
requests a transfer, the transfer is staged and the calling thread is blocked while the hardware completes
the transfer. Once the transfer has completed, an interrupt will signal the calling thread and execution
will resume.
A timeout interval can be specified to avoid a dead-lock condition if the hardware were to fail and never generate
an interrupt, but care must be taken so that timeout conditions do not occur during normal operation. Ensure
the specified timeout value is large enough to accommodate the transfer rate and the amount of data being transferred.
The code snippet below shows how to send and receive several data bytes using an open port.
#include "mcu_spi.h"
#include <assert.h>
void APP_Function(void)
{
STATUS status;
BYTE data[3];
BYTE buf[3];
data[0] = 0; /* Initialize some arbitrary data */
data[1] = 1;
data[2] = 2;
status = SPI_Write(&spi, /* Write the data out the port */
data, /* Pointer to the data to be written */
3, /* Number of bytes to transmitted */
1000); /* Max time, in kernel ticks, to wait for completion */
assert(status == SUCCESS);
status = SPI_Read(&spi, /* Read data over the port */
buf, /* Pointer to a buffer for the data */
3, /* Number of bytes to be received */
1000); /* Max time, in kernel ticks, to wait for completion */
assert(status == SUCCESS);
}
SPI API
STATUS SPI_Open(SPI* port, BYTE number, UINT32 clkHz, UINT32 mode)
Opens an SPI port for communications.
PARAMETERS
port | A pointer to a caller allocated SPI port to be opened. |
number | The port number for the port to be opened. |
clkHz | The clock frequency, in hertz, for the port. |
mode | The mode of control clock phase and polarity. Bitwise OR to specify multiple options.
SPI_DEFAULT | Use default options (CPHA = 0 and CPOL = 1). |
SPI_CPHA0 | Use to sample data on the leading (first) clock edge (CPHA = 0). |
SPI_CPHA1 | Use to sample data on the trailing (second) clock edge (CPHA = 1). |
SPI_CPOL0 | Use for active high clock (CPOL = 0). |
SPI_CPOL1 | Use for active low clock (CPOL = 1). |
|
SUCCESS | The port has been configured and is open for communications. |
ERR_NULLREFERENCE | The argument 'port' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTSUPPORTED | An unsupported port number was specified. |
STATUS SPI_Close(SPI* port)
Closes an SPI port.
PARAMETERS
port | A pointer to the port to be closed. |
SUCCESS | The port has been closed. |
ERR_NULLREFERENCE | The argument 'port' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified port has not been opened. |
BOOLEAN SPI_IsOpen(SPI* port)
Returns an indication of whether an SPI port is currently open for communications.
PARAMETERS
port | A pointer to the target SPI port. |
TRUE if the SPI port is currently open; otherwise FALSE.
STATUS SPI_Select(SPI* port, PIN cs, UINT32 timeout)
Selects an SPI port by acquiring exclusive access to the port and activating the chip-select signal.
PARAMETERS
port | A pointer to the target port. |
cs | The pin to be used as the chip-select signal. |
timeout | The maximum amount of time, in kernel ticks, to block and wait to acquire exclusive access to the port. Use
'0' to return immediately without blocking and use 'INFINITE' to block and wait indefinitely. |
SUCCESS | The port has been selected. |
ERR_NULLREFERENCE | The argument 'port' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified port has not been opened. |
ERR_TIMEOUT | The specified amount of time has elapsed before exclusive access was acquired upon the port. |
STATUS SPI_Deselect(SPI* port, PIN cs)
Deselects a port by deactivating the chip-select signal and releasing exclusive access to an SPI port.
PARAMETERS
port | A pointer to the target port. |
cs | The pin to be used as the chip-select signal. |
SUCCESS | The port has been deselected. |
ERR_NULLREFERENCE | The argument 'port' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified port has not been opened. |
STATUS SPI_Read(SPI* port, BYTE address, void* buf, UINT32 nbytes, UINT32 timeout)
Reads and returns data received from an SPI port.
PARAMETERS
port | A pointer to the port to receive the data. |
address | The target device address to be read. |
buf | A pointer to a caller allocated buffer used to receive the data. |
nbytes | The total number of bytes to be received. |
timeout | The maximum amount of time, in kernel ticks, to block and wait for the transfer to complete. Must not be zero
and must be large enough to allow the transfer to complete; based upon clock rate and amount of data being
transferred. Use INFINITE to wait indefinitely. |
SUCCESS | The data was been received. |
ERR_NULLREFERENCE | The argument 'port' or 'buf' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified port has not been opened. |
ERR_INCOMPLETE | An error occurred while transferring the data and the transfer did not complete. |
ERR_TIMEOUT | The specified timeout interval has elapsed prior to the transfer being completed. |
STATUS SPI_Write(SPI* port, BYTE address, const void* data, UINT32 nbytes, UINT32 timeout)
Writes data to an SPI port.
PARAMETERS
port | A pointer to the port to be written. |
address | The target device address to be written. |
data | A pointer to the data to be written. |
nbytes | The total number of bytes to be written. |
timeout | The maximum amount of time, in kernel ticks, to block and wait for the transfer to complete. Must not be zero
and must be large enough to allow the transfer to complete; based upon clock rate and amount of data being
transferred. Use INFINITE to wait indefinitely. |
SUCCESS | The data has been written. |
ERR_NULLREFERENCE | The argument 'port' or 'data' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified port has not been opened. |
ERR_INCOMPLETE | An error occurred while transferring the data and the transfer did not complete. |
ERR_TIMEOUT | The specified timeout interval has elapsed prior to the transfer being completed. |