SPI

The spi component provides a C++ wrapper around ESP-IDF’s SPI master driver.

Spi owns the bus and Spi::Device owns attached peripherals on that bus.

API Reference

Header File

Classes

class Spi : public espp::BaseComponent

SPI master wrapper and helpers.

`Spi` owns an SPI bus and can create one or more attached `Device` instances. Those devices support blocking reads/writes, queued transactions, and bus acquisition.

Example

  constexpr spi_host_device_t spi_host = SPI2_HOST;
  constexpr auto sclk_gpio = GPIO_NUM_36;
  constexpr auto mosi_gpio = GPIO_NUM_38;
  constexpr auto miso_gpio = GPIO_NUM_35;
  constexpr auto cs_gpio = GPIO_NUM_37;
  constexpr uint8_t read_address = 0x80;

  espp::Spi spi({
      .host = spi_host,
      .sclk_io_num = sclk_gpio,
      .mosi_io_num = mosi_gpio,
      .miso_io_num = miso_gpio,
      .max_transfer_sz = 16,
  });

  std::error_code ec;
  auto device = spi.add_device(
      {
          .address_bits = 8,
          .mode = 0,
          .clock_speed_hz = 1 * 1000 * 1000,
          .cs_io_num = cs_gpio,
          .queue_size = 1,
      },
      ec);
  if (ec || !device) {
    std::printf("Failed to create SPI device: %s\n", ec.message().c_str());
    return;
  }

  std::array<uint8_t, 2> rx_data{};
  if (!device->read(rx_data, {.address = read_address}, ec)) {
    std::printf("SPI read failed: %s\n", ec.message().c_str());
    return;
  }

  std::printf("Read bytes: 0x%02x 0x%02x\n", rx_data[0], rx_data[1]);

Public Functions

explicit Spi(const Config &config)

Construct the SPI bus wrapper.

Parameters:

config – SPI bus configuration.

~Spi()

Deinitialize the SPI bus and remove any remaining devices.

void init(std::error_code &ec)

Initialize the SPI bus.

Parameters:

ec – Error code populated on failure.

void deinit(std::error_code &ec)

Deinitialize the SPI bus.

Parameters:

ec – Error code populated on failure.

bool initialized() const

Check whether the SPI bus is initialized.

Returns:

True if the SPI bus is initialized.

spi_host_device_t host() const

Get the configured SPI host.

Returns:

Configured SPI host controller.

std::shared_ptr<Device> add_device(const DeviceConfig &config, std::error_code &ec)

Add a device to the SPI bus.

Parameters:
  • config – Device configuration.

  • ec – Error code populated on failure.

Returns:

Shared pointer to the registered device, or nullptr on failure.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

Public Static Functions

static spi_bus_config_t make_bus_config(const Config &config)

Convert a `Spi::Config` into an ESP-IDF `spi_bus_config_t`.

Parameters:

config – High-level SPI bus configuration.

Returns:

Equivalent ESP-IDF bus configuration.

static spi_device_interface_config_t make_device_config(const DeviceConfig &config)

Convert a `Spi::DeviceConfig` into an ESP-IDF device config.

Parameters:

config – High-level SPI device configuration.

Returns:

Equivalent ESP-IDF device interface configuration.

class BusLock

RAII helper for holding an acquired SPI device bus lock.

Public Functions

BusLock()

Construct an empty bus lock.

BusLock(BusLock &&other) noexcept

Move-construct the bus lock.

Parameters:

other – Lock to move from.

BusLock &operator=(BusLock &&other) noexcept

Move-assign the bus lock.

Parameters:

other – Lock to move from.

Returns:

Reference to this lock.

~BusLock()

Release the held bus lock on destruction.

void release()

Release the held SPI bus lock, if any.

explicit operator bool() const

Check whether this object currently owns a bus lock.

Returns:

True if a bus lock is held.

struct Config

Bus-level configuration for the SPI master.

Public Members

int isr_core_id = -1

Core on which to initialize the SPI bus.

spi_host_device_t host = SPI2_HOST

SPI host controller to use.

gpio_num_t sclk_io_num = GPIO_NUM_NC

Clock pin.

gpio_num_t mosi_io_num = GPIO_NUM_NC

MOSI pin.

gpio_num_t miso_io_num = GPIO_NUM_NC

MISO pin.

gpio_num_t quadwp_io_num = GPIO_NUM_NC

Quad WP pin.

gpio_num_t quadhd_io_num = GPIO_NUM_NC

Quad HD pin.

