libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::ESP32SPI Class Reference
Inheritance diagram for LibXR::ESP32SPI:
[legend]
Collaboration diagram for LibXR::ESP32SPI:
[legend]

Public Member Functions

 ESP32SPI (spi_host_device_t host, int sclk_pin, int miso_pin, int mosi_pin, RawData dma_rx, RawData dma_tx, SPI::Configuration config={ SPI::ClockPolarity::LOW, SPI::ClockPhase::EDGE_1, SPI::Prescaler::DIV_8, false, }, uint32_t dma_enable_min_size=3U, bool enable_dma=true)
 
ErrorCode ReadAndWrite (RawData read_data, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
 进行 SPI 读写操作。Performs SPI read and write operations.
 
ErrorCode SetConfig (SPI::Configuration config) override
 设置 SPI 配置参数。Sets SPI configuration parameters.
 
ErrorCode MemRead (uint16_t reg, RawData read_data, OperationRW &op, bool in_isr=false) override
 SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.
 
ErrorCode MemWrite (uint16_t reg, ConstRawData write_data, OperationRW &op, bool in_isr=false) override
 SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.
 
ErrorCode Transfer (size_t size, OperationRW &op, bool in_isr=false) override
 进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).
 
uint32_t GetMaxBusSpeed () const override
 获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.
 
Prescaler GetMaxPrescaler () const override
 获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.
 
RawData GetRxBuffer ()
 
RawData GetTxBuffer ()
 
- Public Member Functions inherited from LibXR::SPI
 SPI (RawData rx_buffer, RawData tx_buffer)
 构造函数。Constructor.
 
virtual ErrorCode Read (RawData read_data, OperationRW &op, bool in_isr=false)
 进行 SPI 读取操作。Performs SPI read operation.
 
virtual ErrorCode Write (ConstRawData write_data, OperationRW &op, bool in_isr=false)
 进行 SPI 写入操作。Performs SPI write operation.
 
uint32_t GetBusSpeed () const
 获取 SPI 设备的当前总线速度。Gets the current bus speed of the SPI device.
 
Prescaler CalcPrescaler (uint32_t target_max_bus_speed, uint32_t target_min_bus_speed, bool increase)
 计算 SPI 分频系数。Calculates the SPI prescaler.
 
RawData GetRxBuffer ()
 获取接收数据的缓冲区。Gets the buffer for storing received data.
 
RawData GetTxBuffer ()
 获取发送数据的缓冲区。Gets the buffer for storing data to be sent.
 
void SwitchBuffer ()
 切换缓冲区。Switches the buffer.
 
void SetActiveLength (size_t len)
 设置缓冲区的有效数据长度。Sets the length of valid data in the buffer.
 
size_t GetActiveLength () const
 获取缓冲区的有效数据长度。Gets the length of valid data in the buffer.
 
ConfigurationGetConfig ()
 获取 SPI 配置参数。Gets the SPI configuration parameters.
 
bool IsDoubleBuffer () const
 检查是否使用双缓冲区。Checks if double buffering is enabled.
 

Private Member Functions

bool Acquire ()
 
void Release ()
 
ErrorCode InitializeHardware ()
 
ErrorCode ConfigurePins ()
 
ErrorCode ResolveClockSource (uint32_t &source_hz)
 
ErrorCode InstallInterrupt ()
 
ErrorCode InitDmaBackend ()
 
void HandleInterrupt ()
 
void FinishAsync (bool in_isr, ErrorCode ec)
 
bool CanUseDma (size_t size) const
 
ErrorCode EnsureReadyAndAcquire ()
 
ErrorCode ReturnAsyncStartResult (ErrorCode ec, bool started)
 
ErrorCode StartAsyncTransfer (const uint8_t *tx, uint8_t *rx, size_t size, bool enable_rx, RawData read_back, bool mem_read, OperationRW &op, bool &started)
 
void ConfigureTransferRegisters (size_t size)
 
ErrorCode ExecuteChunk (const uint8_t *tx, uint8_t *rx, size_t size, bool enable_rx)
 
ErrorCode ExecuteTransfer (const uint8_t *tx, uint8_t *rx, size_t size, bool enable_rx)
 
bool UseLocalDoubleBuffer () const
 
void SwitchBufferLocal ()
 

Static Private Member Functions

static void SpiIsrEntry (void *arg)
 
static ErrorCode FinalizeSyncResult (OperationRW &op, bool in_isr, ErrorCode ec)
 
static ErrorCode CompleteZeroSize (OperationRW &op, bool in_isr)
 

Private Attributes

spi_host_device_t host_
 
spi_dev_t * hw_ = nullptr
 
int sclk_pin_
 
int miso_pin_
 
int mosi_pin_
 
uint32_t source_clock_hz_ = 0
 
std::atomic< bool > busy_ {false}
 
bool initialized_ = false
 
uint32_t dma_enable_min_size_ = 3U
 
bool dma_requested_ = true
 
RawData dma_rx_raw_ = {nullptr, 0}
 
RawData dma_tx_raw_ = {nullptr, 0}
 
size_t dbuf_rx_block_size_ = 0
 
size_t dbuf_tx_block_size_ = 0
 
uint8_t dbuf_active_block_ = 0
 
bool dbuf_enabled_ = false
 
intr_handle_t intr_handle_ = nullptr
 
bool intr_installed_ = false
 
bool dma_enabled_ = false
 
void * dma_ctx_ = nullptr
 
size_t dma_max_transfer_bytes_ = 0
 
bool async_running_ = false
 
size_t async_dma_size_ = 0
 
bool async_dma_rx_enabled_ = false
 
bool mem_read_ = false
 
RawData read_back_ = {nullptr, 0}
 
OperationRW rw_op_
 

Static Private Attributes

static constexpr size_t kMaxPollingTransferBytes = SOC_SPI_MAXIMUM_BUFFER_SIZE
 
static constexpr size_t kMaxDmaTransferBytes = SPI_LL_DMA_MAX_BIT_LEN / 8U
 

