The friendly Operating System for the Internet of Things

Low-level SPI peripheral driver. More...

Detailed Description

This interface defines an abstraction for using a CPU's hardware SPI units. The interface only supports SPI master mode.

As SPI buses can have multiple devices connected to them they are to be considered as shared resources. To reflect this, the SPI interface is based on a transaction model. This requires that the bus needs to be acquired before usage and released afterwards, using the spi_acquire() and the spi_release() functions.

This interface supports both software and hardware chip select lines. This is reflected by the cpi_cs_t type, which overloads the gpio_t type with platform specific values for defining platform dependent hardware chip select lines.

Some devices have however very uncommon requirements on the usage and the timings of their chip select line. For those cases this interface allows to manage the chip select line manually from the user code (e.g. by calling gpio_set/clear explicitly) while deactivating the SPI driver internal chip select handling by passing GPIO_UNDEF as CS parameter.

In the time, when the SPI bus is not used, the SPI unit should be in low-power mode to save energy.

The SPI unit's initialization is split into 3 parts:

  1. spi_init() should be called once for each SPI unit defined by a board during system initialization.
  2. spi_init_cs() should be called during device driver initialization, as each chip select pin/line is used uniquely by a specific device, i.e. chip select lines are no shared resource.
  3. spi_acquire() needs to be called for each new transaction. This function configures the bus with specific parameters (clock, mode) for the duration of that transaction.

Files

file  spi.h
 Low-level SPI peripheral driver interface definition.
 

Macros

#define SPI_DEV(x)   (x)
 Default SPI device access macro.
 
#define SPI_UNDEF   (UINT_MAX)
 Define global value for undefined SPI device.
 
#define SPI_CS_UNDEF   (GPIO_UNDEF)
 Define value for unused CS line.
 
#define SPI_HWCS(x)   (SPI_CS_UNDEF)
 Default SPI hardware chip select access macro. More...
 

Typedefs

typedef unsigned int spi_t
 Default type for SPI devices.
 
typedef gpio_t spi_cs_t
 Chip select pin type overlaps with gpio_t so it can be casted to this.
 

Enumerations

enum  {
  SPI_OK = 0, SPI_NODEV = -1, SPI_NOCS = -2, SPI_NOMODE = -3,
  SPI_NOCLK = -4
}
 Status codes used by the SPI driver interface. More...
 
enum  spi_mode_t {
  SPI_MODE_0 = SPI_MODE_SEL(0, 0), SPI_MODE_1 = SPI_MODE_SEL(0, 1), SPI_MODE_2 = SPI_MODE_SEL(1, 0), SPI_MODE_3 = SPI_MODE_SEL(1, 1),
  SPI_MODE_0 = 0, SPI_MODE_1 = (SSI_CR0_SPH), SPI_MODE_2 = (SSI_CR0_SPO), SPI_MODE_3 = (SSI_CR0_SPO | SSI_CR0_SPH),
  SPI_MODE_0 = 0, SPI_MODE_1 = SPI_CONFIG_CPHA_Msk, SPI_MODE_2 = SPI_CONFIG_CPOL_Msk, SPI_MODE_3 = (SPI_CONFIG_CPOL_Msk | SPI_CONFIG_CPHA_Msk),
  SPI_MODE_0 = 0x0, SPI_MODE_1 = 0x1, SPI_MODE_2 = 0x2, SPI_MODE_3 = 0x3,
  SPI_MODE_0 = (SPI_CSR_NCPHA), SPI_MODE_1 = (0), SPI_MODE_2 = (SPI_CSR_CPOL | SPI_CSR_NCPHA), SPI_MODE_3 = (SPI_CSR_CPOL),
  SPI_MODE_0 = 0, SPI_MODE_1, SPI_MODE_2, SPI_MODE_3
}
 Available SPI modes, defining the configuration of clock polarity and clock phase. More...
 