int max_transfer_sz = 0

Maximum transfer size in bytes.

uint32_t bus_flags = 0

ESP-IDF bus configuration flags.

int intr_flags = 0

Interrupt allocation flags.

spi_dma_chan_t dma_channel = SPI_DMA_CH_AUTO

DMA channel selection.

bool auto_init = true

Automatically initialize on construction.

Logger::Verbosity log_level = Logger::Verbosity::WARN

Logger verbosity.

class Device : public espp::BaseComponent

Attached SPI device wrapper.

Public Functions

explicit Device(Logger::Verbosity log_level, const DeviceConfig &config)

Construct an unattached device wrapper.

Parameters:
  • log_levelLogger verbosity inherited from the owning SPI bus.

  • config – Device configuration.

~Device()

Remove the device from the SPI bus on destruction.

bool initialized() const

Check whether the device is attached to the SPI bus.

Returns:

True if the device has a valid ESP-IDF handle.

spi_device_handle_t handle() const

Get the underlying ESP-IDF device handle.

Returns:

SPI device handle, or nullptr if unattached.

const DeviceConfig &config() const

Get the configuration used to create this device.

Returns:

Device configuration.

void remove_device(std::error_code &ec)

Remove this device from the SPI bus.

Parameters:

ec – Error code populated on failure.

bool transmit(spi_transaction_t &transaction, std::error_code &ec)

Submit a blocking SPI transaction.

Parameters:
  • transaction – Transaction to execute.

  • ec – Error code populated on failure.

Returns:

True on success.

bool polling_transmit(spi_transaction_t &transaction, std::error_code &ec)

Submit a polling SPI transaction.

Parameters:
  • transaction – Transaction to execute.

  • ec – Error code populated on failure.

Returns:

True on success.

bool queue_transaction(spi_transaction_t &transaction, TickType_t timeout, std::error_code &ec)

Queue an asynchronous SPI transaction.

Parameters:
  • transaction – Transaction to queue.

  • timeout – Queue timeout in FreeRTOS ticks.

  • ec – Error code populated on failure.

Returns:

True on success.

bool get_transaction_result(spi_transaction_t **transaction, TickType_t timeout, std::error_code &ec)

Wait for a queued SPI transaction to complete.

Parameters:
  • transaction – Filled with the completed transaction pointer.

  • timeout – Wait timeout in FreeRTOS ticks.

  • ec – Error code populated on failure.

Returns:

True on success.

BusLock acquire_bus(TickType_t timeout, std::error_code &ec)

Acquire exclusive access to the SPI bus for this device.

Parameters:
  • timeout – Acquire timeout in FreeRTOS ticks.

  • ec – Error code populated on failure.

Returns:

RAII bus lock object.

bool write(std::span<const uint8_t> data, const TransactionConfig &config, std::error_code &ec)

Write a transmit buffer using the configured per-transaction overrides.

Parameters:
  • data – Data to transmit.

  • config – Transaction overrides.

  • ec – Error code populated on failure.

Returns:

True on success.

bool read(std::span<uint8_t> data, const TransactionConfig &config, std::error_code &ec)

Read data using the configured per-transaction overrides.

Parameters:
  • data – Receive buffer to fill.

  • config – Transaction overrides.

  • ec – Error code populated on failure.

Returns:

True on success.

bool transfer(std::span<const uint8_t> tx_data, std::span<uint8_t> rx_data, const TransactionConfig &config, std::error_code &ec)

Perform a combined transmit/receive transaction.

Parameters:
  • tx_data – Transmit buffer.

  • rx_data – Receive buffer.

  • config – Transaction overrides.

  • ec – Error code populated on failure.

Returns:

True on success.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

struct DeviceConfig

Per-device configuration for a device attached to the SPI bus.

Public Members

int command_bits = 0

Number of command bits sent before payload data.

int address_bits = 0

Number of address bits sent before payload data.

int dummy_bits = 0

Number of dummy bits inserted before payload data.

uint8_t mode = 0

SPI mode.

int clock_speed_hz = 1 * 1000 * 1000

Device clock speed.

int input_delay_ns = 0

Input delay in nanoseconds.

gpio_num_t cs_io_num = GPIO_NUM_NC

Chip-select pin.

int queue_size = 1

Queue depth for asynchronous transactions.

uint32_t flags = 0

ESP-IDF device flags.

uint16_t cs_ena_pretrans = 0

CS lead time in SPI bit-cycles.

uint16_t cs_ena_posttrans = 0

CS hold time in SPI bit-cycles.