Additional Inherited Members

- Public Types inherited from LibXR::SPI
enum class  ClockPolarity : uint8_t { LOW = 0 , HIGH = 1 }
 定义 SPI 时钟极性。Defines the SPI clock polarity. More...
 
enum class  ClockPhase : uint8_t { EDGE_1 = 0 , EDGE_2 = 1 }
 定义 SPI 时钟相位。Defines the SPI clock phase. More...
 
enum class  Prescaler : uint8_t {
  DIV_1 = 0 , DIV_2 = 1 , DIV_4 = 2 , DIV_8 = 3 ,
  DIV_16 = 4 , DIV_32 = 5 , DIV_64 = 6 , DIV_128 = 7 ,
  DIV_256 = 8 , DIV_512 = 9 , DIV_1024 = 10 , DIV_2048 = 11 ,
  DIV_4096 = 12 , DIV_8192 = 13 , DIV_16384 = 14 , DIV_32768 = 15 ,
  DIV_65536 = 16 , UNKNOWN = 0xFF
}
 
using OperationRW = WriteOperation
 定义读写操作类型的别名。Defines an alias for the read/write operation type.
 
- Static Public Member Functions inherited from LibXR::SPI
static constexpr uint32_t PrescalerToDiv (Prescaler prescaler)
 将分频系数转换为除数。Converts a prescaler to a divisor.
 

Detailed Description

Definition at line 19 of file esp_spi.hpp.

Constructor & Destructor Documentation

◆ ESP32SPI()

LibXR::ESP32SPI::ESP32SPI ( spi_host_device_t host,
int sclk_pin,
int miso_pin,
int mosi_pin,
RawData dma_rx,
RawData dma_tx,
SPI::Configuration config = SPI::ClockPolarity::LOWSPI::ClockPhase::EDGE_1SPI::Prescaler::DIV_8, false, },
uint32_t dma_enable_min_size = 3U,
bool enable_dma = true )

Definition at line 113 of file esp_spi.cpp.

116 : SPI(dma_rx, dma_tx),
117 host_(host),
118 sclk_pin_(sclk_pin),
119 miso_pin_(miso_pin),
120 mosi_pin_(mosi_pin),
121 dma_enable_min_size_(dma_enable_min_size),
122 dma_requested_(enable_dma),
123 dma_rx_raw_(dma_rx),
124 dma_tx_raw_(dma_tx),
125 dbuf_rx_block_size_(dma_rx.size_ / 2U),
126 dbuf_tx_block_size_(dma_tx.size_ / 2U)
127{
128 ASSERT(host_ != SPI1_HOST);
129 ASSERT(host_ < SPI_HOST_MAX);
130 ASSERT(static_cast<int>(host_) < SOC_SPI_PERIPH_NUM);
131 ASSERT(dma_rx_raw_.addr_ != nullptr);
132 ASSERT(dma_tx_raw_.addr_ != nullptr);
133 ASSERT(dma_rx_raw_.size_ > 0U);
134 ASSERT(dma_tx_raw_.size_ > 0U);
135
136 if (InitializeHardware() != ErrorCode::OK)
137 {
138 ASSERT(false);
139 return;
140 }
141
142 if (ConfigurePins() != ErrorCode::OK)
143 {
144 ASSERT(false);
145 return;
146 }
147
148 if (InstallInterrupt() != ErrorCode::OK)
149 {
150 ASSERT(false);
151 return;
152 }
153
154 if (dma_requested_)
155 {
156 const ErrorCode dma_ans = InitDmaBackend();
157 ASSERT(dma_ans == ErrorCode::OK);
158 if (dma_ans != ErrorCode::OK)
159 {
160 return;
161 }
162 }
163
164 if (SetConfig(config) != ErrorCode::OK)
165 {
166 ASSERT(false);
167 return;
168 }
169}
ErrorCode SetConfig(SPI::Configuration config) override
设置 SPI 配置参数。Sets SPI configuration parameters.
Definition esp_spi.cpp:452
size_t size_
数据大小(字节)。 The size of the data (in bytes).
void * addr_
数据存储地址。 The storage address of the data.
SPI(RawData rx_buffer, RawData tx_buffer)
构造函数。Constructor.
Definition spi.hpp:110

Member Function Documentation

◆ Acquire()

bool LibXR::ESP32SPI::Acquire ( )
private

Definition at line 171 of file esp_spi.cpp.

172{
173 bool expected = false;
174 return busy_.compare_exchange_strong(expected, true, std::memory_order_acq_rel,
175 std::memory_order_acquire);
176}

◆ CanUseDma()

bool LibXR::ESP32SPI::CanUseDma ( size_t size) const
private

Definition at line 538 of file esp_spi.cpp.

539{
540 return dma_requested_ && dma_enabled_ && (dma_ctx_ != nullptr) &&
541 (size > dma_enable_min_size_) && (size <= dma_max_transfer_bytes_);
542}

◆ CompleteZeroSize()

ErrorCode LibXR::ESP32SPI::CompleteZeroSize ( OperationRW & op,
bool in_isr )
staticprivate

Definition at line 566 of file esp_spi.cpp.

567{
568 return FinalizeSyncResult(op, in_isr, ErrorCode::OK);
569}

◆ ConfigurePins()

ErrorCode LibXR::ESP32SPI::ConfigurePins ( )
private

Definition at line 241 of file esp_spi.cpp.