enum  spi_clk_t {
  SPI_CLK_100KHZ = SPI_CLK_SEL(0, 1, 1), SPI_CLK_400KHZ = SPI_CLK_SEL(1, 1, 0), SPI_CLK_1MHZ = SPI_CLK_SEL(0, 0, 1), SPI_CLK_5MHZ = SPI_CLK_SEL(0, 0, 0),
  SPI_CLK_10MHZ = SPI_CLK_SEL(1, 0, 0), SPI_CLK_100KHZ = 0, SPI_CLK_400KHZ = 1, SPI_CLK_1MHZ = 2,
  SPI_CLK_5MHZ = 3, SPI_CLK_10MHZ = 4, SPI_CLK_100KHZ = 119, SPI_CLK_400KHZ = 29,
  SPI_CLK_1MHZ = 11, SPI_CLK_5MHZ = 2, SPI_CLK_10MHZ = 0, SPI_CLK_100KHZ = 100,
  SPI_CLK_400KHZ = 400, SPI_CLK_1MHZ = 1000, SPI_CLK_5MHZ = 5000, SPI_CLK_10MHZ = 10000,
  SPI_CLK_100KHZ = SPI_FREQUENCY_FREQUENCY_K125, SPI_CLK_400KHZ = SPI_FREQUENCY_FREQUENCY_K500, SPI_CLK_1MHZ = SPI_FREQUENCY_FREQUENCY_M1, SPI_CLK_5MHZ = SPI_FREQUENCY_FREQUENCY_M4,
  SPI_CLK_10MHZ = SPI_FREQUENCY_FREQUENCY_M8, SPI_CLK_100KHZ = 100000U, SPI_CLK_400KHZ = 400000U, SPI_CLK_1MHZ = 1000000U,
  SPI_CLK_5MHZ = 5000000U, SPI_CLK_10MHZ = 10000000U, SPI_CLK_100KHZ = (100000), SPI_CLK_400KHZ = (400000),
  SPI_CLK_1MHZ = (1000000), SPI_CLK_5MHZ = (5000000), SPI_CLK_10MHZ = (10000000), SPI_CLK_100KHZ = 0,
  SPI_CLK_400KHZ, SPI_CLK_1MHZ, SPI_CLK_5MHZ, SPI_CLK_10MHZ
}
 Available SPI clock speeds. More...
 

Functions

void spi_init (spi_t bus)
 Basic initialization of the given SPI bus. More...
 
void spi_init_pins (spi_t bus)
 Initialize the used SPI bus pins, i.e. More...
 
int spi_init_cs (spi_t bus, spi_cs_t cs)
 Initialize the given chip select pin. More...
 
