blob: 2b3617bc49c166eb522d896aa3cd13862fc2159d [file] [log] [blame]
/***************************************************************************//**
* (c) Copyright 2008 Actel Corporation. All rights reserved.
*
* SmartFusion microcontroller subsystem SPI bare metal software driver public API.
*
* The microcontroller subsystem SPI driver provides functions for implementing
* SPI master or SPI slave operations. These operations can be one of two
* classes: SPI frame operation or block transfer operations.
* Frame operations allow transferring SPI frames from 4 to 32 bits long. Block
* operations allow transferring blocks of data organized as 8 bit bytes.
*
* SVN $Revision: 2189 $
* SVN $Date: 2010-02-16 22:02:32 +0000 (Tue, 16 Feb 2010) $
*/
/*=========================================================================*//**
@mainpage SmartFusion MSS SPI Bare Metal Driver.
@section intro_sec Introduction
The SmartFusion™ microcontroller subsystem (MSS) includes two serial
peripheral interface SPI peripherals for serial communication. This driver
provides a set of functions for controlling the MSS SPIs as part of a bare
metal system where no operating system is available. These drivers can be
adapted for use as part of an operating system, but the implementation of the
adaptation layer between this driver and the operating system's driver model
is outside the scope of this driver.
@section hw_dependencies Hardware Flow Dependencies
The configuration of all features of the MSS SPIs is covered by this driver
with the exception of the SmartFusion IOMUX configuration. SmartFusion allows
multiple non-concurrent uses of some external pins through IOMUX configuration.
This feature allows optimization of external pin usage by assigning external
pins for use by either the microcontroller subsystem or the FPGA fabric. The
MSS SPIs serial signals are routed through IOMUXes to the SmartFusion device
external pins. These IOMUXes are automatically configured correctly by the MSS
configurator tool in the hardware flow when the MSS SPIs are enabled in that
tool. You must ensure that the MSS SPIs are enabled by the MSS configurator
tool in the hardware flow; otherwise the serial inputs and outputs will not be
connected to the chip's external pins. For more information on IOMUX, refer to
the IOMUX section of the SmartFusion Datasheet.
The base address, register addresses and interrupt number assignment for the
MSS SPI blocks are defined as constants in the SmartFusion CMSIS-PAL. You must
ensure that the SmartFusion CMSIS-PAL is either included in the software tool
chain used to build your project or is included in your project.
@section theory_op Theory of Operation
The MSS SPI driver functions are grouped into the following categories:
• Initialization
• Configuration for either master or slave operations
• SPI master frame transfer control
• SPI master block transfer control
• SPI slave frame transfer control
• SPI slave block transfer control
• DMA block transfer
Frame transfers allow the MSS SPI to write or read up to 32 bits of data in a
SPI transaction. For example, a frame transfer of 12 bits might be used to
read the result of an ADC conversion from a SPI analog to digital converter.
Block transfers allow the MSS SPI to write or read a number of bytes in a SPI
transaction. Block transfer transactions allow data transfers in multiples of
8 bits (8, 16, 24, 32, 40…). Block transfers are typically used with byte
oriented devices like SPI FLASH devices.
Initialization
The MSS SPI driver is initialized through a call to the MSS_SPI_init()
function. The MSS_SPI_init() function takes only one parameter, a pointer
to one of two global data structures used by the driver to store state
information for each MSS SPI. A pointer to these data structures is also
used as first parameter to any of the driver functions to identify which MSS
SPI will be used by the called function. The names of these two data
structures are g_mss_spi0 and g_mss_spi1. Therefore any call to an MSS SPI
driver function should be of the form MSS_SPI_function_name( &g_mss_spi0, ... )
or MSS_SPI_function_name( &g_mss_spi1, ... ).
The MSS_SPI_init() function resets the specified MSS SPI hardware block and
clears any pending interrupts from that MSS SPI in the Cortex-M3 NVIC.
The MSS_SPI_init() function must be called before any other MSS SPI driver
functions can be called.
Configuration
A MSS SPI block can operate either as a master or slave SPI device. There
are two distinct functions for configuring a MSS SPI block for master or
slave operations.
Master configuration
The MSS_SPI_configure_master_mode() function configures the specified MSS
SPI block for operations as a SPI master. It must be called once for each
remote SPI slave device the MSS SPI block will communicate with. It is used
to provide the following information about each SPI slave’s communication
characteristics:
• The SPI protocol mode
• The SPI clock speed
• The frame bit length
This information is held by the driver and will be used to alter the
configuration of the MSS SPI block each time a slave is selected through a
call to MSS_SPI_set_slave_select(). The SPI protocol mode defines the
initial state of the clock signal at the start of a transaction and which
clock edge will be used to sample the data signal, or it defines whether the
SPI block will operate in TI synchronous serial mode or in NSC MICROWIRE mode.
Slave configuration
The MSS_SPI_configure_slave_mode() function configures the specified MSS SPI
block for operations as a SPI slave. It configures the following SPI
communication characteristics:
• The SPI protocol mode
• The SPI clock speed
• The frame bit length
The SPI protocol mode defines the initial state of the clock signal at the
start of a transaction and which clock edge will be used to sample the data
signal, or it defines whether the SPI block will operate in TI synchronous
serial mode or in NSC MICROWIRE mode.
SPI master frame transfer control
The following functions are used as part of SPI master frame transfers:
• MSS_SPI_set_slave_select()
• MSS_SPI_transfer_frame()
• MSS_SPI_clear_slave_select()
The master must first select the target slave through a call to
MSS_SPI_set_slave_select(). This causes the relevant slave select line to
become asserted while data is clocked out onto the SPI data line.
A call to is then made to function MSS_SPI_transfer_frame() specifying and
the value of the data frame to be sent.
The function MSS_SPI_clear_slave_select() can be used after the transfer is
complete to prevent this slave select line from being asserted during
subsequent SPI transactions. A call to this function is only required if the
master is communicating with multiple slave devices.
SPI master block transfer control
The following functions are used as part of SPI master block transfers:
• MSS_SPI_set_slave_select()
• MSS_SPI_clear_slave_select()
• MSS_SPI_transfer_block()
The master must first select the target slave through a call to
MSS_SPI_set_slave_select(). This causes the relevant slave select line to
become asserted while data is clocked out onto the SPI data line.
Alternatively a GPIO can be used to control the state of the target slave
device’s chip select signal.
A call to is then made to function MSS_SPI_transfer_block (). The
parameters of this function specify:
• the number of bytes to be transmitted
• a pointer to the buffer containing the data to be transmitted
• the number of bytes to be received
• a pointer to the buffer where received data will be stored
The number of bytes to be transmitted can be set to zero to indicate that
the transfer is purely a block read transfer. The number of bytes to be
received can be set to zero to specify that the transfer is purely a block
write transfer.
The function MSS_SPI_clear_slave_select() can be used after the transfer is
complete to prevent this slave select line from being asserted during
subsequent SPI transactions. A call to this function is only required if the
master is communicating with multiple slave devices.
SPI slave frame transfer control
The following functions are used as part of SPI slave frame transfers:
• MSS_SPI_set_slave_tx_frame()
• MSS_SPI_set_frame_rx_handler()
The MSS_SPI_set_slave_tx_frame() function specifies the frame data that will
be returned to the SPI master. The frame data specified through this
function is the value that will be read over the SPI bus by the remote SPI
master when it initiates a transaction. A call to MSS_SPI_set_slave_tx_frame()
is only required if the MSS SPI slave is the target of SPI read transactions,
i.e. if data is meant to be read from the SmartFusion device over SPI.
The MSS_SPI_set_frame_rx_handler() function specifies the receive handler
function that will called when a frame of data has been received by the MSS
SPI when it is configured as a slave. The receive handler function specified
through this call will process the frame data written, over the SPI bus, to
the MSS SPI slave by the remote SPI master. The receive handler function must
be implemented as part of the application. It is only required if the MSS SPI
slave is the target of SPI frame write transactions.
SPI slave block transfer control
The following functions are used as part of SPI slave block transfers:
• MSS_SPI_set_slave_block_buffers()
The MSS_SPI_set_slave_block_buffers() function is used to configure a MSS SPI
slave for block transfer operations. It specifies:
• The buffer containing the data that will be returned to the remote SPI master
• The buffer where data received from the remote SPI master will be stored
• The handler function that will be called after the receive buffer is filled
DMA block transfer control
The following functions are used as part of MSS SPI DMA transfers:
• MSS_SPI_disable()
• MSS_SPI_set_transfer_byte_count()
• MSS_SPI_enable()
• MSS_SPI_tx_done()
The MSS SPI must first be disabled through a call to function MSS_SPI_disable().
The number of bytes to be transferred is then set through a call to function
MSS_SPI_set_transfer_byte_count(). The DMA transfer is then initiated by a call
to the MSS_PDMA_start() function provided by the MSS PDMA driver. The actual
DMA transfer will only start once the MSS SPI block has been re-enabled through
a call to MSS_SPI_enable(). The completion of the DMA driven SPI transfer can
be detected through a call to MSS_SPI_tx_done(). The direction of the SPI
transfer, write or read, depends on the DMA channel configuration. A SPI write
transfer occurs when the DMA channel is configured to write data to the MSS SPI
block. A SPI read transfer occurs when the DMA channel is configured to read data
from the MSS SPI block.
*//*=========================================================================*/
#ifndef MSS_SPI_H_
#define MSS_SPI_H_
#include "../../CMSIS/a2fxxxm3.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
This defines the function prototype that must be followed by MSS SPI slave
frame receive handler functions. These functions are registered with the MSS
SPI driver through the MSS_SPI_set_frame_rx_handler () function.
Declaring and Implementing Slave Frame Receive Handler Functions:
Slave frame receive handler functions should follow the following prototype:
void slave_frame_receive_handler ( uint32_t rx_frame );
The actual name of the receive handler is unimportant. You can use any name
of your choice for the receive frame handler. The rx_frame parameter will
contain the value of the received frame.
*/
typedef void (*mss_spi_frame_rx_handler_t)( uint32_t rx_frame );
/***************************************************************************//**
This defines the function prototype that must be followed by MSS SPI slave
block receive handler functions. These functions are registered with the MSS
SPI driver through the MSS_SPI_set_slave_block_buffers() function.
Declaring and Implementing Slave Block Receive Handler Functions
Slave block receive handler functions should follow the following prototype:
void mss_spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size );
The actual name of the receive handler is unimportant. You can use any name
of your choice for the receive frame handler. The rx_buff parameter will
contain a pointer to the start of the received block. The rx_size parameter
will contain the number of bytes of the received block.
*/
typedef void (*mss_spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size );
/***************************************************************************//**
This enumeration is used to define the settings for the SPI protocol mode
bits, CPHA and CPOL. It is used as a parameter to the MSS_SPI_configure_master_mode()
and MSS_SPI_configure_slave_mode() functions.
- MSS_SPI_MODE0:
Clock starts low, data read on clock's rising edge, data changes on
falling edge.
- MSS_SPI_MODE1:
Clock starts low, data read on clock's falling edge, data changes on
rising edge.
- MSS_SPI_MODE2:
Clock starts high, data read on clock's falling edge, data changes on
rising edge.
- MSS_SPI_MODE3:
Clock starts high, data read on clock's rising edge, data changes on
falling edge.
- MSS_TI_MODE:
TI syncronous serial mode. Slave select is pulsed at start of transfer.
- MSS_NSC_MODE:
NSC Microwire mode.
*/
typedef enum __mss_spi_protocol_mode_t
{
MSS_SPI_MODE0 = 0x00000000,
MSS_SPI_TI_MODE = 0x00000004,
MSS_SPI_NSC_MODE = 0x00000008,
MSS_SPI_MODE2 = 0x01000000,
MSS_SPI_MODE1 = 0x02000000,
MSS_SPI_MODE3 = 0x03000000
} mss_spi_protocol_mode_t;
/***************************************************************************//**
This enumeration specifies the divider to be applied to the the APB bus clock
in order to generate the SPI clock. It is used as parameter to the
MSS_SPI_configure_master_mode() and MSS_SPI_configure_slave_mode()functions.
*/
typedef enum __mss_spi_pclk_div_t
{
MSS_SPI_PCLK_DIV_2 = 0,
MSS_SPI_PCLK_DIV_4 = 1,
MSS_SPI_PCLK_DIV_8 = 2,
MSS_SPI_PCLK_DIV_16 = 3,
MSS_SPI_PCLK_DIV_32 = 4,
MSS_SPI_PCLK_DIV_64 = 5,
MSS_SPI_PCLK_DIV_128 = 6,
MSS_SPI_PCLK_DIV_256 = 7
} mss_spi_pclk_div_t;
/***************************************************************************//**
This enumeration is used to select a specific SPI slave device (0 to 7). It is
used as a parameter to the MSS_SPI_configure_master_mode(),
MSS_SPI_set_slave_select() and MSS_SPI_clear_slave_select () functions.
*/
typedef enum __mss_spi_slave_t
{
MSS_SPI_SLAVE_0 = 0,
MSS_SPI_SLAVE_1 = 1,
MSS_SPI_SLAVE_2 = 2,
MSS_SPI_SLAVE_3 = 3,
MSS_SPI_SLAVE_4 = 4,
MSS_SPI_SLAVE_5 = 5,
MSS_SPI_SLAVE_6 = 6,
MSS_SPI_SLAVE_7 = 7,
MSS_SPI_MAX_NB_OF_SLAVES = 8
} mss_spi_slave_t;
/***************************************************************************//**
This constant defines a frame size of 8 bits when configuring an MSS SPI to
perform block transfer data transactions.
It must be used as the value for the frame_bit_length parameter of function
MSS_SPI_configure_master_mode() when performing block transfers between the
MSS SPI master and the target SPI slave.
It must also be used as the value for the frame_bit_length parameter of
function MSS_SPI_configure_slave_mode() when performing block transfers
between the MSS SPI slave and the remote SPI master.
*/
#define MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE 8
/***************************************************************************//**
The mss_spi_slave_cfg_t holds the MSS SPI configuration that must be used to
communicate with a specific SPI slave.
*/
typedef struct __mss_spi_slave_cfg_t
{
uint32_t ctrl_reg;
uint8_t txrxdf_size_reg;
uint8_t clk_gen;
} mss_spi_slave_cfg_t;
/***************************************************************************//**
There is one instance of this structure for each of the microcontroller
subsystem's SPIs. Instances of this structure are used to identify a specific
SPI. A pointer to an instance of the mss_spi_instance_t structure is passed as
the first parameter to MSS SPI driver functions to identify which SPI should
perform the requested operation.
*/
typedef struct __mss_spi_instance_t
{
/* CMSIS related defines identifying the SPI hardware. */
SPI_TypeDef * hw_reg; /*!< Pointer to SPI registers. */
SPI_BitBand_TypeDef * hw_reg_bit; /*!< Pointer to SPI registers bit band area. */
IRQn_Type irqn; /*!< SPI's Cortex-M3 NVIC interrupt number. */
/* Internal transmit state: */
const uint8_t * slave_tx_buffer; /*!< Pointer to slave transmit buffer. */
uint32_t slave_tx_size; /*!< Size of slave transmit buffer. */
uint32_t slave_tx_idx; /*!< Current index into slave transmit buffer. */
/* Internal receive state: */
uint8_t * slave_rx_buffer; /*!< Pointer to buffer where data received by a slave will be stored. */
uint32_t slave_rx_size; /*!< Slave receive buffer size. */
uint32_t slave_rx_idx; /*!< Current index into slave receive buffer. */
/* Configuration for each target slave. */
mss_spi_slave_cfg_t slaves_cfg[MSS_SPI_MAX_NB_OF_SLAVES];
/** Slave received frame handler: */
mss_spi_frame_rx_handler_t frame_rx_handler; /*!< Pointer to function that will be called when a frame is received when the SPI block is configured as slave. */
uint32_t slave_tx_frame; /*!< Value of the data frame that will be transmited when the SPI block is configured as slave. */
/* Slave block rx handler: */
mss_spi_block_rx_handler_t block_rx_handler; /*!< Pointer to the function that will be called when a data block has been received. */
} mss_spi_instance_t;
/***************************************************************************//**
This instance of mss_spi_instance_t holds all data related to the operations
performed by MSS SPI 0. A pointer to g_mss_spi0 is passed as the first
parameter to MSS SPI driver functions to indicate that MSS SPI 0 should
perform the requested operation.
*/
extern mss_spi_instance_t g_mss_spi0;
/***************************************************************************//**
This instance of mss_spi_instance_t holds all data related to the operations
performed by MSS SPI 1. A pointer to g_mss_spi1 is passed as the first
parameter to MSS SPI driver functions to indicate that MSS SPI 1 should
perform the requested operation.
*/
extern mss_spi_instance_t g_mss_spi1;
/***************************************************************************//**
The MSS_SPI_init() function initializes and hardware and data structures of
one of the SmartFusion MSS SPIs. The MSS_SPI_init() function must be called
before any other MSS SPI driver functions can be called.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
Example:
@code
MSS_SPI_init( &g_mss_spi0 );
@endcode
*/
void MSS_SPI_init
(
mss_spi_instance_t * this_spi
);
/***************************************************************************//**
The MSS_SPI_configure_slave_mode() function configure a MSS SPI block for
operations as a slave SPI device. It configures the SPI hardware with the
selected SPI protocol mode and clock speed.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param protocol_mode
Serial peripheral interface operating mode. Allowed values are:
- MSS_SPI_MODE0
- MSS_SPI_MODE1
- MSS_SPI_MODE2
- MSS_SPI_MODE3
- MSS_TI_MODE
- MSS_NSC_MODE
@param clk_rate
Divider value used to generate serial interface clock signal from PCLK.
Allowed values are:
- MSS_SPI_PCLK_DIV_2
- MSS_SPI_PCLK_DIV_4
- MSS_SPI_PCLK_DIV_8
- MSS_SPI_PCLK_DIV_16
- MSS_SPI_PCLK_DIV_32
- MSS_SPI_PCLK_DIV_64
- MSS_SPI_PCLK_DIV_128
- MSS_SPI_PCLK_DIV_256
@param frame_bit_length
Number of bits making up the frame. The maximum frame length is 32 bits. You
must use the MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE constant as the value for
frame_bit_length when configuring the MSS SPI master for block transfer
transactions with the target SPI slave.
Example:
@code
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_slave_mode
(
&g_mss_spi0,
MSS_SPI_MODE2,
MSS_SPI_PCLK_DIV_64,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE
);
@endcode
*/
void MSS_SPI_configure_slave_mode
(
mss_spi_instance_t * this_spi,
mss_spi_protocol_mode_t protocol_mode,
mss_spi_pclk_div_t clk_rate,
uint8_t frame_bit_length
);
/***************************************************************************//**
The MSS_SPI_configure_master_mode() function configures the protocol mode,
serial clock speed and frame size for a specific target SPI slave device. It
is used when the MSS SPI hardware block is used as a SPI master. This function
must be called once for each target SPI slave the SPI master is going to
communicate with. The SPI master hardware will be configured with the
configuration specified by this function during calls to
MSS_SPI_set_slave_select().
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param slave
The slave parameter is used to identify a target SPI slave. The driver will
hold the MSS SPI master configuration required to communicate with this
slave, as specified by the other function parameters. Allowed values are:
• MSS_SPI_SLAVE_0
• MSS_SPI_SLAVE_1
• MSS_SPI_SLAVE_2
• MSS_SPI_SLAVE_3
• MSS_SPI_SLAVE_4
• MSS_SPI_SLAVE_5
• MSS_SPI_SLAVE_6
• MSS_SPI_SLAVE_7
@param protocol_mode
Serial peripheral interface operating mode. Allowed values are:
• MSS_SPI_MODE0
• MSS_SPI_MODE1
• MSS_SPI_MODE2
• MSS_SPI_MODE3
• MSS_SPI_TI_MODE
• MSS_SPI_NSC_MODE
@param clk_rate
Divider value used to generate serial interface clock signal from PCLK.
Allowed values are:
• MSS_SPI_PCLK_DIV_2
• MSS_SPI_PCLK_DIV_4
• MSS_SPI_PCLK_DIV_8
• MSS_SPI_PCLK_DIV_16
• MSS_SPI_PCLK_DIV_32
• MSS_SPI_PCLK_DIV_64
• MSS_SPI_PCLK_DIV_128
• MSS_SPI_PCLK_DIV_256
@param frame_bit_length
Number of bits making up the frame. The maximum frame length is 32 bits. You
must use the MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE constant as the value for
frame_bit_length when configuring the MSS SPI master for block transfer
transactions with the target SPI slave.
Example:
@code
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE2,
MSS_SPI_PCLK_DIV_64,
12
);
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_1,
MSS_SPI_TI_MODE,
MSS_SPI_PCLK_DIV_128,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE
);
@endcode
*/
void MSS_SPI_configure_master_mode
(
mss_spi_instance_t * this_spi,
mss_spi_slave_t slave,
mss_spi_protocol_mode_t protocol_mode,
mss_spi_pclk_div_t clk_rate,
uint8_t frame_bit_length
);
/*==============================================================================
* Master functions
*============================================================================*/
/***************************************************************************//**
The MSS_SPI_slave_select() function is used by a MSS SPI master to select a
specific slave. This function causes the relevant slave select signal to be
asserted.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param slave
The slave parameter is one of mss_spi_slave_t enumerated constants
identifying a slave.
Example:
@code
const uint8_t frame_size = 25;
const uint32_t master_tx_frame = 0x0100A0E1;
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE1,
MSS_SPI_PCLK_DIV_256,
frame_size
);
MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
MSS_SPI_transfer_frame( &g_mss_spi0, master_tx_frame );
MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
@endcode
*/
void MSS_SPI_set_slave_select
(
mss_spi_instance_t * this_spi,
mss_spi_slave_t slave
);
/***************************************************************************//**
The MSS_SPI_clear_slave_select() function is used by a MSS SPI Master to
deselect a specific slave. This function causes the relevant slave select
signal to be de-asserted.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param slave
The slave parameter is one of mss_spi_slave_t enumerated constants
identifying a slave.
Example:
@code
const uint8_t frame_size = 25;
const uint32_t master_tx_frame = 0x0100A0E1;
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE1,
MSS_SPI_PCLK_DIV_256,
frame_size
);
MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
MSS_SPI_transfer_frame( &g_mss_spi0, master_tx_frame );
MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
@endcode
*/
void MSS_SPI_clear_slave_select
(
mss_spi_instance_t * this_spi,
mss_spi_slave_t slave
);
/***************************************************************************//**
The MSS_SPI_disable() function is used to temporarily disable a MSS SPI
hardware block. This function is typically used in conjunction with the
SPI_set_transfer_byte_count() function to setup a DMA controlled SPI transmit
transaction as the SPI_set_transfer_byte_count() function must only be used
when the MSS SPI hardware is disabled.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
Example:
@code
uint32_t transfer_size;
uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
transfer_size = sizeof(tx_buffer);
MSS_SPI_disable( &g_mss_spi0 );
MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size );
PDMA_start
(
PDMA_CHANNEL_0,
(uint32_t)tx_buffer,
PDMA_SPI1_TX_REGISTER,
transfer_size
);
MSS_SPI_enable( &g_mss_spi0 );
while ( !MSS_SPI_tx_done( &g_mss_spi0 ) )
{
;
}
@endcode
*/
static __INLINE void MSS_SPI_disable
(
mss_spi_instance_t * this_spi
)
{
this_spi->hw_reg_bit->CTRL_ENABLE = 0;
}
/***************************************************************************//**
The MSS_SPI_enable() function is used to re-enable a MSS SPI hardware block
after it was disabled using the SPI_disable() function.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
Example:
@code
uint32_t transfer_size;
uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
transfer_size = sizeof(tx_buffer);
MSS_SPI_disable( &g_mss_spi0 );
MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size );
PDMA_start
(
PDMA_CHANNEL_0,
(uint32_t)tx_buffer,
PDMA_SPI1_TX_REGISTER,
transfer_size
);
MSS_SPI_enable( &g_mss_spi0 );
while ( !MSS_SPI_tx_done( &g_mss_spi0 ) )
{
;
}
@endcode
*/
static __INLINE void MSS_SPI_enable
(
mss_spi_instance_t * this_spi
)
{
this_spi->hw_reg_bit->CTRL_ENABLE = 1;
}
/***************************************************************************//**
The MSS_SPI_set_transfer_byte_count() function is used as part of setting up
a SPI transfer using DMA. It specifies the number of bytes that must be
transferred before MSS_SPI_tx_done() indicates that the transfer is complete.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param byte_count
The byte_count parameter specifies the number of bytes that must be
transferred by the SPI hardware block considering that a transaction has
been completed.
Example:
@code
uint32_t transfer_size;
uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
transfer_size = sizeof(tx_buffer);
MSS_SPI_disable( &g_mss_spi0 );
MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size );
PDMA_start( PDMA_CHANNEL_0, (uint32_t)tx_buffer, 0x40011014, transfer_size );
MSS_SPI_enable( &g_mss_spi0 );
while ( !MSS_SPI_tx_done( &g_mss_spi0) )
{
;
}
@endcode
*/
static __INLINE void MSS_SPI_set_transfer_byte_count
(
mss_spi_instance_t * this_spi,
uint16_t byte_count
)
{
const uint32_t TXRXDFCOUNT_SHIFT = 8U;
const uint32_t TXRXDFCOUNT_MASK = 0x00FFFF00U;
this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ( (byte_count << TXRXDFCOUNT_SHIFT) & TXRXDFCOUNT_MASK);
this_spi->hw_reg->TXRXDF_SIZE = 8U;
}
/***************************************************************************//**
The MSS_SPI_tx_done() function is used to find out if a DMA controlled transfer
has completed.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
Example:
@code
uint32_t transfer_size;
uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
transfer_size = sizeof(tx_buffer);
MSS_SPI_disable( &g_mss_spi0 );
MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size );
PDMA_start
(
PDMA_CHANNEL_0,
(uint32_t)tx_buffer,
PDMA_SPI1_TX_REGISTER,
transfer_size
);
MSS_SPI_enable( &g_mss_spi0 );
while ( !MSS_SPI_tx_done(&g_mss_spi0) )
{
;
}
@endcode
*/
static __INLINE uint32_t MSS_SPI_tx_done
(
mss_spi_instance_t * this_spi
)
{
return this_spi->hw_reg_bit->STATUS_TX_DONE;
}
/***************************************************************************//**
The MSS_SPI_transfer_frame() function is used by a MSS SPI master to transmit
and receive a frame up to 32 bits long. This function is typically used for
transactions with a SPI slave where the number of transmit and receive bits is
not divisible by 8.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param tx_bits
The tx_bits parameter is a 32 bits word containing the value that will be
transmitted.
Note: The bit length of the value to be transmitted to the slave must be
specified as the frame_bit_length parameter in a previous call to
the MSS_SPI_configure_master() function.
@return
This function returns a 32 bits word containing the value that is received
from the slave.
Example:
@code
const uint8_t frame_size = 25;
const uint32_t master_tx_frame = 0x0100A0E1;
uint32_t master_rx;
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE1,
MSS_SPI_PCLK_DIV_256,
frame_size
);
MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
master_rx = MSS_SPI_transfer_frame( &g_mss_spi0, master_tx_frame );
MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
@endcode
*/
uint32_t MSS_SPI_transfer_frame
(
mss_spi_instance_t * this_spi,
uint32_t tx_bits
);
/***************************************************************************//**
The MSS_SPI_transfer_block() function is used by MSS SPI masters to transmit
and receive blocks of data organized as a specified number of bytes. It can be
used for:
• Writing a data block to a slave
• Reading a data block from a slave
• Sending a command to a slave followed by reading the outcome of the
command in a single SPI transaction. This function can be used alongside
Peripheral DMA functions to perform the actual moving to and from the SPI
hardware block using Peripheral DMA.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param cmd_buffer
The cmd_buffer parameter is a pointer to the buffer containing the data that
will be sent by the master from the beginning of the transfer. This pointer
can be null (0) if the master does not need to send a command before reading
data or if the command part of the transfer is written to the SPI hardware
block using DMA.
@param cmd_byte_size
The cmd_byte_size parameter specifies the number of bytes contained in
cmd_buffer that will be sent. A value of 0 indicates that no data needs to
be sent to the slave. A non-zero value while the cmd_buffer pointer is 0 is
used to indicate that the command data will be written to the SPI hardware
block using DMA.
@param rd_buffer
The rd_buffer parameter is a pointer to the buffer where the data received
from the slave after the command has been sent will be stored.
@param rd_byte_size
The rd_byte_size parameter specifies the number of bytes to be received from
the slave and stored in the rd_buffer. A value of 0 indicates that no data
is to be read from the slave. A non-zero value while the rd_buffer pointer
is null (0) is used to specify the receive size when using DMA to read from
the slave.
Note: All bytes received from the slave, including the bytes received
while the command is sent, will be read through DMA.
Polled write transfer example:
@code
uint8_t master_tx_buffer[MASTER_TX_BUFFER] =
{
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A
};
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE1,
MSS_SPI_PCLK_DIV_256,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE
);
MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
MSS_SPI_transfer_block
(
&g_mss_spi0,
master_tx_buffer,
sizeof(master_tx_buffer),
0,
0
);
MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
@endcode
DMA transfer example:
In this example the transmit and receive buffers are not specified as part of
the call to MSS_SPI_transfer_block(). MSS_SPI_transfer_block() will only
prepare the MSS SPI hardware for a transfer. The MSS SPI transmit hardware
FIFO is filled using one DMA channel and a second DMA channel is used to read
the content of the MSS SPI receive hardware FIFO. The transmit and receive
buffers are specified by two separate calls to PDMA_start() to initiate DMA
transfers on the channel used for transmit data and the channel used for
receive data.
@code
uint8_t master_tx_buffer[MASTER_RX_BUFFER] =
{
0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA
};
uint8_t slave_rx_buffer[MASTER_RX_BUFFER] =
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A
};
MSS_SPI_init( &g_mss_spi0 );
MSS_SPI_configure_master_mode
(
&g_mss_spi0,
MSS_SPI_SLAVE_0,
MSS_SPI_MODE1,
MSS_SPI_PCLK_DIV_256,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE
);
MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
MSS_SPI_transfer_block( &g_mss_spi0, 0, 0, 0, 0 );
PDMA_start
(
PDMA_CHANNEL_1,
PDMA_SPI0_RX_REGISTER,
(uint32_t)master_rx_buffer,
sizeof(master_rx_buffer)
);
PDMA_start
(
PDMA_CHANNEL_2,
(uint32_t)master_tx_buffer,
PDMA_SPI0_TX_REGISTER,
sizeof(master_tx_buffer)
);
while( PDMA_status(PDMA_CHANNEL_1) == 0 )
{
;
}
MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
@endcode
*/
void MSS_SPI_transfer_block
(
mss_spi_instance_t * this_spi,
const uint8_t * cmd_buffer,
uint16_t cmd_byte_size,
uint8_t * rd_buffer,
uint16_t rd_byte_size
);
/*==============================================================================
* Slave functions
*============================================================================*/
/***************************************************************************//**
The MSS_SPI_set_frame_rx_handler() function is used by MSS SPI slaves to
specify the receive handler function that will be called by the MSS SPI driver
interrupt handler when a a frame of data is received by the MSS SPI slave.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param rx_handler
The rx_handler parameter is a pointer to the frame receive handler that must
be called when a frame is received by the MSS SPI slave.
Example:
@code
uint32_t g_slave_rx_frame = 0;
void slave_frame_handler( uint32_t rx_frame )
{
g_slave_rx_frame = rx_frame;
}
int setup_slave( void )
{
const uint16_t frame_size = 25;
MSS_SPI_init( &g_mss_spi1 );
MSS_SPI_configure_slave_mode
(
&g_mss_spi0,
MSS_SPI_MODE2,
MSS_SPI_PCLK_DIV_64,
frame_size
);
MSS_SPI_set_frame_rx_handler( &g_mss_spi1, slave_frame_handler );
}
@endcode
*/
void MSS_SPI_set_frame_rx_handler
(
mss_spi_instance_t * this_spi,
mss_spi_frame_rx_handler_t rx_handler
);
/***************************************************************************//**
The MSS_SPI_set_slave_tx_frame() function is used by MSS SPI slaves to specify
the frame that will be transmitted when a transaction is initiated by the SPI
master.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param frame_value
The frame_value parameter contains the value of the frame to be sent to the
master.
Note: The bit length of the value to be transmitted to the master must be
specified as the frame_bit_length parameter in a previous call to
the MSS_SPI_configure_slave() function.
Example:
@code
const uint16_t frame_size = 25;
const uint32_t slave_tx_frame = 0x0110F761;
uint32_t master_rx;
MSS_SPI_init( &g_mss_spi1 );
MSS_SPI_configure_slave_mode
(
&g_mss_spi0,
MSS_SPI_MODE2,
MSS_SPI_PCLK_DIV_64,
frame_size
);
MSS_SPI_set_slave_tx_frame( &g_mss_spi1, slave_tx_frame );
@endcode
*/
void MSS_SPI_set_slave_tx_frame
(
mss_spi_instance_t * this_spi,
uint32_t frame_value
);
/***************************************************************************//**
The MSS_SPI_set_slave_block_buffers() function is used to configure an MSS
SPI slave for block transfer operations. It specifies one or more of the
following:
• The data that will be transmitted when accessed by a master.
• The buffer where data received from a master will be stored.
• The handler function that must be called after the receive buffer has been
filled.
• The number of bytes that must be received from the master before the receive
handler function is called.
These parameters allow the following use cases:
• Slave performing an action after receiving a block of data from a master
containing a command. The action will be performed by the receive handling
based on the content of the receive data buffer.
• Slave returning a block of data to the master. The type of information is
always the same but the actual values change over time. For example,
returning the voltage of a predefined set of analog inputs.
• Slave returning data based on a command contained in the first part of the
SPI transaction. For example, reading the voltage of the analog input
specified by the first data byte by the master. This is achieved by setting
the rx_buff_size parameter to the number of received bytes making up the
command.
@param this_spi
The this_spi parameter is a pointer to an mss_spi_instance_t structure
identifying the MSS SPI hardware block to be initialized. There are two such
data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
or g_mss_spi1 global data structure defined within the SPI driver.
@param tx_buffer
The tx_buffer parameter is a pointer to a buffer containing the data that
will be sent to the master. This parameter can be set to 0 if the MSS SPI
slave is not intended to be the target of SPI read transactions or if DMA
is used to transfer SPI read data into the MSS SPI slave.
@param tx_buff_size
The tx_buff_size parameter specifies the number of bytes contained in the
tx_buffer. This parameter can be set to 0 if the MSS SPI slave is not
intended to be the target of SPI read transactions or if DMA is used to
transfer SPI read data into the MSS SPI slave.
@param rx_buffer
The rx_buffer parameter is a pointer to the buffer where data received from
the master will be stored. This parameter can be set to 0 if the MSS SPI
slave is not intended to be the target of SPI write or write-read
transactions. It can also set to 0 if the MSS SPI slave uses DMA to handle
data written to it.
@param rx_buff_size
The rx_buff_size parameter specifies the size of the receive buffer. It is
also the number of bytes that must be received before the receive handler
is called, if a receive handler is specified using the block_rx_handler
parameter. This parameter can be set to 0 if the MSS SPI slave is not
intended to be the target of SPI write or write-read transactions. It can
also set to 0 if the MSS SPI slave uses DMA to handle data written to it.
@param block_rx_handler
The block_rx_handler parameter is a pointer to a function that will be
called when the receive buffer has been filled. This parameter can be set
to 0 if the MSS SPI slave is not intended to be the target of SPI write or
write-read transactions. It can also set to 0 if the MSS SPI slave uses DMA
to handle data written to it.
Slave performing operation based on master command:
In this example the SPI slave is configured to receive 10 bytes of data or
command from the SPI slave and process the data received from the master.
@code
uint32_t nb_of_rx_handler_calls = 0;
void spi1_block_rx_handler_b
(
uint8_t * rx_buff,
uint16_t rx_size
)
{
++nb_of_rx_handler_calls;
}
void setup_slave( void )
{
uint8_t slave_rx_buffer[10] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
MSS_SPI_init( &g_mss_spi1 );
MSS_SPI_configure_slave_mode
(
&g_mss_spi0,
MSS_SPI_MODE2,
MSS_SPI_PCLK_DIV_64,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE
);
MSS_SPI_set_slave_block_buffers
(
&g_mss_spi1,
0,
0,
slave_rx_buffer,
sizeof(master_tx_buffer),
spi1_block_rx_handler_b
);
}
@endcode
Slave responding to command example:
In this example the slave will return data based on a command sent by the
master. The first part of the transaction is handled using polled mode where
each byte returned to the master is written as part of the interrupt service
routine. The second part of the transaction, where the slave returns data
based on the command value, is sent using a DMA transfer initiated by the
receive handler.
@code
static uint8_t g_spi1_tx_buffer_b[SLAVE_TX_BUFFER_SIZE] =
{
5, 6, 7, 8, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5
};
void spi1_block_rx_handler
(
uint8_t * rx_buff,
uint16_t rx_size
)
{
if ( rx_buff[2] == 0x99 )
{
PDMA_start
(
PDMA_CHANNEL_0,
(uint32_t)g_spi1_tx_buffer_b,
0x40011014,
sizeof(g_spi1_tx_buffer_b)
);
}
}
void setup_slave( void )
{
uint8_t slave_preamble[8] = { 9, 10, 11, 12, 13, 14, 16, 16 };
MSS_SPI_init( &g_mss_spi1 );
MSS_SPI_configure_slave_mode
(
&g_mss_spi0,
MSS_SPI_MODE2,
MSS_SPI_PCLK_DIV_64,
MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE
);
PDMA_init();
PDMA_configure
(
PDMA_CHANNEL_0,
TO_SPI_1,
LOW_PRIORITY | BYTE_TRANSFER | INC_SRC_ONE_BYTE
);
MSS_SPI_set_slave_block_buffers
(
&g_mss_spi1,
slave_preamble,
4,
g_spi1_rx_buffer,
sizeof(g_spi1_rx_buffer),
spi1_block_rx_handler
);
}
@endcode
*/
void MSS_SPI_set_slave_block_buffers
(
mss_spi_instance_t * this_spi,
const uint8_t * tx_buffer,
uint32_t tx_buff_size,
uint8_t * rx_buffer,
uint32_t rx_buff_size,
mss_spi_block_rx_handler_t block_rx_handler
);
#ifdef __cplusplus
}
#endif
#endif /* MSS_SPI_H_*/