242{
243 if (!initialized_ || (hw_ == nullptr))
244 {
245 return ErrorCode::STATE_ERR;
246 }
247
248 const auto& signal = spi_periph_signal[host_];
249
250 if (sclk_pin_ >= 0)
251 {
252 if (!GPIO_IS_VALID_OUTPUT_GPIO(sclk_pin_))
253 {
254 return ErrorCode::ARG_ERR;
255 }
256 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(sclk_pin_));
257 esp_rom_gpio_connect_out_signal(sclk_pin_, signal.spiclk_out, false, false);
258 gpio_input_enable(static_cast<gpio_num_t>(sclk_pin_));
259 esp_rom_gpio_connect_in_signal(sclk_pin_, signal.spiclk_in, false);
260 }
261
262 if (mosi_pin_ >= 0)
263 {
264 if (!GPIO_IS_VALID_OUTPUT_GPIO(mosi_pin_))
265 {
266 return ErrorCode::ARG_ERR;
267 }
268 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(mosi_pin_));
269 esp_rom_gpio_connect_out_signal(mosi_pin_, signal.spid_out, false, false);
270 gpio_input_enable(static_cast<gpio_num_t>(mosi_pin_));
271 esp_rom_gpio_connect_in_signal(mosi_pin_, signal.spid_in, false);
272 }
273
274 if (miso_pin_ >= 0)
275 {
276 if (!GPIO_IS_VALID_GPIO(miso_pin_))
277 {
278 return ErrorCode::ARG_ERR;
279 }
280 gpio_input_enable(static_cast<gpio_num_t>(miso_pin_));
281 esp_rom_gpio_connect_in_signal(miso_pin_, signal.spiq_in, false);
282 }
283
284 return ErrorCode::OK;
285}

◆ ConfigureTransferRegisters()

void LibXR::ESP32SPI::ConfigureTransferRegisters ( size_t size)
private

Definition at line 580 of file esp_spi.cpp.

581{
582 static constexpr spi_line_mode_t kLineMode = {
583 .cmd_lines = 1,
584 .addr_lines = 1,
585 .data_lines = 1,
586 };
587 const size_t bitlen = size * 8U;
588
589 spi_ll_master_set_line_mode(hw_, kLineMode);
590 spi_ll_set_mosi_bitlen(hw_, bitlen);
591 spi_ll_set_miso_bitlen(hw_, bitlen);
592 spi_ll_set_command_bitlen(hw_, 0);
593 spi_ll_set_addr_bitlen(hw_, 0);
594 spi_ll_set_command(hw_, 0, 0, false);
595 spi_ll_set_address(hw_, 0, 0, false);
596 hw_->user.usr_command = 0;
597 hw_->user.usr_addr = 0;
598}

◆ EnsureReadyAndAcquire()

ErrorCode LibXR::ESP32SPI::EnsureReadyAndAcquire ( )
private

Definition at line 544 of file esp_spi.cpp.

545{
546 if (!initialized_)
547 {
548 return ErrorCode::INIT_ERR;
549 }
550 if (!Acquire())
551 {
552 return ErrorCode::BUSY;
553 }
554 return ErrorCode::OK;
555}

◆ ExecuteChunk()

ErrorCode LibXR::ESP32SPI::ExecuteChunk ( const uint8_t * tx,
uint8_t * rx,
size_t size,
bool enable_rx )
private

Definition at line 692 of file esp_spi.cpp.

694{
695 if ((size == 0U) || (size > kMaxPollingTransferBytes))
696 {
697 return ErrorCode::SIZE_ERR;
698 }
699
700 static constexpr std::array<uint8_t, kMaxPollingTransferBytes> kZero = {};
701 const uint8_t* tx_data = (tx != nullptr) ? tx : kZero.data();
702
703 ConfigureTransferRegisters(size);
704 spi_ll_enable_mosi(hw_, 1);
705 spi_ll_enable_miso(hw_, enable_rx ? 1 : 0);
706 spi_ll_write_buffer(hw_, tx_data, size * 8U);
707 spi_ll_clear_int_stat(hw_);
708 spi_ll_apply_config(hw_);
709 spi_ll_user_start(hw_);
710
711 const uint64_t timeout_us = CalcPollingTimeoutUs(size, GetBusSpeed());
712 const uint64_t start_us = GetNowUs();
713 while (!spi_ll_usr_is_done(hw_))
714 {
715 if ((GetNowUs() - start_us) > timeout_us)
716 {
717 return ErrorCode::TIMEOUT;
718 }
719 }
720
721 if (enable_rx && (rx != nullptr))
722 {
723 spi_ll_read_buffer(hw_, rx, size * 8U);
724 }
725 spi_ll_clear_int_stat(hw_);
726 return ErrorCode::OK;
727}
uint32_t GetBusSpeed() const
获取 SPI 设备的当前总线速度。Gets the current bus speed of the SPI device.
Definition spi.hpp:178

◆ ExecuteTransfer()

ErrorCode LibXR::ESP32SPI::ExecuteTransfer ( const uint8_t * tx,
uint8_t * rx,
size_t size,
bool enable_rx )
private

Definition at line 729 of file esp_spi.cpp.

731{
732 size_t offset = 0U;
733 while (offset < size)
734 {
735 const size_t remain = size - offset;
736 const size_t chunk = std::min(remain, kMaxPollingTransferBytes);
737 const uint8_t* tx_chunk = (tx != nullptr) ? (tx + offset) : nullptr;
738 uint8_t* rx_chunk = (enable_rx && (rx != nullptr)) ? (rx + offset) : nullptr;
739
740 const ErrorCode ec = ExecuteChunk(tx_chunk, rx_chunk, chunk, enable_rx);
741 if (ec != ErrorCode::OK)
742 {
743 return ec;
744 }
745 offset += chunk;
746 }
747
748 return ErrorCode::OK;
749}

◆ FinalizeSyncResult()

ErrorCode LibXR::ESP32SPI::FinalizeSyncResult ( OperationRW & op,
bool in_isr,
ErrorCode ec )
staticprivate

Definition at line 557 of file esp_spi.cpp.

558{
559 if (op.type != OperationRW::OperationType::BLOCK)
560 {
561 op.UpdateStatus(in_isr, ec);
562 }
563 return ec;
564}

◆ FinishAsync()

void IRAM_ATTR LibXR::ESP32SPI::FinishAsync ( bool in_isr,
ErrorCode ec )
private

Definition at line 385 of file esp_spi.cpp.

