Loading...
Searching...
No Matches

Low-level SPI peripheral driver. More...

Detailed Description

Low-level SPI peripheral driver.

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.

(Low-) Power Implications

As SPI buses are shared peripherals and the interfaces implements a transaction based paradigm, we leverage this for the SPI peripherals power management. After calling spi_init(), the SPI peripheral should be completely powered off (e.g. through peripheral clock gating). It should subsequently only be powered on and enabled in between spi_acquire() and spi_release() blocks.

In case the SPI driver implementation puts the active thread to sleep during data transfer (e.g. when using DMA), the implementation might need to block certain power states during that time.

Files

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

Data Structures

struct  spi_gpio_mode_t
 SPI gpio mode. More...
 

Macros

#define CONFIG_SPI_DMA_THRESHOLD_BYTES   16
 Threshold under which polling transfers are used instead of DMA TODO: determine at run-time based on SPI clock.
 
#define SPI_DEV(x)   (x)
 Default SPI device access macro.
 
#define SPI_UNDEF   (UINT_FAST8_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.
 

Typedefs

typedef uint_fast8_t 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 = -ENXIO , SPI_NOCS = -EINVAL , SPI_NOMODE = -EINVAL ,
  SPI_NOCLK = -EINVAL
}
 Status codes used by the SPI driver interface. More...
 
