AVRTools
A Library for the AVR ATmega328 and ATmega2560 Microcontrollers
|
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... | |
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:
enum SPI::ByteOrder |
enum SPI::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.
|
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.
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.
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.
|
inline |
Transmit a single byte using the SPI subsystem.
data
the byte to be transmitted.
|
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.
|
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.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.