386{
387 if (!async_running_)
388 {
389 return;
390 }
391
392#if CONFIG_IDF_TARGET_ESP32
393 // Keep ESP32 SPI DMA workaround state in sync with transfer lifecycle.
394 if (dma_enabled_)
395 {
396 spi_dma_ctx_t* ctx = ToDmaCtx(dma_ctx_);
397 if (ctx != nullptr)
398 {
399 spicommon_dmaworkaround_idle(ctx->tx_dma_chan.chan_id);
400 }
401 }
402#endif
403
404 spi_ll_disable_int(hw_);
405 spi_ll_clear_int_stat(hw_);
406
407 RawData rx = {nullptr, 0U};
408 if ((ec == ErrorCode::OK) && async_dma_rx_enabled_)
409 {
410 rx = GetRxBuffer();
411#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
412 if (!CacheSyncDmaBuffer(rx.addr_, async_dma_size_, false))
413 {
414 ec = ErrorCode::FAILED;
415 }
416#endif
417 }
418
419 if ((ec == ErrorCode::OK) && (read_back_.size_ > 0U))
420 {
421 if (rx.addr_ == nullptr)
422 {
423 rx = GetRxBuffer();
424 }
425 uint8_t* src = static_cast<uint8_t*>(rx.addr_);
426 if (mem_read_)
427 {
428 ASSERT(rx.size_ >= (read_back_.size_ + 1U));
429 src += 1;
430 }
431 else
432 {
433 ASSERT(rx.size_ >= read_back_.size_);
434 }
435 Memory::FastCopy(read_back_.addr_, src, read_back_.size_);
436 }
437
438 if (ec == ErrorCode::OK)
439 {
440 SwitchBufferLocal();
441 }
442
443 async_running_ = false;
444 async_dma_size_ = 0U;
445 async_dma_rx_enabled_ = false;
446 mem_read_ = false;
447 read_back_ = {nullptr, 0};
448 Release();
449 rw_op_.UpdateStatus(in_isr, ec);
450}
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
Definition libxr_mem.cpp:3
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
Definition libxr_rw.hpp:177

◆ GetMaxBusSpeed()

uint32_t LibXR::ESP32SPI::GetMaxBusSpeed ( ) const
overridevirtual

获取 SPI 设备的最大时钟速度。Gets the maximum clock speed of the SPI device.

Returns
SPI 设备的最大时钟速度(单位:Hz)。The maximum clock speed of the SPI device (in Hz).

Implements LibXR::SPI.

Definition at line 927 of file esp_spi.cpp.

927{ return source_clock_hz_; }

◆ GetMaxPrescaler()

SPI::Prescaler LibXR::ESP32SPI::GetMaxPrescaler ( ) const
overridevirtual

获取 SPI 设备的最大分频系数。Gets the maximum prescaler of the SPI device.

Returns
SPI 设备的最大分频系数。The maximum prescaler of the SPI device.

Implements LibXR::SPI.

Definition at line 929 of file esp_spi.cpp.

929{ return Prescaler::DIV_65536; }
@ DIV_65536
分频系数为 65536。Division factor is 65536.

◆ GetRxBuffer()

RawData LibXR::ESP32SPI::GetRxBuffer ( )

Definition at line 508 of file esp_spi.cpp.

509{
510 if (UseLocalDoubleBuffer())
511 {
512 auto* base = static_cast<uint8_t*>(dma_rx_raw_.addr_);
513 return {base + static_cast<size_t>(dbuf_active_block_) * dbuf_rx_block_size_,
514 dbuf_rx_block_size_};
515 }
516 return dma_rx_raw_;
517}

◆ GetTxBuffer()

RawData LibXR::ESP32SPI::GetTxBuffer ( )

Definition at line 519 of file esp_spi.cpp.

520{
521 if (UseLocalDoubleBuffer())
522 {
523 auto* base = static_cast<uint8_t*>(dma_tx_raw_.addr_);
524 return {base + static_cast<size_t>(dbuf_active_block_) * dbuf_tx_block_size_,
525 dbuf_tx_block_size_};
526 }
527 return dma_tx_raw_;
528}

◆ HandleInterrupt()

void IRAM_ATTR LibXR::ESP32SPI::HandleInterrupt ( )
private

Definition at line 364 of file esp_spi.cpp.

365{
366 if ((hw_ == nullptr) || !initialized_)
367 {
368 return;
369 }
370
371 if (!async_running_)
372 {
373 spi_ll_clear_int_stat(hw_);
374 return;
375 }
376
377 if (!spi_ll_usr_is_done(hw_))
378 {
379 return;
380 }
381
382 FinishAsync(true, ErrorCode::OK);
383}

◆ InitDmaBackend()

ErrorCode LibXR::ESP32SPI::InitDmaBackend ( )
private

Definition at line 319 of file esp_spi.cpp.

320{
321 if (dma_enabled_)
322 {
323 return ErrorCode::OK;
324 }
325
326 spi_dma_ctx_t* ctx = nullptr;
327 if (spicommon_dma_chan_alloc(host_, SPI_DMA_CH_AUTO, &ctx) != ESP_OK)
328 {
329 return ErrorCode::INIT_ERR;
330 }
331
332 const size_t cfg_max_size = std::max(dma_rx_raw_.size_, dma_tx_raw_.size_);
333 int actual_max_size = 0;
334 if (spicommon_dma_desc_alloc(ctx, static_cast<int>(cfg_max_size), &actual_max_size) !=
335 ESP_OK)
336 {
337 (void)spicommon_dma_chan_free(ctx);
338 return ErrorCode::INIT_ERR;
339 }
340
341 dma_ctx_ = ctx;
342 dma_enabled_ = true;
343 dma_max_transfer_bytes_ =
344 std::min<size_t>({static_cast<size_t>(actual_max_size), dma_rx_raw_.size_,
345 dma_tx_raw_.size_, kMaxDmaTransferBytes});
346
347 if (dma_max_transfer_bytes_ == 0U)
348 {
349 return ErrorCode::INIT_ERR;
350 }
351
352 return ErrorCode::OK;
353}

