AVRTools
A Library for the AVR ATmega328 and ATmega2560 Microcontrollers
Classes | Enumerations | Functions
SPI Namespace Reference

This namespace bundles an interface to the SPI hardware subsystem on the AVR ATMega328p (Arduino Uno) and ATMega2560 (Arduino Mega) microcontrollers. It provides logical cohesion for functions implement the Master portion of the SPI protocol and prevents namespace collisions. More...

Classes

class  SPISettings
 A class that binds settings for configuring SPI transmissions. More...
 

Enumerations

enum  ByteOrder { kLsbFirst, kMsbFirst }
 An enumeration that defines the byte order for multibyte SPI transmissions. More...
 
enum  SpiMode { kSpiMode0, kSpiMode1, kSpiMode2, kSpiMode3 }
 An enumeration that defines the modes available for SPI transmissions. More...
 

Functions

void enable ()
 Enable the SPI subsystem for transmission. More...
 
void disable ()
 Disable the SPI subsystem, precluding further transmissions. More...
 
void configure (SPISettings settings)
 Set the configuration of SPI subsystem to match the needs of the system you are going to communicate with. More...
 
uint8_t transmit (uint8_t data)
 Transmit a single byte using the SPI subsystem. More...
 
uint16_t transmit16 (uint16_t data)
 Transmit a word-sized integer (two bytes) using the SPI subsystem. The order in which the bytes are sent is determined by the bit order configuration that has been set. More...
 
uint32_t transmit32 (uint32_t data)
 Transmit a long-word-sized integer (four bytes) using the SPI subsystem. The order in which the bytes are sent is determined by the bit order configuration that has been set. More...
 
void transmit (uint8_t *buffer, size_t count)
 Transmit an array of bytes using the SPI subsystem. The bytes are transmitted in array order. More...
 

Detailed Description

This namespace bundles an interface to the SPI hardware subsystem on the AVR ATMega328p (Arduino Uno) and ATMega2560 (Arduino Mega) microcontrollers. It provides logical cohesion for functions implement the Master portion of the SPI protocol and prevents namespace collisions.

These interfaces are synchronous, based on polling the flag in the SPI status register to determine transmission is complete and refill the transmit register with data. While it is possible to create an interrupt driven, asynchronous interface to the SPI subsystem, SPI-based communications are so fast that interrupt-based implementations are slower than polling by nearly a factor of 2. This is based on actual testing data which you can review here. What happens is that SPI can work at half the CPU frequency, which means the CPU can only execute about 16 instructions per byte sent. When the CPU is calling interrupts that often, the overhead of calling the interrupt function dominates, and is greater than the overhead of a simple polling loop.

The AVRTools implementation is based in part on the Arduino Library SPI module. In particular, the SPISettings class from the Arduino library is very cleverly and efficiently coded and has been adopted here. The lessons learned by the Arduino library SPI authors in correctly initializing the SPI subsystem have also been incorporated into this implementation. However, the packaging of the interface is somewhat different the AVRTools implementation takes a different approach to deconflicting SPI usage between the main thread of code execution and interrupt code.

The fundamental problem is this: if SPI is used in both the main code and in interrupt code, then it is important to ensure that the SPI "transactions" not be interleaved, that only one SPI "transaction" happen at a time. More specifically, you have to ensure that interrupt code using SPI does not interrupt an on-going SPI transaction in the main thread. The Arduino library achieves this by requiring library users to register any interrupts that use SPI and then requirng users to formally define (via function calls) the beginning and end of an SPI "transaction". The AVRTools library instead provides tools (via the InterruptUtils module) to temporarily suppress selected interrupts while the main thread is executing an SPI transaction. This approach allows more fine-tuned control of interrupt suppression, automatically restores interrupts when the SPI transaction is complete (no risk of a missing "end-of-transaction"), and does it with less overhead and memory footprint than the Arduino SPI library. The following code snippet illustrates how to protect main thread SPI usage from conflicts with SPI usage by two external interrupt handlers:

uint8_t send( uint8_t data )
{
// SPI is used by the interrupt functions that respond to external interrupts 0 and 1,
// so to prevent clashes, we suppress these two external interrupts for
// the duration of this function
// Configure SPI
SPI::configure( SPISettings( 4000000, SPI::kLsbFirst, SPI::kSpiMode2 ) );
// Set the remote slave SS pin low to initiate a transmission
setGpioPinLow( pConnectedToSlaveSSpin );
// Transmit
uint8_t retVal = SPI::transmit( data );
// Set the remote slave SS pin high to terminate the transmission
setGpioPinLow( pConnectedToSlaveSSpin );
// Interrupts automatically reset when this function exits
return retVal;
}
Note
This module implements SPI master mode only.