int spi_acquire (spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
 Start a new SPI transaction. More...
 
void spi_release (spi_t bus)
 Finish an ongoing SPI transaction by releasing the given SPI bus. More...
 
uint8_t spi_transfer_byte (spi_t bus, spi_cs_t cs, bool cont, uint8_t out)
 Transfer one byte on the given SPI bus. More...
 
void spi_transfer_bytes (spi_t bus, spi_cs_t cs, bool cont, const void *out, void *in, size_t len)
 Transfer a number bytes using the given SPI bus. More...
 
uint8_t spi_transfer_reg (spi_t bus, spi_cs_t cs, uint8_t reg, uint8_t out)
 Transfer one byte to/from a given register address. More...
 
void spi_transfer_regs (spi_t bus, spi_cs_t cs, uint8_t reg, const void *out, void *in, size_t len)
 Transfer a number of bytes to/from a given register address. More...
 

Macro Definition Documentation

#define SPI_HWCS (   x)    (SPI_CS_UNDEF)

Per default, we map all hardware chip select lines to be not defined. If an implementation makes use of HW chip select lines, this value needs to be overridden by the corresponding CPU.

Definition at line 98 of file spi.h.

Enumeration Type Documentation

anonymous enum
Enumerator
SPI_OK 

everything went as planned

SPI_NODEV 

invalid SPI bus specified

SPI_NOCS 

invalid chip select line specified

SPI_NOMODE 

selected mode is not supported

SPI_NOCLK 

selected clock value is not supported

Definition at line 119 of file spi.h.

enum spi_clk_t

The actual speed of the bus can vary to some extend, as the combination of CPU clock and available prescaler values on certain platforms may not make the exact values possible.

Enumerator
SPI_CLK_100KHZ 

16/128 -> 125KHz

SPI_CLK_400KHZ 

16/32 -> 500KHz

SPI_CLK_1MHZ 

16/16 -> 1MHz

SPI_CLK_5MHZ 

16/4 -> 4MHz

SPI_CLK_10MHZ 

16/2 -> 8MHz

SPI_CLK_100KHZ 

drive the SPI bus with 100KHz

SPI_CLK_400KHZ 

drive the SPI bus with 400KHz

SPI_CLK_1MHZ 

drive the SPI bus with 1MHz

SPI_CLK_5MHZ 

drive the SPI bus with 5MHz

SPI_CLK_10MHZ 

drive the SPI bus with 10MHz

SPI_CLK_100KHZ 

drive the SPI bus with 100KHz

SPI_CLK_400KHZ 

drive the SPI bus with 400KHz

SPI_CLK_1MHZ 

drive the SPI bus with 1MHz

SPI_CLK_5MHZ 

drive the SPI bus with 5MHz

SPI_CLK_10MHZ 

actual: 12 MHz

SPI_CLK_100KHZ 

drive the SPI bus with 100KHz

SPI_CLK_400KHZ 

drive the SPI bus with 400KHz

SPI_CLK_1MHZ 

drive the SPI bus with 1MHz

SPI_CLK_5MHZ 

drive the SPI bus with 5MHz

SPI_CLK_10MHZ 

drive the SPI bus with 10MHz

SPI_CLK_100KHZ 

100KHz

SPI_CLK_400KHZ 

400KHz

SPI_CLK_1MHZ 

1MHz

SPI_CLK_5MHZ 

5MHz

SPI_CLK_10MHZ 

10MHz

SPI_CLK_100KHZ 

drive the SPI bus with 100KHz

SPI_CLK_400KHZ 

drive the SPI bus with 400KHz

SPI_CLK_1MHZ 

drive the SPI bus with 1MHz

SPI_CLK_5MHZ 

drive the SPI bus with 5MHz

SPI_CLK_10MHZ 

drive the SPI bus with 10MHz

SPI_CLK_100KHZ 

100KHz

SPI_CLK_400KHZ 

400KHz

SPI_CLK_1MHZ 

1MHz

SPI_CLK_5MHZ 

5MHz

SPI_CLK_10MHZ 

10MHz

SPI_CLK_100KHZ 

drive the SPI bus with 100KHz

SPI_CLK_400KHZ 

drive the SPI bus with 400KHz

SPI_CLK_1MHZ 

drive the SPI bus with 1MHz

SPI_CLK_5MHZ 

drive the SPI bus with 5MHz

SPI_CLK_10MHZ 

drive the SPI bus with 10MHz

Definition at line 160 of file spi.h.

enum spi_mode_t

RIOT is using the mode numbers as commonly defined by most vendors (https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers):

  • MODE_0: CPOL=0, CPHA=0 - The first data bit is sampled by the receiver on the first SCK rising SCK edge (this mode is used most often).
  • MODE_1: CPOL=0, CPHA=1 - The first data bit is sampled by the receiver on the second rising SCK edge.
  • MODE_2: CPOL=1, CPHA=0 - The first data bit is sampled by the receiver on the first falling SCK edge.
  • MODE_3: CPOL=1, CPHA=1 - The first data bit is sampled by the receiver on the second falling SCK edge.
Enumerator
SPI_MODE_0 

mode 0

SPI_MODE_1 

mode 1

SPI_MODE_2 

mode 2

SPI_MODE_3 

mode 3

SPI_MODE_0 

CPOL=0, CPHA=0.

SPI_MODE_1 

CPOL=0, CPHA=1.

SPI_MODE_2 

CPOL=1, CPHA=0.

SPI_MODE_3 

CPOL=1, CPHA=1.

SPI_MODE_0 

CPOL=0, CPHA=0.

SPI_MODE_1 

CPOL=0, CPHA=1.

SPI_MODE_2 

CPOL=1, CPHA=0.

SPI_MODE_3 

CPOL=1, CPHA=1.

SPI_MODE_0 

CPOL=0, CPHA=0.

SPI_MODE_1 

CPOL=0, CPHA=1.

SPI_MODE_2 

CPOL=1, CPHA=0.

SPI_MODE_3 

CPOL=1, CPHA=1.

SPI_MODE_0 

CPOL=0, CPHA=0.

SPI_MODE_1 

CPOL=0, CPHA=1.

SPI_MODE_2 

CPOL=1, CPHA=0.

SPI_MODE_3 

CPOL=1, CPHA=1.

SPI_MODE_0 

CPOL=0, CPHA=0.

SPI_MODE_1 

CPOL=0, CPHA=1.

SPI_MODE_2 

CPOL=1, CPHA=0.

SPI_MODE_3 

CPOL=1, CPHA=1.

Definition at line 144 of file spi.h.

Function Documentation

int spi_acquire ( spi_t  bus,
spi_cs_t  cs,
spi_mode_t  mode,
spi_clk_t  clk 
)

Starting a new SPI transaction will get exclusive access to the SPI bus and configure it according to the given values. If another SPI transaction is active when this function is called, this function will block until the other transaction is complete (spi_relase was called).

Note
This function expects the bus and the cs parameters to be valid (they are checked in spi_init and spi_init_cs before)
Parameters
[in]busSPI device to access
[in]cschip select pin/line to use, set to SPI_CS_UNDEF if chip select should not be handled by the SPI driver
[in]modemode to use for the new transaction
[in]clkbus clock speed to use for the transaction
Returns
SPI_OK on success
SPI_NOMODE if given mode is not supported
SPI_NOCLK if given clock speed is not supported
void spi_init ( spi_t  bus)

This function does the basic initialization including pin configuration for MISO, MOSI, and CLK pins. After initialization, the given device should be in power down state.

This function is intended to be called by the board initialization code during system startup to prepare the (shared) SPI device for further usage. It uses the board specific initialization parameters as defined in the board's periph_conf.h.

Errors (e.g. invalid bus parameter) are not signaled through a return value, but should be signaled using the assert() function internally.

Note
This function MUST not be called more than once per bus!
Parameters
[in]busSPI device to initialize
int spi_init_cs ( spi_t  bus,
spi_cs_t  cs 
)

The chip select can be any generic GPIO pin (e.g. GPIO_PIN(x,y)), or it can be a hardware chip select line. The existence and number of hardware chip select lines depends on the underlying platform and the actual pins used for hardware chip select lines are defined in the board's periph_conf.h.

Define the used chip select line using the SPI_HWCS(x) macro for hardware chip select line x or the GPIO_PIN(x,y) macro for using any GPIO pin for manual chip select.

Parameters
[in]busSPI device that is used with the given CS line
[in]cschip select pin to initialize
Returns
SPI_OK on success
SPI_NODEV on invalid device
SPI_NOCS on invalid CS pin/line
void spi_init_pins ( spi_t  bus)

MISO, MOSI, and CLK

After calling spi_init, the pins must be initialized (i.e. spi_init is calling this function internally). In normal cases, this function will not be used. But there are some devices (e.g. CC110x), that use SPI bus lines also for other purposes and need the option to dynamically re-configure one or more of the used pins. So they can take control over certain pins and return control back to the SPI driver using this function.

The pins used are configured in the board's periph_conf.h.

Parameters
[in]busSPI device the pins are configure for
void spi_release ( spi_t  bus)

After release, the given SPI bus should be fully powered down until acquired again.

Parameters
[in]busSPI device to release
uint8_t spi_transfer_byte ( spi_t  bus,
spi_cs_t  cs,
bool  cont,
uint8_t  out 
)
Parameters
[in]busSPI device to use
[in]cschip select pin/line to use, set to SPI_CS_UNDEF if chip select should not be handled by the SPI driver
[in]contif true, keep device selected after transfer
[in]outbyte to send out, set NULL if only receiving
Returns
the received byte
void spi_transfer_bytes ( spi_t  bus,
spi_cs_t  cs,
bool  cont,
const void *  out,
void *  in,
size_t  len 
)
Parameters
[in]busSPI device to use
[in]cschip select pin/line to use, set to SPI_CS_UNDEF if chip select should not be handled by the SPI driver
[in]contif true, keep device selected after transfer
[in]outbuffer to send data from, set NULL if only receiving
[out]inbuffer to read into, set NULL if only sending
[in]lennumber of bytes to transfer
uint8_t spi_transfer_reg ( spi_t  bus,
spi_cs_t  cs,
uint8_t  reg,
uint8_t  out 
)

This function is a shortcut function for easier handling of SPI devices that implement a register based access scheme.

Parameters
[in]busSPI device to use
[in]cschip select pin/line to use, set to SPI_CS_UNDEF if chip select should not be handled by the SPI driver
[in]regregister address to transfer data to/from
[in]outbyte to send, set NULL if only receiving data
Returns
value that was read from the given register address
void spi_transfer_regs ( spi_t  bus,
spi_cs_t  cs,
uint8_t  reg,
const void *  out,
void *  in,
size_t  len 
)

This function is a shortcut function for easier handling of SPI devices that implement a register based access scheme.

Parameters
[in]busSPI device to use
[in]cschip select pin/line to use, set to SPI_CS_UNDEF if chip select should not be handled by the SPI driver
[in]regregister address to transfer data to/from
[in]outbuffer to send data from, set NULL if only receiving
[out]inbuffer to read into, set NULL if only sending
[in]lennumber of bytes to transfer