ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
spi_zephyr.cpp
Go to the documentation of this file.
1#ifdef USE_ZEPHYR
2
3#include "spi_zephyr.h"
5#include "esphome/core/log.h"
6
7#include <algorithm>
8#include <cstring>
9
10namespace esphome::spi {
11
12ESPHOME_LOG_TAG(TAG, "spi.zephyr");
13
14// Words swapped per transceive for MSB-first 16-bit writes
15static constexpr size_t SWAP_BUFFER_WORDS = 64;
16
17static spi_operation_t build_operation(SPIBitOrder bit_order, SPIMode mode) {
18 spi_operation_t op = SPI_OP_MODE_MASTER | SPI_WORD_SET(8);
19 op |= (bit_order == BIT_ORDER_LSB_FIRST) ? SPI_TRANSFER_LSB : SPI_TRANSFER_MSB;
21 op |= SPI_MODE_CPOL;
23 op |= SPI_MODE_CPHA;
24 return op;
25}
26
27// release_device and write_only are not needed here: the Zephyr driver locks the bus per transfer,
28// and a null rx buffer already skips the receive DMA
30 bool release_device, bool write_only) {
31 return new ZephyrSPIDelegate(this, data_rate, bit_order, mode, cs_pin); // NOLINT
32}
33
35 GPIOPin *cs_pin)
36 : SPIDelegate(data_rate, bit_order, mode, cs_pin), bus_(bus) {
37 this->cfg_.frequency = data_rate;
38 this->cfg_.operation = build_operation(bit_order, mode);
39}
40
41// The driver skips a config at the address it applied last, so a delegate created later in this allocation
42// would run with the old settings: hand it the bus's own config before this one goes away.
44 if (this->bus_->active_ != this)
45 return;
46 this->bus_->active_ = nullptr;
47 spi_transceive(this->bus_->dev_, &this->bus_->idle_cfg_, nullptr, nullptr);
48}
49
50// The driver applies cfg_ (and the SCK idle level for CPOL) at the start of each transfer, so switch
51// it over with an empty transfer before CS goes low; otherwise SCK changes level while CS is active.
53 if (this->bus_->active_ != this) {
54 const int err = spi_transceive(this->bus_->dev_, &this->cfg_, nullptr, nullptr);
55 if (err == 0) {
56 this->bus_->active_ = this;
57 } else {
58 ESP_LOGE(TAG, "spi_transceive failed: %d", err);
59 }
60 }
62}
63
64// Buffers EasyDMA cannot reach (flash tables, for one) are copied by the nrfx SPIM driver itself,
65// CONFIG_SPI_NRFX_RAM_BUFFER_SIZE bytes at a time
66void ZephyrSPIDelegate::transceive_(const uint8_t *tx, uint8_t *rx, size_t length) {
67 if (length == 0)
68 return;
69 const spi_buf tx_buf{const_cast<uint8_t *>(tx), length}; // NOLINT(cppcoreguidelines-pro-type-const-cast)
70 const spi_buf rx_buf{rx, length};
71 const spi_buf_set tx_set{&tx_buf, 1};
72 const spi_buf_set rx_set{&rx_buf, 1};
73 const int err = spi_transceive(this->bus_->dev_, &this->cfg_, tx != nullptr ? &tx_set : nullptr,
74 rx != nullptr ? &rx_set : nullptr);
75 if (err != 0) {
76 ESP_LOGE(TAG, "spi_transceive failed: %d", err);
77 if (rx != nullptr)
78 memset(rx, 0, length);
79 }
80}
81
82uint8_t ZephyrSPIDelegate::transfer(uint8_t data) {
83 uint8_t rx = 0;
84 this->transceive_(&data, &rx, 1);
85 return rx;
86}
87
88void ZephyrSPIDelegate::transfer(const uint8_t *txbuf, uint8_t *rxbuf, size_t length) {
89 this->transceive_(txbuf, rxbuf, length);
90}
91
92void ZephyrSPIDelegate::write_array(const uint8_t *ptr, size_t length) { this->transceive_(ptr, nullptr, length); }
93
94void ZephyrSPIDelegate::write_array16(const uint16_t *data, size_t length) {
95 if (this->bit_order_ == BIT_ORDER_LSB_FIRST) {
96 this->write_array(reinterpret_cast<const uint8_t *>(data), length * 2);
97 return;
98 }
99 uint16_t buffer[SWAP_BUFFER_WORDS];
100 while (length != 0) {
101 const size_t partial = std::min(length, SWAP_BUFFER_WORDS);
102 for (size_t i = 0; i != partial; i++)
103 buffer[i] = byteswap(data[i]);
104 this->write_array(reinterpret_cast<const uint8_t *>(buffer), partial * 2);
105 data += partial;
106 length -= partial;
107 }
108}
109
110void ZephyrSPIDelegate::read_array(uint8_t *ptr, size_t length) { this->transceive_(nullptr, ptr, length); }
111
112} // namespace esphome::spi
113
114#endif // USE_ZEPHYR
BedjetMode mode
BedJet operating mode.
virtual void begin_transaction()
Definition spi.h:202
SPIBitOrder bit_order_
Definition spi.h:267
static SPIClockPhase get_phase(SPIMode mode)
Definition spi.h:159
static SPIClockPolarity get_polarity(SPIMode mode)
Definition spi.h:169
const ZephyrSPIDelegate * active_
Definition spi_zephyr.h:32
friend class ZephyrSPIDelegate
Definition spi_zephyr.h:13
SPIDelegate * get_delegate(uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin, bool release_device, bool write_only) override
void write_array16(const uint16_t *data, size_t length) override
void read_array(uint8_t *ptr, size_t length) override
ZephyrSPIDelegate(ZephyrSPIBus *bus, uint32_t data_rate, SPIBitOrder bit_order, SPIMode mode, GPIOPin *cs_pin)
void transceive_(const uint8_t *tx, uint8_t *rx, size_t length)
One spi_transceive; rx (if given) is zeroed when the transfer fails.
void write_array(const uint8_t *ptr, size_t length) override
uint8_t transfer(uint8_t data) override
uint32_t buffer
Definition gif.cpp:50
Implementation of SPI Controller mode.
Definition spi.cpp:9
SPIMode
Modes mapping to clock phase and polarity.
Definition spi.h:84
SPIBitOrder
The bit-order for SPI devices. This defines how the data read from and written to the device is inter...
Definition spi.h:46
@ BIT_ORDER_LSB_FIRST
The least significant bit is transmitted/received first.
Definition spi.h:48
ESPHOME_LOG_TAG(TAG, "spi")
@ CLOCK_POLARITY_HIGH
The clock signal idles on HIGH.
Definition spi.h:66
@ CLOCK_PHASE_TRAILING
The data is sampled on a trailing clock edge. (CPHA=1)
Definition spi.h:76
static void uint32_t
void byteswap()
uint16_t length
Definition tt21100.cpp:0