◆ InitializeHardware()

ErrorCode LibXR::ESP32SPI::InitializeHardware ( )
private

Definition at line 180 of file esp_spi.cpp.

181{
182 if (initialized_)
183 {
184 return ErrorCode::OK;
185 }
186
187 if ((host_ <= SPI1_HOST) || (host_ >= SPI_HOST_MAX) ||
188 (static_cast<int>(host_) >= SOC_SPI_PERIPH_NUM))
189 {
190 return ErrorCode::ARG_ERR;
191 }
192
193 const auto& signal = spi_periph_signal[host_];
194 hw_ = signal.hw;
195 if (hw_ == nullptr)
196 {
197 return ErrorCode::NOT_SUPPORT;
198 }
199
200 PERIPH_RCC_ATOMIC()
201 {
202 (void)__DECLARE_RCC_ATOMIC_ENV;
203 spi_ll_enable_bus_clock(host_, true);
204 spi_ll_reset_register(host_);
205 }
206 spi_ll_enable_clock(host_, true);
207 spi_ll_master_init(hw_);
208
209 const spi_line_mode_t line_mode = {
210 .cmd_lines = 1,
211 .addr_lines = 1,
212 .data_lines = 1,
213 };
214 spi_ll_master_set_line_mode(hw_, line_mode);
215 spi_ll_set_half_duplex(hw_, false);
216 spi_ll_set_tx_lsbfirst(hw_, false);
217 spi_ll_set_rx_lsbfirst(hw_, false);
218 spi_ll_set_mosi_delay(hw_, 0, 0);
219 spi_ll_enable_mosi(hw_, 1);
220 spi_ll_enable_miso(hw_, 1);
221 spi_ll_set_dummy(hw_, 0);
222 spi_ll_set_command_bitlen(hw_, 0);
223 spi_ll_set_addr_bitlen(hw_, 0);
224 spi_ll_set_command(hw_, 0, 0, false);
225 spi_ll_set_address(hw_, 0, 0, false);
226 hw_->user.usr_command = 0;
227 hw_->user.usr_addr = 0;
228
229 spi_ll_set_clk_source(hw_, SPI_CLK_SRC_DEFAULT);
230 if (ResolveClockSource(source_clock_hz_) != ErrorCode::OK)
231 {
232 return ErrorCode::INIT_ERR;
233 }
234
235 spi_ll_disable_int(hw_);
236 spi_ll_clear_int_stat(hw_);
237 initialized_ = true;
238 return ErrorCode::OK;
239}

◆ InstallInterrupt()

ErrorCode LibXR::ESP32SPI::InstallInterrupt ( )
private

Definition at line 300 of file esp_spi.cpp.

301{
302 if (intr_installed_)
303 {
304 return ErrorCode::OK;
305 }
306
307 const int irq_source = static_cast<int>(spi_periph_signal[host_].irq);
308 if (esp_intr_alloc(irq_source, ESP_INTR_FLAG_IRAM, &ESP32SPI::SpiIsrEntry, this,
309 &intr_handle_) != ESP_OK)
310 {
311 intr_handle_ = nullptr;
312 return ErrorCode::INIT_ERR;
313 }
314
315 intr_installed_ = true;
316 return ErrorCode::OK;
317}

◆ MemRead()

ErrorCode LibXR::ESP32SPI::MemRead ( uint16_t reg,
RawData read_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

SPI 设备的寄存器读取数据。 Reads data from a specific register of the SPI device.

Parameters
reg寄存器地址。Register address.
read_data读取的数据缓冲区。Buffer to store read data.
op操作类型(同步/异步)。Operation mode (sync/async).
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 804 of file esp_spi.cpp.

805{
806 if (read_data.size_ == 0U)
807 {
808 return CompleteZeroSize(op, in_isr);
809 }
810
811 const ErrorCode lock_ec = EnsureReadyAndAcquire();
812 if (lock_ec != ErrorCode::OK)
813 {
814 return lock_ec;
815 }
816
817 RawData rx = GetRxBuffer();
818 RawData tx = GetTxBuffer();
819 const size_t total = read_data.size_ + 1U;
820
821 ASSERT(rx.size_ >= total);
822 ASSERT(tx.size_ >= total);
823
824 auto* tx_ptr = static_cast<uint8_t*>(tx.addr_);
825 tx_ptr[0] = static_cast<uint8_t>(reg | 0x80U);
826 Memory::FastSet(tx_ptr + 1, 0x00, read_data.size_);
827
828 if (CanUseDma(total))
829 {
830 bool started = false;
831 const ErrorCode ec = StartAsyncTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_),
832 total, true, read_data, true, op, started);
833 return ReturnAsyncStartResult(ec, started);
834 }
835
836 const ErrorCode ec =
837 ExecuteTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_), total, true);
838 if (ec == ErrorCode::OK)
839 {
840 auto* rx_ptr = static_cast<uint8_t*>(rx.addr_);
841 Memory::FastCopy(read_data.addr_, rx_ptr + 1, read_data.size_);
842 SwitchBufferLocal();
843 }
844
845 Release();
846 return FinalizeSyncResult(op, in_isr, ec);
847}
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill

◆ MemWrite()

