# idfxx_spi
Type-safe SPI master bus driver for ESP32.
📚 **[Full API Documentation](https://cleishm.github.io/idfxx/group__idfxx__spi.html)**
## Features
- SPI bus lifecycle management
- Support for DMA transfers
## Requirements
- ESP-IDF 5.5 or later
- C++23 compiler
## Installation
### ESP-IDF Component Manager
Add to your project's `idf_component.yml`:
```yaml
dependencies:
idfxx_spi:
version: "^2.0.0"
```
Or add `idfxx_spi` to the `REQUIRES` list in your component's `CMakeLists.txt`.
## Usage
### Basic Example
If `CONFIG_COMPILER_CXX_EXCEPTIONS` is enabled:
```cpp
try {
idfxx::spi::master_bus bus(
idfxx::spi::host_device::spi2,
idfxx::spi::dma_chan::ch_auto,
idfxx::spi::bus_config{ /* ... */ }
);
// Use bus
idfxx::log::info("SPI", "SPI bus initialized");
} catch (const std::system_error& e) {
idfxx::log::error("SPI", "Failed to create bus: {}", e.what());
}
```
### Result-based API
If `CONFIG_COMPILER_CXX_EXCEPTIONS` is *not* enabled, the result-based API must be used:
```cpp
#include <idfxx/spi/master>
#include <idfxx/log>
// Configure SPI bus
idfxx::spi::bus_config config{
.mosi = idfxx::gpio_23,
.miso = idfxx::gpio_19,
.sclk = idfxx::gpio_18,
.max_transfer_sz = 4096,
};
// Create SPI bus - returns idfxx::result<idfxx::spi::master_bus>
auto bus_result = idfxx::spi::master_bus::make(
idfxx::spi::host_device::spi2, // SPI host
idfxx::spi::dma_chan::ch_auto, // DMA channel (or dma_chan::disabled)
std::move(config) // Bus configuration. Using `std::move(...)` is not required, as the bus config
// is copyable, but it is included here for consistency with other classes.
);
if (!bus_result) {
idfxx::log::error("SPI", "Failed to create bus: {}", bus_result.error().message());
return;
}
auto bus = std::move(*bus_result);
idfxx::log::info("SPI", "SPI bus initialized");
```
### With DMA
```cpp
idfxx::spi::master_bus bus(
idfxx::spi::host_device::spi2,
idfxx::spi::dma_chan::ch_auto, // Automatic DMA channel selection
idfxx::spi::bus_config{
.mosi = idfxx::gpio_23,
.miso = idfxx::gpio_19,
.sclk = idfxx::gpio_18,
.max_transfer_sz = 32768, // Larger transfers with DMA
}
);
```
### Without DMA
```cpp
idfxx::spi::master_bus bus(
idfxx::spi::host_device::spi2,
idfxx::spi::dma_chan::disabled, // No DMA
idfxx::spi::bus_config{ /* ... */ }
);
```
### Integration with `idfxx_lcd`
The SPI bus is commonly used with LCD panels.
```cpp
#include <idfxx/spi/master>
#include <idfxx/panel_io>
// Create SPI bus
idfxx::spi::master_bus spi_bus(
idfxx::spi::host_device::spi2,
idfxx::spi::dma_chan::ch_auto,
idfxx::spi::bus_config{ /* ... */ }
);
// Create panel I/O using the bus
idfxx::panel_io panel_io(
spi_bus, // Reference to bus
idfxx::panel_io::spi_config{ /* ... */ }
);
// Caller must ensure spi_bus outlives panel_io
```
## API Overview
### `master_bus`
**Creation:**
- `make(host, dma_chan, config)` - Create SPI bus (result-based)
- `master_bus(host, dma_chan, config)` - Constructor (exception-based, if enabled)
**Properties:**
- `host()` - Get SPI host device
**Lifetime:**
- Non-copyable and move-only
- Destructor automatically cleans up resources
## SPI Hosts
ESP32 provides multiple SPI hosts via `idfxx::spi::host_device`:
- `host_device::spi1` - Typically used for flash
- `host_device::spi2` - General purpose (HSPI on some chips)
- `host_device::spi3` - General purpose (VSPI on some chips)
Check your ESP32 variant's documentation for available hosts.
## DMA Channels
Via `idfxx::spi::dma_chan`:
- `dma_chan::ch_auto` - Automatic DMA channel selection (recommended)
- `dma_chan::ch_1`, `dma_chan::ch_2` - Specific DMA channels (ESP32 only)
- `dma_chan::disabled` - No DMA (limited transfer size)
## Interrupt Configuration
`bus_config::intr_levels` and `bus_config::intr_flags` control the bus interrupt. The driver rejects the
following with `errc::invalid_arg` when the bus is created:
- `intr_flag::shared`, `intr_flag::edge` and `intr_flag::disabled`
- `intr_levels` level 4, 5, 6 and `nmi`
- `intr_flag::iram`, unless `CONFIG_SPI_MASTER_ISR_IN_IRAM` is enabled (and then all callbacks must be in IRAM)
## DMA Burst Size
With ESP-IDF 6.1 or later, `bus_config::dma_burst_size` sets the DMA burst size in bytes. Left unset, the driver
chooses. When set, the value must be one of the burst sizes supported by the chip's DMA controller, and is ignored on
chips whose burst size is not configurable.
## Important Notes
- **Dual API Pattern**: The component provides both result-based and exception-based APIs
- `make()` returns `result<master_bus>` (always available)
- Constructor throws `std::system_error` (requires `CONFIG_COMPILER_CXX_EXCEPTIONS`)
- Only one bus can be initialized per SPI host
- The bus must remain alive while devices using it exist
- DMA enables larger transfers but requires DMA-capable memory
- Maximum transfer size without DMA is ~64 bytes
- With DMA, transfer size is limited by `max_transfer_sz` in config; left unset, the driver default applies
- GPIO pins must not be used by other peripherals
## License
Apache License 2.0 - see [LICENSE](LICENSE) for details.
5aa7c84cf8254c6163ab3e02e489b9592a91c9f1
idf.py add-dependency "cleishm/idfxx_spi^2.0.0"