Enumeration Type Documentation

§ ByteOrder

An enumeration that defines the byte order for multibyte SPI transmissions.

Enumerator
kLsbFirst 

Least significant byte first.

kMsbFirst 

Most significant byte first.

§ SpiMode

An enumeration that defines the modes available for SPI transmissions.

There are four modes controlling whether data is shifted in and out on the rising or falling edge of the data clock signal (called the phase, CPHA), and whether the clock is idle when high or low (called the polarity, CPOL). The four modes are simply the possible combinations of phase and polarity.

Enumerator
kSpiMode0 

Phase falling, idle low (CPHA = 0, CPOL = 0)

kSpiMode1 

Phase rising, idle low (CPHA = 1, CPOL = 0)

kSpiMode2 

Phase falling, idle high (CPHA = 0, CPOL = 1)

kSpiMode3 

Phase rising, idle high (CPHA = 1, CPOL = 1)

Function Documentation

§ configure()

void SPI::configure ( SPISettings  settings)
inline

Set the configuration of SPI subsystem to match the needs of the system you are going to communicate with.

You should always configure the SPI subsystem before transmitting any data. The configuration settings remain in place until a subsequent call to this function or until you disable SPI.

Note
If you are using SPI both from interrupts and from the main thread of execution, you must protect SPI onfigurations and transmissions from interleaving. To do this, disable interrupts in the main thread by using the appropriate objects from InterruptUtils. Interrupts should be disabled starting before setting the configuration until the end of the corresponding data transmission. For example:
uint8_t send( uint8_t data )
{
// SPI is used by the interrupt functions that respond to external interrupts 0 and 1,
// so to prevent clashes, we suppress these two external interrupts for
// the duration of this function
// Configure SPI
SPI::configure( SPISettings( 4000000, SPI::kLsbFirst, SPI::kSpiMode2 ) );
// Set the remote slave SS pin low to initiate a transmission
setGpioPinLow( pConnectedToSlaveSSpin );
// Transmit
uint8_t retVal = SPI::transmit( data );
// Set the remote slave SS pin high to terminate the transmission
setGpioPinLow( pConnectedToSlaveSSpin );
// Interrupts automatically reset when this function exits
return retVal;
}

§ disable()

void SPI::disable ( )

Disable the SPI subsystem, precluding further transmissions.

This call disables the SPI hardware, releasing the MOSI, MISO, CLK, and SS pins for other uses.

Note
No further SPI transmissions should be made after calling this function, unless you re-enable the SPI subsystem by again calling enable().

§ enable()

void SPI::enable ( )

Enable the SPI subsystem for transmission.

This call enables the SPI hardware and configures the MOSI, MISO, CLK, and SS pins, making them unavailable for other uses. It also sets a default configuration of the SPI subsystem to a maximum transmission speed of 8 MHz, most significant bit first, and kSpiMode0.

Note
Even though SPI is configured in master-mode, the configuration of the SS pin is affected. The SS pin is set to output to prevent inadvertent automatic triggering of slave-mode by the SPI hardware (this happens if a low signal is received on the SS pin). Although the SS pin must be in output mode, it can still be used as a general purpose output port (it doesn't affect SPI operations as long as it remains in output mode).

§ transmit() [1/2]

uint8_t SPI::transmit ( uint8_t  data)
inline

Transmit a single byte using the SPI subsystem.

  • data the byte to be transmitted.
Returns
the byte received from the SPI subsystem.

§ transmit() [2/2]

void SPI::transmit ( uint8_t *  buffer,
size_t  count 
)
inline

Transmit an array of bytes using the SPI subsystem. The bytes are transmitted in array order.

  • buffer the array of bytes to transmit. Incoming bytes are also stored here, replacing the outgoing data, byte-for-byte.
Returns
nothing, but the received stream of bytes is loaded into the buffer, replacing the data originally in the buffer.

§ transmit16()

uint16_t SPI::transmit16 ( uint16_t  data)
inline

Transmit a word-sized integer (two bytes) using the SPI subsystem. The order in which the bytes are sent is determined by the bit order configuration that has been set.

  • data the word-sized integer (two bytes) to be transmitted.
Returns
the word-sized integer (two bytes) received from the SPI subsystem, with byte order determined by the bit order configuration that has been set.

§ transmit32()

uint32_t SPI::transmit32 ( uint32_t  data)

Transmit a long-word-sized integer (four bytes) using the SPI subsystem. The order in which the bytes are sent is determined by the bit order configuration that has been set.

  • data the long-word-sized integer (four bytes) to be transmitted.
Returns
the long-word-sized integer(four bytes) received from the SPI subsystem, with byte order determined by the bit order configuration that has been set.