ErrorCode LibXR::ESP32SPI::MemWrite ( uint16_t reg,
ConstRawData write_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

SPI 设备的寄存器写入数据。 Writes data to a specific register of the SPI device.

Parameters
reg寄存器地址。Register address.
write_data写入的数据缓冲区。Buffer containing data to write.
op操作类型(同步/异步)。Operation mode (sync/async).
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating success or failure.

Implements LibXR::SPI.

Definition at line 849 of file esp_spi.cpp.

851{
852 if (write_data.size_ == 0U)
853 {
854 return CompleteZeroSize(op, in_isr);
855 }
856
857 const ErrorCode lock_ec = EnsureReadyAndAcquire();
858 if (lock_ec != ErrorCode::OK)
859 {
860 return lock_ec;
861 }
862
863 RawData tx = GetTxBuffer();
864 const size_t total = write_data.size_ + 1U;
865 ASSERT(tx.size_ >= total);
866
867 auto* tx_ptr = static_cast<uint8_t*>(tx.addr_);
868 tx_ptr[0] = static_cast<uint8_t>(reg & 0x7FU);
869 Memory::FastCopy(tx_ptr + 1, write_data.addr_, write_data.size_);
870
871 if (CanUseDma(total))
872 {
873 bool started = false;
874 const ErrorCode ec = StartAsyncTransfer(tx_ptr, nullptr, total, false, {nullptr, 0},
875 false, op, started);
876 return ReturnAsyncStartResult(ec, started);
877 }
878
879 const ErrorCode ec = ExecuteTransfer(tx_ptr, nullptr, total, false);
880 if (ec == ErrorCode::OK)
881 {
882 SwitchBufferLocal();
883 }
884
885 Release();
886 return FinalizeSyncResult(op, in_isr, ec);
887}

◆ ReadAndWrite()

ErrorCode LibXR::ESP32SPI::ReadAndWrite ( RawData read_data,
ConstRawData write_data,
OperationRW & op,
bool in_isr = false )
overridevirtual

进行 SPI 读写操作。Performs SPI read and write operations.

Parameters
read_data存储读取数据的缓冲区。Buffer to store the read data.
write_data需要写入的数据缓冲区。Buffer containing the data to be written.
op读写操作类型。Type of read/write operation.
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 751 of file esp_spi.cpp.

753{
754 const size_t need = std::max(read_data.size_, write_data.size_);
755 if (need == 0U)
756 {
757 return CompleteZeroSize(op, in_isr);
758 }
759
760 const ErrorCode lock_ec = EnsureReadyAndAcquire();
761 if (lock_ec != ErrorCode::OK)
762 {
763 return lock_ec;
764 }
765
766 RawData rx = GetRxBuffer();
767 RawData tx = GetTxBuffer();
768 ASSERT(rx.size_ >= need);
769 ASSERT(tx.size_ >= need);
770
771 auto* tx_ptr = static_cast<uint8_t*>(tx.addr_);
772 if (write_data.size_ > 0U)
773 {
774 Memory::FastCopy(tx_ptr, write_data.addr_, write_data.size_);
775 }
776 if (need > write_data.size_)
777 {
778 Memory::FastSet(tx_ptr + write_data.size_, 0x00, need - write_data.size_);
779 }
780
781 if (CanUseDma(need))
782 {
783 bool started = false;
784 const ErrorCode ec = StartAsyncTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_), need,
785 true, read_data, false, op, started);
786 return ReturnAsyncStartResult(ec, started);
787 }
788
789 const ErrorCode ec =
790 ExecuteTransfer(tx_ptr, static_cast<uint8_t*>(rx.addr_), need, true);
791 if (ec == ErrorCode::OK)
792 {
793 if (read_data.size_ > 0U)
794 {
795 Memory::FastCopy(read_data.addr_, rx.addr_, read_data.size_);
796 }
797 SwitchBufferLocal();
798 }
799
800 Release();
801 return FinalizeSyncResult(op, in_isr, ec);
802}

◆ Release()

void LibXR::ESP32SPI::Release ( )
private

Definition at line 178 of file esp_spi.cpp.

178{ busy_.store(false, std::memory_order_release); }

◆ ResolveClockSource()

ErrorCode LibXR::ESP32SPI::ResolveClockSource ( uint32_t & source_hz)
private

Definition at line 287 of file esp_spi.cpp.

288{
289 source_hz = 0;
290 const esp_err_t err =
291 esp_clk_tree_src_get_freq_hz(static_cast<soc_module_clk_t>(SPI_CLK_SRC_DEFAULT),
292 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &source_hz);
293 if ((err != ESP_OK) || (source_hz == 0))
294 {
295 return ErrorCode::INIT_ERR;
296 }
297 return ErrorCode::OK;
298}

◆ ReturnAsyncStartResult()

ErrorCode LibXR::ESP32SPI::ReturnAsyncStartResult ( ErrorCode ec,
bool started )
private

Definition at line 571 of file esp_spi.cpp.

572{
573 if (!started)
574 {
575 Release();
576 }
577 return ec;
578}

◆ SetConfig()

ErrorCode LibXR::ESP32SPI::SetConfig ( SPI::Configuration config)
overridevirtual

设置 SPI 配置参数。Sets SPI configuration parameters.

Parameters
config需要应用的 SPI 配置。The SPI configuration to apply.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 452 of file esp_spi.cpp.

453{
454 if (!initialized_ || (hw_ == nullptr))
455 {
456 return ErrorCode::STATE_ERR;
457 }
458 if (busy_.load(std::memory_order_acquire))
459 {
460 return ErrorCode::BUSY;
461 }
462
463 if (config.prescaler == Prescaler::UNKNOWN)
464 {
465 return ErrorCode::ARG_ERR;
466 }
467 if (config.double_buffer &&
468 ((dbuf_rx_block_size_ == 0U) || (dbuf_tx_block_size_ == 0U)))
469 {
470 return ErrorCode::ARG_ERR;
471 }
472
473 const uint32_t div = PrescalerToDiv(config.prescaler);
474 if ((div == 0) || (source_clock_hz_ == 0))
475 {
476 return ErrorCode::ARG_ERR;
477 }
478
479 const uint32_t target_hz = source_clock_hz_ / div;
480 if (target_hz == 0)
481 {
482 return ErrorCode::ARG_ERR;
483 }
484
485 const uint8_t mode = ResolveSpiMode(config.clock_polarity, config.clock_phase);
486 spi_ll_master_set_mode(hw_, mode);
487
488 const int applied_hz = spi_ll_master_set_clock(hw_, static_cast<int>(source_clock_hz_),
489 static_cast<int>(target_hz), 128);
490 if (applied_hz <= 0)
491 {
492 return ErrorCode::INIT_ERR;
493 }
494
495 spi_ll_apply_config(hw_);
496 GetConfig() = config;
497 dbuf_enabled_ = config.double_buffer;
498 dbuf_active_block_ = 0U;
499
500 return ErrorCode::OK;
501}
@ UNKNOWN
未知分频系数。Unknown prescaler.
static constexpr uint32_t PrescalerToDiv(Prescaler prescaler)
将分频系数转换为除数。Converts a prescaler to a divisor.
Definition spi.hpp:70
Configuration & GetConfig()
获取 SPI 配置参数。Gets the SPI configuration parameters.
Definition spi.hpp:396