transaction_cb_t pre_cb = nullptr

Optional pre-transfer callback.

transaction_cb_t post_cb = nullptr

Optional post-transfer callback.

struct TransactionConfig

Per-transaction overrides for read/write/transfer helpers.

Public Members

uint16_t command = 0

Command value for this transaction.

uint64_t address = 0

Address value for this transaction.

uint32_t flags = 0

ESP-IDF transaction flags.

size_t rx_length_bits = 0

Optional receive length override, in bits. For this byte-oriented API it must be a multiple of 8, must not exceed the RX buffer capacity, and must not exceed the TX bit length when both TX and RX are used in the same transaction.

class BusLock

RAII helper for holding an acquired SPI device bus lock.

Public Functions

BusLock()

Construct an empty bus lock.

BusLock(BusLock &&other) noexcept

Move-construct the bus lock.

Parameters:

other – Lock to move from.

BusLock &operator=(BusLock &&other) noexcept

Move-assign the bus lock.

Parameters:

other – Lock to move from.

Returns:

Reference to this lock.

~BusLock()

Release the held bus lock on destruction.

void release()

Release the held SPI bus lock, if any.

explicit operator bool() const

Check whether this object currently owns a bus lock.

Returns:

True if a bus lock is held.

class Device : public espp::BaseComponent

Attached SPI device wrapper.

Public Functions

explicit Device(Logger::Verbosity log_level, const DeviceConfig &config)

Construct an unattached device wrapper.

Parameters:
  • log_levelLogger verbosity inherited from the owning SPI bus.

  • config – Device configuration.

~Device()

Remove the device from the SPI bus on destruction.

bool initialized() const

Check whether the device is attached to the SPI bus.

Returns:

True if the device has a valid ESP-IDF handle.

spi_device_handle_t handle() const

Get the underlying ESP-IDF device handle.

Returns:

SPI device handle, or nullptr if unattached.

const DeviceConfig &config() const

Get the configuration used to create this device.

Returns:

Device configuration.

void remove_device(std::error_code &ec)

Remove this device from the SPI bus.

Parameters:

ec – Error code populated on failure.

bool transmit(spi_transaction_t &transaction, std::error_code &ec)

Submit a blocking SPI transaction.

Parameters:
  • transaction – Transaction to execute.

  • ec – Error code populated on failure.

Returns:

True on success.

bool polling_transmit(spi_transaction_t &transaction, std::error_code &ec)

Submit a polling SPI transaction.

Parameters:
  • transaction – Transaction to execute.

  • ec – Error code populated on failure.

Returns:

True on success.

bool queue_transaction(spi_transaction_t &transaction, TickType_t timeout, std::error_code &ec)

Queue an asynchronous SPI transaction.

Parameters:
  • transaction – Transaction to queue.

  • timeout – Queue timeout in FreeRTOS ticks.

  • ec – Error code populated on failure.

Returns:

True on success.

bool get_transaction_result(spi_transaction_t **transaction, TickType_t timeout, std::error_code &ec)

Wait for a queued SPI transaction to complete.

Parameters:
  • transaction – Filled with the completed transaction pointer.

  • timeout – Wait timeout in FreeRTOS ticks.

  • ec – Error code populated on failure.

Returns:

True on success.

BusLock acquire_bus(TickType_t timeout, std::error_code &ec)

Acquire exclusive access to the SPI bus for this device.

Parameters:
  • timeout – Acquire timeout in FreeRTOS ticks.

  • ec – Error code populated on failure.

Returns:

RAII bus lock object.

bool write(std::span<const uint8_t> data, const TransactionConfig &config, std::error_code &ec)

Write a transmit buffer using the configured per-transaction overrides.

Parameters:
  • data – Data to transmit.

  • config – Transaction overrides.

  • ec – Error code populated on failure.

Returns:

True on success.

bool read(std::span<uint8_t> data, const TransactionConfig &config, std::error_code &ec)

Read data using the configured per-transaction overrides.

Parameters:
  • data – Receive buffer to fill.

  • config – Transaction overrides.

  • ec – Error code populated on failure.

Returns:

True on success.

bool transfer(std::span<const uint8_t> tx_data, std::span<uint8_t> rx_data, const TransactionConfig &config, std::error_code &ec)

Perform a combined transmit/receive transaction.

Parameters:
  • tx_data – Transmit buffer.

  • rx_data – Receive buffer.

  • config – Transaction overrides.

  • ec – Error code populated on failure.

Returns:

True on success.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger