Name
SPI Slave — Hardware Support for SPI Slave Device
Synopsis
#include <cyg/hal/mpc512x_spislave.h>
typedef void hal_mpc512x_spi_slave_rx(
hal_mpc512x_spi_slave *slave
,
cyg_uint8 *buf
)
;
hal_mpc512x_spi_slave *hal_mpc512x_spi_slave_init(
int psc
,
cyg_uint32 tfr_size
,
cyg_uint32 flags
,
hal_mpc512x_spi_slave_rx *rx_callback
,
void *user_data
)
;
int hal_mpc512x_spi_slave_tx(
hal_mpc512x_spi_slave *slave
,
cyg_uint8 *buf
)
;
Introduction
SPI slave support is provided by a module in the MPC512X variant
HAL. It comprises a data structure, two functions and the
prototype of a function that must be supplied by the user. All of
these may be defined by including the cyg/hal/mpc512x_spislave.h
header
file.
Configuration
Any PSC that is to be used as an SPI slave must be configured into
SPISLAVE
mode. If this is done then the
following configuration options become available:
- CYGHWR_HAL_POWERPC_MPC512X_PSCX_SPI_SLAVE_MAX
- This option defines the maximum transfer size that any SPI slave device can handle. This is used to define the size of the buffers allocated to any SPI slave device. Individual SPI slaves may define FIFO sizes less than or equal to this value.
- CYGHWR_HAL_POWERPC_MPC512X_PSCN_SPI_SLAVE_MAX
- This option defines the maximum transfer size that the SPI slave device on PSCN can handle. This is used to control the size of the FIFOs allocated to this device. At initialization an application can choose an actual transfer size equal to or less than this value.
- CYGHWR_HAL_POWERPC_MPC512X_PSCN_SPI_SLAVE_INTR_PRI
- This option defines interrupt priority for the SPI slave on PSCN. The priority may range from 0 to 7. The default value of 8 selects the hardware default level.
Usage
The SPI protocol is highly asymmetric. The timing of when a transfer starts, the frequency at which it is clocked and any gap between individual bytes is under the control of the master. The slave device has no mechanism for influencing any of this. For example, with an 8MHz clock the slave would have to supply one byte every microsecond, and the gap between bytes is only 125ns. In a processor that has many other demands on its time, this kind of latency is hard to guarantee. Therefore, the SPI slave support provided makes use of the hardware characteristics to avoid any software being involved in the main part of an SPI transfer.
The SPI slave support makes use of the hardware FIFOs associated with each PSC. By pre-loading the transmit FIFO with data and keeping the transfer size to less than the FIFO size, the entire transfer can occur without software involvement. Software only needs to get involved at the end of the transfer, to empty the data sent by the master from the receive FIFO, and to load data for the next transfer into the transmit FIFO. To make this work, all transfers must be less than the size configured for the FIFOs, and all transfers must be of the same pre-defined size.
An SPI slave PSC is initialized by calling
hal_mpc512x_spi_slave_init()
. The
psc
parameter identifies the PSC to be
initialized, which must have been configured in
SPISLAVE
mode. The
tfr_size
parameter defines the transfer
size to be used, and must be less than or equal to this PSC's
maximum transfer size. rx_callback
is a
pointer to a function that will be called when data is available
and user_data
is a user-supplied value. The
flags
parameter contains configuration
flags, at present these can be used to set the SPI CPHA and CPOL
parameters used to control data sampling and clocking.
On return the init function will return a pointer to a hal_mpc512x_spi_slave structure which is used in the other API calls. If the initialization fails for some reason, NULL is returned. After a successful initialization, the SPI slave is ready for the master to initiate a transfer.
When the master performs a transfer, bytes will be clocked in to
the receive FIFO and bytes will be clocked out of the transmit
FIFO. Initialization will have pre-primed the transmit FIFO with
tfr_size
zeroes, so on the first transfer
the master can only send data to the slave. Once the transfer is
complete the PSC will raise an interrupt and call the
rx_callback()
function. This will be
provided with a pointer to a buffer containing the received
data. The user_data
may be accessed via the
slave
pointer. This function is called from
DSR mode, so should not call any functions that potentially cause
a context switch; generally it should use a semaphore or other
synchronization object to wake up a thread to perform any further
processing. The receive buffer will be overwritten by the next
transfer, so should be copied out to private memory if it needs to
be preserved.
To supply data to be sent during the next transfer, the user
should call hal_mpc512x_spi_slave_tx()
. The
buf
argument points to
tfr_size
bytes to be sent. There is
sufficient buffering for a single pending transfer, in addition to
the contents of the FIFO, so this function may be called before
the previous transfer completes. On completion of the transfer,
the transmit FIFO will be filled from the pending buffer. If the
pending buffer is already full when this function is called the
thread will be made to wait until the buffer is empty.
The following code (with some irrelevant details omitted) gives the basic outline of how a dedicated SPI slave might be structured:
// Omitted: standard headers #include <cyg/hal/mpc512x_spislave.h> #define PSC 3 #define TFR_SIZE 32 cyg_sem_t sem; cyg_uint8 tx_buf[CYGHWR_HAL_POWERPC_MPC512X_PSCX_SPI_SLAVE_MAX]; cyg_uint8 rx_buf[CYGHWR_HAL_POWERPC_MPC512X_PSCX_SPI_SLAVE_MAX]; // SPI slave callback void rx_callback( hal_mpc512x_spi_slave *slave, cyg_uint8 *buf ) { // Copy received data to private buffer memcpy( rx_buf, buf, TFR_SIZE ); // Wake up thread cyg_semaphore_post( &sem ); } // Entry function for SPI slave handling thread // Omitted: thread creation void spi_slave(cyg_addrword_t arg) { hal_mpc512x_spi_slave *slave; // Initialize semaphore cyg_semaphore_init( &sem, 0 ); // Initialize SPI slave on the PSC slave = hal_mpc512x_spi_slave_init( PSC, TFR_SIZE, HAL_SPI_SLAVE_CPHA0|HAL_SPI_SLAVE_CPOL0, &rx_callback, NULL ); // Omitted: raise error on slave == NULL // Loop forever handling transfers while( 1 ) { // Wait for a transfer to complete cyg_semaphore_wait( &sem ); // Omitted: deal with received data. // Omitted: create transmit data for next transfer. // Queue up for next transfer hal_mpc512x_spi_slave_tx( slave, tx_buf ); } }
A test program in the ADS512101 board HAL (the only board on which this device could be tested) demonstrates the use of the SPI slave support in a real program.
2024-03-18 | eCosPro Non-Commercial Public License |