◆ SpiIsrEntry()

void IRAM_ATTR LibXR::ESP32SPI::SpiIsrEntry ( void * arg)
staticprivate

Definition at line 355 of file esp_spi.cpp.

356{
357 auto* spi = static_cast<ESP32SPI*>(arg);
358 if (spi != nullptr)
359 {
360 spi->HandleInterrupt();
361 }
362}

◆ StartAsyncTransfer()

ErrorCode LibXR::ESP32SPI::StartAsyncTransfer ( const uint8_t * tx,
uint8_t * rx,
size_t size,
bool enable_rx,
RawData read_back,
bool mem_read,
OperationRW & op,
bool & started )
private

Definition at line 600 of file esp_spi.cpp.

603{
604 started = false;
605
606 if (!CanUseDma(size))
607 {
608 return ErrorCode::NOT_SUPPORT;
609 }
610 if ((tx == nullptr) || (size == 0U))
611 {
612 return ErrorCode::ARG_ERR;
613 }
614
615 spi_dma_ctx_t* ctx = ToDmaCtx(dma_ctx_);
616 if (ctx == nullptr)
617 {
618 return ErrorCode::INIT_ERR;
619 }
620
621 const bool rx_enabled = enable_rx && (rx != nullptr);
622 ConfigureTransferRegisters(size);
623
624#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
625 if (!CacheSyncDmaBuffer(tx, size, true))
626 {
627 return ErrorCode::FAILED;
628 }
629#endif
630
631 if (enable_rx && (rx != nullptr))
632 {
633 spicommon_dma_desc_setup_link(ctx->dmadesc_rx, rx, static_cast<int>(size), true);
634 if (DmaReset(ctx->rx_dma_chan) != ESP_OK)
635 {
636 return ErrorCode::INIT_ERR;
637 }
638 spi_hal_hw_prepare_rx(hw_);
639 if (DmaStart(ctx->rx_dma_chan, ctx->dmadesc_rx) != ESP_OK)
640 {
641 return ErrorCode::INIT_ERR;
642 }
643 }
644#if CONFIG_IDF_TARGET_ESP32
645 else
646 {
647 // Keep ESP32 full-duplex TX-only DMA behavior aligned with IDF workaround.
648 spi_ll_dma_rx_enable(hw_, true);
649 (void)DmaStart(ctx->rx_dma_chan, nullptr);
650 }
651#endif
652
653 spicommon_dma_desc_setup_link(ctx->dmadesc_tx, tx, static_cast<int>(size), false);
654 if (DmaReset(ctx->tx_dma_chan) != ESP_OK)
655 {
656 return ErrorCode::INIT_ERR;
657 }
658 spi_hal_hw_prepare_tx(hw_);
659 if (DmaStart(ctx->tx_dma_chan, ctx->dmadesc_tx) != ESP_OK)
660 {
661 return ErrorCode::INIT_ERR;
662 }
663
664#if CONFIG_IDF_TARGET_ESP32
665 spicommon_dmaworkaround_transfer_active(ctx->tx_dma_chan.chan_id);
666#endif
667
668 rw_op_ = op;
669 read_back_ = read_back;
670 mem_read_ = mem_read;
671 async_dma_size_ = size;
672 async_dma_rx_enabled_ = rx_enabled;
673 started = true;
674
675 // On ESP32 classic, enable data lines only after DMA descriptors/channels are ready.
676 spi_ll_enable_mosi(hw_, 1);
677 spi_ll_enable_miso(hw_, rx_enabled ? 1 : 0);
678 spi_ll_clear_int_stat(hw_);
679 spi_ll_enable_int(hw_);
680 async_running_ = true;
681 spi_ll_apply_config(hw_);
682 spi_ll_user_start(hw_);
683
684 op.MarkAsRunning();
685 if (op.type == OperationRW::OperationType::BLOCK)
686 {
687 return op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
688 }
689 return ErrorCode::OK;
690}

◆ SwitchBufferLocal()

void LibXR::ESP32SPI::SwitchBufferLocal ( )
private

Definition at line 530 of file esp_spi.cpp.

531{
532 if (UseLocalDoubleBuffer())
533 {
534 dbuf_active_block_ ^= 1U;
535 }
536}

◆ Transfer()

ErrorCode LibXR::ESP32SPI::Transfer ( size_t size,
OperationRW & op,
bool in_isr = false )
overridevirtual

进行一次SPI传输(使用当前缓冲区数据,零拷贝,支持双缓冲)。 Performs a SPI transfer (zero-copy, supports double buffering).

Parameters
size需要传输的数据大小。The size of the data to be transferred.
op读写操作类型。Type of read/write operation.
in_isr是否在中断中进行操作。Whether the operation is performed in an ISR.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::SPI.

Definition at line 889 of file esp_spi.cpp.