enum  spi_mode_t { 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 = 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.
 
void spi_init_pins (spi_t bus)
 Initialize the used SPI bus pins, i.e.
 
int spi_init_cs (spi_t bus, spi_cs_t cs)
 Initialize the given chip select pin.
 
void spi_deinit_pins (spi_t dev)
 Change the pins of the given SPI bus back to plain GPIO functionality.
 
gpio_t spi_pin_miso (spi_t dev)
 Get the MISO pin of the given SPI bus.
 
gpio_t spi_pin_mosi (spi_t dev)
 Get the MOSI pin of the given SPI bus.
 
gpio_t spi_pin_clk (spi_t dev)
 Get the CLK pin of the given SPI bus.
 
int spi_init_with_gpio_mode (spi_t bus, const spi_gpio_mode_t *mode)
 Initialize MOSI/MISO/SCLK pins with adapted GPIO modes.
 
void spi_acquire (spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
 Start a new SPI transaction.
 
void spi_release (spi_t bus)
 Finish an ongoing SPI transaction by releasing the given SPI bus.
 
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.
 
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.
 
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.
 
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.
 
static uint16_t spi_transfer_u16_be (spi_t bus, spi_cs_t cs, bool cont, uint16_t host_number)
 Transfer a 16 bit number in big endian byte order.
 

Macro Definition Documentation

◆ CONFIG_SPI_DMA_THRESHOLD_BYTES

#define CONFIG_SPI_DMA_THRESHOLD_BYTES   16

Threshold under which polling transfers are used instead of DMA TODO: determine at run-time based on SPI clock.

Definition at line 88 of file spi.h.

◆ SPI_CS_UNDEF

#define SPI_CS_UNDEF   (GPIO_UNDEF)

Define value for unused CS line.

Definition at line 109 of file spi.h.

◆ SPI_DEV

#define SPI_DEV (   x)    (x)

Default SPI device access macro.

Definition at line 95 of file spi.h.

◆ SPI_HWCS

#define SPI_HWCS (   x)    (SPI_CS_UNDEF)

Default SPI hardware chip select access macro.

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 120 of file spi.h.

◆ SPI_UNDEF

#define SPI_UNDEF   (UINT_FAST8_MAX)

Define global value for undefined SPI device.

Definition at line 102 of file spi.h.

Typedef Documentation

◆ spi_cs_t

typedef gpio_t spi_cs_t

Chip select pin type overlaps with gpio_t so it can be casted to this.

Definition at line 135 of file spi.h.

◆ spi_t

typedef uint_fast8_t spi_t

Default type for SPI devices.

Definition at line 127 of file spi.h.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Status codes used by the SPI driver interface.

Deprecated:
Use negative errno codes instead. The enum is still provided for backwards compatibility
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 144 of file spi.h.

◆ spi_clk_t

enum spi_clk_t

Available SPI clock speeds.

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 

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 185 of file spi.h.

◆ spi_mode_t

enum spi_mode_t

Available SPI modes, defining the configuration of clock polarity and clock phase.

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 

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 169 of file spi.h.

Function Documentation

◆ spi_acquire()

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

Start a new SPI transaction.

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).

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
Precondition
All parameters are valid and supported, otherwise an assertion blows up (if assertions are enabled).

◆ spi_deinit_pins()

void spi_deinit_pins ( spi_t  dev)

Change the pins of the given SPI bus back to plain GPIO functionality.

The pin mux of the MISO, MOSI and CLK pins of the bus will be changed back to default (GPIO) mode and the SPI bus is powered off. This allows to use the SPI pins for another function and return to SPI functionality again by calling spi_init_pins()

If you want the pin to be in a defined state, call gpio_init() on it.

The bus MUST not be acquired before initializing it, as this is handled internally by the spi_deinit_pins() function!

Calls to spi_acquire() will block until spi_init_pins() is called again.

Note
Until this is implemented on all platforms, this requires the periph_spi_reconfigure feature to be used.
Parameters
[in]devthe device to de-initialize

◆ spi_init()

void spi_init ( spi_t  bus)

Basic initialization of the given SPI 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

◆ spi_init_cs()

int spi_init_cs ( spi_t  bus,
spi_cs_t  cs 
)

Initialize the given chip select pin.

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
Return values
0success
-ENXIOinvalid device
-EINVALinvalid CS pin/line

◆ spi_init_pins()

void spi_init_pins ( spi_t  bus)

Initialize the used SPI bus pins, i.e.

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.

This function must be called after spi_deinit_pins to return the pins to SPI operation.

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

Parameters
[in]busSPI device the pins are configure for

◆ spi_init_with_gpio_mode()

int spi_init_with_gpio_mode ( spi_t  bus,
const spi_gpio_mode_t mode 
)

Initialize MOSI/MISO/SCLK pins with adapted GPIO modes.

Parameters
[in]busSPI device that is used with the given CS line
[in]modea pointer to a struct containing the 3 modes to use on each pin
Return values
0success
<0error

◆ spi_pin_clk()

gpio_t spi_pin_clk ( spi_t  dev)

Get the CLK pin of the given SPI bus.

Parameters
[in]devThe device to query
Note
Until this is implemented on all platforms, this requires the periph_spi_reconfigure feature to be used.
Returns
The GPIO used for the SPI CLK line.

◆ spi_pin_miso()

gpio_t spi_pin_miso ( spi_t  dev)

Get the MISO pin of the given SPI bus.

Parameters
[in]devThe device to query
Note
Until this is implemented on all platforms, this requires the periph_spi_reconfigure feature to be used.
Returns
The GPIO used for the SPI MISO line.

◆ spi_pin_mosi()

gpio_t spi_pin_mosi ( spi_t  dev)

Get the MOSI pin of the given SPI bus.

Parameters
[in]devThe device to query
Note
Until this is implemented on all platforms, this requires the periph_spi_reconfigure feature to be used.
Returns
The GPIO used for the SPI MOSI line.

◆ spi_release()

void spi_release ( spi_t  bus)

Finish an ongoing SPI transaction by releasing the given SPI bus.

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

Parameters
[in]busSPI device to release

◆ spi_transfer_byte()

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.

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
Returns
the received byte

◆ spi_transfer_bytes()

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.

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

◆ spi_transfer_reg()

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.

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
Returns
value that was read from the given register address

◆ spi_transfer_regs()

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.

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

◆ spi_transfer_u16_be()

static uint16_t spi_transfer_u16_be ( spi_t  bus,
spi_cs_t  cs,
bool  cont,
uint16_t  host_number 
)
inlinestatic

Transfer a 16 bit number in big endian byte order.

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]host_numbernumber to transfer in host byte order
Returns
The 16 bit number received in host byte order

Definition at line 444 of file spi.h.