890{
891 if (size == 0U)
892 {
893 return CompleteZeroSize(op, in_isr);
894 }
895
896 const ErrorCode lock_ec = EnsureReadyAndAcquire();
897 if (lock_ec != ErrorCode::OK)
898 {
899 return lock_ec;
900 }
901
902 RawData rx = GetRxBuffer();
903 RawData tx = GetTxBuffer();
904 ASSERT(rx.size_ >= size);
905 ASSERT(tx.size_ >= size);
906
907 if (CanUseDma(size))
908 {
909 bool started = false;
910 const ErrorCode ec = StartAsyncTransfer(static_cast<const uint8_t*>(tx.addr_),
911 static_cast<uint8_t*>(rx.addr_), size, true,
912 {nullptr, 0}, false, op, started);
913 return ReturnAsyncStartResult(ec, started);
914 }
915
916 const ErrorCode ec = ExecuteTransfer(static_cast<const uint8_t*>(tx.addr_),
917 static_cast<uint8_t*>(rx.addr_), size, true);
918 if (ec == ErrorCode::OK)
919 {
920 SwitchBufferLocal();
921 }
922
923 Release();
924 return FinalizeSyncResult(op, in_isr, ec);
925}

◆ UseLocalDoubleBuffer()

bool LibXR::ESP32SPI::UseLocalDoubleBuffer ( ) const
private

Definition at line 503 of file esp_spi.cpp.

504{
505 return dbuf_enabled_ && (dbuf_rx_block_size_ > 0U) && (dbuf_tx_block_size_ > 0U);
506}

Field Documentation

◆ async_dma_rx_enabled_

bool LibXR::ESP32SPI::async_dma_rx_enabled_ = false
private

Definition at line 129 of file esp_spi.hpp.

◆ async_dma_size_

size_t LibXR::ESP32SPI::async_dma_size_ = 0
private

Definition at line 128 of file esp_spi.hpp.

◆ async_running_

bool LibXR::ESP32SPI::async_running_ = false
private

Definition at line 127 of file esp_spi.hpp.

◆ busy_

std::atomic<bool> LibXR::ESP32SPI::busy_ {false}
private

Definition at line 112 of file esp_spi.hpp.

112{false};

◆ dbuf_active_block_

uint8_t LibXR::ESP32SPI::dbuf_active_block_ = 0
private

Definition at line 120 of file esp_spi.hpp.

◆ dbuf_enabled_

bool LibXR::ESP32SPI::dbuf_enabled_ = false
private

Definition at line 121 of file esp_spi.hpp.

◆ dbuf_rx_block_size_

size_t LibXR::ESP32SPI::dbuf_rx_block_size_ = 0
private

Definition at line 118 of file esp_spi.hpp.

◆ dbuf_tx_block_size_

size_t LibXR::ESP32SPI::dbuf_tx_block_size_ = 0
private

Definition at line 119 of file esp_spi.hpp.

◆ dma_ctx_

void* LibXR::ESP32SPI::dma_ctx_ = nullptr
private

Definition at line 125 of file esp_spi.hpp.

◆ dma_enable_min_size_

uint32_t LibXR::ESP32SPI::dma_enable_min_size_ = 3U
private

Definition at line 114 of file esp_spi.hpp.

◆ dma_enabled_

bool LibXR::ESP32SPI::dma_enabled_ = false
private

Definition at line 124 of file esp_spi.hpp.

◆ dma_max_transfer_bytes_

size_t LibXR::ESP32SPI::dma_max_transfer_bytes_ = 0
private

Definition at line 126 of file esp_spi.hpp.

◆ dma_requested_

bool LibXR::ESP32SPI::dma_requested_ = true
private

Definition at line 115 of file esp_spi.hpp.

◆ dma_rx_raw_

RawData LibXR::ESP32SPI::dma_rx_raw_ = {nullptr, 0}
private

Definition at line 116 of file esp_spi.hpp.

116{nullptr, 0};

◆ dma_tx_raw_

RawData LibXR::ESP32SPI::dma_tx_raw_ = {nullptr, 0}
private

Definition at line 117 of file esp_spi.hpp.

117{nullptr, 0};

◆ host_

spi_host_device_t LibXR::ESP32SPI::host_
private

Definition at line 106 of file esp_spi.hpp.

◆ hw_

spi_dev_t* LibXR::ESP32SPI::hw_ = nullptr
private

Definition at line 107 of file esp_spi.hpp.

◆ initialized_

bool LibXR::ESP32SPI::initialized_ = false
private

Definition at line 113 of file esp_spi.hpp.

◆ intr_handle_

intr_handle_t LibXR::ESP32SPI::intr_handle_ = nullptr
private

Definition at line 122 of file esp_spi.hpp.

◆ intr_installed_

bool LibXR::ESP32SPI::intr_installed_ = false
private

Definition at line 123 of file esp_spi.hpp.

◆ kMaxDmaTransferBytes

size_t LibXR::ESP32SPI::kMaxDmaTransferBytes = SPI_LL_DMA_MAX_BIT_LEN / 8U
staticconstexprprivate

Definition at line 57 of file esp_spi.hpp.

◆ kMaxPollingTransferBytes

size_t LibXR::ESP32SPI::kMaxPollingTransferBytes = SOC_SPI_MAXIMUM_BUFFER_SIZE
staticconstexprprivate

Definition at line 56 of file esp_spi.hpp.

◆ mem_read_

bool LibXR::ESP32SPI::mem_read_ = false
private

Definition at line 130 of file esp_spi.hpp.

◆ miso_pin_

int LibXR::ESP32SPI::miso_pin_
private

Definition at line 109 of file esp_spi.hpp.

◆ mosi_pin_

int LibXR::ESP32SPI::mosi_pin_
private

Definition at line 110 of file esp_spi.hpp.

◆ read_back_

RawData LibXR::ESP32SPI::read_back_ = {nullptr, 0}
private

Definition at line 131 of file esp_spi.hpp.

131{nullptr, 0};

◆ rw_op_

OperationRW LibXR::ESP32SPI::rw_op_
private

Definition at line 132 of file esp_spi.hpp.

◆ sclk_pin_

int LibXR::ESP32SPI::sclk_pin_
private

Definition at line 108 of file esp_spi.hpp.

◆ source_clock_hz_

uint32_t LibXR::ESP32SPI::source_clock_hz_ = 0
private

Definition at line 111 of file esp_spi.hpp.


The documentation for this class was generated from the following files: