8#include "driver/gpio.h"
9#include "driver/spi_common.h"
11#include "esp_clk_tree.h"
13#include "esp_memory_utils.h"
14#include "esp_private/periph_ctrl.h"
15#include "esp_private/spi_common_internal.h"
18#include "esp_private/gdma.h"
20#include "esp_rom_gpio.h"
21#include "hal/spi_hal.h"
22#include "libxr_def.hpp"
23#include "soc/spi_periph.h"
24#include "timebase.hpp"
40spi_dma_ctx_t* ToDmaCtx(
void* ctx) {
return reinterpret_cast<spi_dma_ctx_t*
>(ctx); }
44uint64_t CalcPollingTimeoutUs(
size_t size, uint32_t bus_hz)
46 const uint32_t safe_hz = (bus_hz == 0U) ? 1U : bus_hz;
47 const uint64_t bits =
static_cast<uint64_t
>(size) * 8ULL;
48 const uint64_t wire_time_us = (bits * 1000000ULL + safe_hz - 1ULL) / safe_hz;
51 return std::max<uint64_t>(100ULL, wire_time_us * 8ULL + 50ULL);
55esp_err_t DmaReset(gdma_channel_handle_t chan) {
return gdma_reset(chan); }
57esp_err_t DmaStart(gdma_channel_handle_t chan,
const void* desc)
59 return gdma_start(chan,
reinterpret_cast<intptr_t
>(desc));
62esp_err_t DmaReset(spi_dma_chan_handle_t chan)
68esp_err_t DmaStart(spi_dma_chan_handle_t chan,
const void* desc)
70 spi_dma_start(chan,
const_cast<void*
>(desc));
75#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
76extern "C" esp_err_t esp_cache_msync(
void* addr,
size_t size,
int flags);
78constexpr int CACHE_SYNC_FLAG_UNALIGNED = (1 << 1);
79constexpr int CACHE_SYNC_FLAG_DIR_C2M = (1 << 2);
80constexpr int CACHE_SYNC_FLAG_DIR_M2C = (1 << 3);
82bool CacheSyncDmaBuffer(
const void* addr,
size_t size,
bool cache_to_mem)
84 if ((addr ==
nullptr) || (size == 0U))
89#if SOC_PSRAM_DMA_CAPABLE && !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
90 if (!esp_ptr_external_ram(addr))
96 int flags = cache_to_mem ? CACHE_SYNC_FLAG_DIR_C2M : CACHE_SYNC_FLAG_DIR_M2C;
97 flags |= CACHE_SYNC_FLAG_UNALIGNED;
99 const esp_err_t ret = esp_cache_msync(
const_cast<void*
>(addr), size, flags);
102 return (ret == ESP_OK) || (ret == ESP_ERR_INVALID_ARG);
108ESP32SPI::ESP32SPI(spi_host_device_t host,
int sclk_pin,
int miso_pin,
int mosi_pin,
109 RawData dma_rx, RawData dma_tx, SPI::Configuration config,
110 uint32_t dma_enable_min_size,
bool enable_dma)
111 : SPI(dma_rx, dma_tx),
116 dma_enable_min_size_(dma_enable_min_size),
117 dma_requested_(enable_dma),
120 dbuf_rx_block_size_(dma_rx.size_ / 2U),
121 dbuf_tx_block_size_(dma_tx.size_ / 2U)
123 ASSERT(host_ != SPI1_HOST);
124 ASSERT(host_ < SPI_HOST_MAX);
125 ASSERT(
static_cast<int>(host_) < SOC_SPI_PERIPH_NUM);
126 ASSERT(dma_rx_raw_.addr_ !=
nullptr);
127 ASSERT(dma_tx_raw_.addr_ !=
nullptr);
128 ASSERT(dma_rx_raw_.size_ > 0U);
129 ASSERT(dma_tx_raw_.size_ > 0U);
131 if (InitializeHardware() != ErrorCode::OK)
137 if (ConfigurePins() != ErrorCode::OK)
143 if (InstallInterrupt() != ErrorCode::OK)
151 const ErrorCode dma_ans = InitDmaBackend();
152 ASSERT(dma_ans == ErrorCode::OK);
153 if (dma_ans != ErrorCode::OK)
159 if (SetConfig(config) != ErrorCode::OK)
166bool ESP32SPI::Acquire() {
return !busy_.TestAndSet(); }
168void ESP32SPI::Release() { busy_.Clear(); }
174 return ErrorCode::OK;
177 if ((host_ <= SPI1_HOST) || (host_ >= SPI_HOST_MAX) ||
178 (
static_cast<int>(host_) >= SOC_SPI_PERIPH_NUM))
180 return ErrorCode::ARG_ERR;
183 const auto& signal = spi_periph_signal[host_];
187 return ErrorCode::NOT_SUPPORT;
192 (void)__DECLARE_RCC_ATOMIC_ENV;
193 spi_ll_enable_bus_clock(host_,
true);
194 spi_ll_reset_register(host_);
196 spi_ll_enable_clock(host_,
true);
197 spi_ll_master_init(hw_);
199 const spi_line_mode_t line_mode = {
204 spi_ll_master_set_line_mode(hw_, line_mode);
205 spi_ll_set_half_duplex(hw_,
false);
206 spi_ll_set_tx_lsbfirst(hw_,
false);
207 spi_ll_set_rx_lsbfirst(hw_,
false);
208 spi_ll_set_mosi_delay(hw_, 0, 0);
209 spi_ll_enable_mosi(hw_, 1);
210 spi_ll_enable_miso(hw_, 1);
211 spi_ll_set_dummy(hw_, 0);
212 spi_ll_set_command_bitlen(hw_, 0);
213 spi_ll_set_addr_bitlen(hw_, 0);
214 spi_ll_set_command(hw_, 0, 0,
false);
215 spi_ll_set_address(hw_, 0, 0,
false);
216 hw_->user.usr_command = 0;
217 hw_->user.usr_addr = 0;
219 spi_ll_set_clk_source(hw_, SPI_CLK_SRC_DEFAULT);
220 if (ResolveClockSource(source_clock_hz_) != ErrorCode::OK)
222 return ErrorCode::INIT_ERR;
225 spi_ll_disable_int(hw_);
226 spi_ll_clear_int_stat(hw_);
228 return ErrorCode::OK;
233 if (!initialized_ || (hw_ ==
nullptr))
235 return ErrorCode::STATE_ERR;
238 const auto& signal = spi_periph_signal[host_];
242 if (!GPIO_IS_VALID_OUTPUT_GPIO(sclk_pin_))
244 return ErrorCode::ARG_ERR;
246 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(sclk_pin_));
247 esp_rom_gpio_connect_out_signal(sclk_pin_, signal.spiclk_out,
false,
false);
248 gpio_input_enable(
static_cast<gpio_num_t
>(sclk_pin_));
249 esp_rom_gpio_connect_in_signal(sclk_pin_, signal.spiclk_in,
false);
254 if (!GPIO_IS_VALID_OUTPUT_GPIO(mosi_pin_))
256 return ErrorCode::ARG_ERR;
258 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(mosi_pin_));
259 esp_rom_gpio_connect_out_signal(mosi_pin_, signal.spid_out,
false,
false);
260 gpio_input_enable(
static_cast<gpio_num_t
>(mosi_pin_));
261 esp_rom_gpio_connect_in_signal(mosi_pin_, signal.spid_in,
false);
266 if (!GPIO_IS_VALID_GPIO(miso_pin_))
268 return ErrorCode::ARG_ERR;
270 gpio_input_enable(
static_cast<gpio_num_t
>(miso_pin_));
271 esp_rom_gpio_connect_in_signal(miso_pin_, signal.spiq_in,
false);
274 return ErrorCode::OK;
277ErrorCode ESP32SPI::ResolveClockSource(uint32_t& source_hz)
280 const esp_err_t err =
281 esp_clk_tree_src_get_freq_hz(
static_cast<soc_module_clk_t
>(SPI_CLK_SRC_DEFAULT),
282 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &source_hz);
283 if ((err != ESP_OK) || (source_hz == 0))
285 return ErrorCode::INIT_ERR;
287 return ErrorCode::OK;
294 return ErrorCode::OK;
297 const int irq_source =
static_cast<int>(spi_periph_signal[host_].irq);
298 if (esp_intr_alloc(irq_source, ESP_INTR_FLAG_IRAM, &ESP32SPI::SpiIsrEntry,
this,
299 &intr_handle_) != ESP_OK)
301 intr_handle_ =
nullptr;
302 return ErrorCode::INIT_ERR;
305 intr_installed_ =
true;
306 return ErrorCode::OK;
313 return ErrorCode::OK;
316 spi_dma_ctx_t* ctx =
nullptr;
317 if (spicommon_dma_chan_alloc(host_, SPI_DMA_CH_AUTO, &ctx) != ESP_OK)
319 return ErrorCode::INIT_ERR;
322 const size_t cfg_max_size = std::max(dma_rx_raw_.size_, dma_tx_raw_.size_);
323 int actual_max_size = 0;
324 if (spicommon_dma_desc_alloc(ctx,
static_cast<int>(cfg_max_size), &actual_max_size) !=
327 (void)spicommon_dma_chan_free(ctx);
328 return ErrorCode::INIT_ERR;
333 dma_max_transfer_bytes_ =
334 std::min<size_t>({
static_cast<size_t>(actual_max_size), dma_rx_raw_.size_,
335 dma_tx_raw_.size_, MAX_DMA_TRANSFER_BYTES});
337 if (dma_max_transfer_bytes_ == 0U)
339 return ErrorCode::INIT_ERR;
342 return ErrorCode::OK;
345void IRAM_ATTR ESP32SPI::SpiIsrEntry(
void* arg)
347 auto* spi =
static_cast<ESP32SPI*
>(arg);
350 spi->HandleInterrupt();
354void IRAM_ATTR ESP32SPI::HandleInterrupt()
356 if ((hw_ ==
nullptr) || !initialized_)
363 spi_ll_clear_int_stat(hw_);
367 if (!spi_ll_usr_is_done(hw_))
372 FinishAsync(
true, ErrorCode::OK);
375void IRAM_ATTR ESP32SPI::FinishAsync(
bool in_isr, ErrorCode ec)
382#if CONFIG_IDF_TARGET_ESP32
386 spi_dma_ctx_t* ctx = ToDmaCtx(dma_ctx_);
389 spicommon_dmaworkaround_idle(ctx->tx_dma_chan.chan_id);
394 spi_ll_disable_int(hw_);
395 spi_ll_clear_int_stat(hw_);
397 RawData rx = {
nullptr, 0U};
398 const RawData read_back = read_back_;
399 const bool mem_read = mem_read_;
400 if ((ec == ErrorCode::OK) && async_dma_rx_enabled_)
403#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
404 if (!CacheSyncDmaBuffer(rx.addr_, async_dma_size_,
false))
406 ec = ErrorCode::FAILED;
411 if ((ec == ErrorCode::OK) && (read_back.size_ > 0U))
413 if (rx.addr_ ==
nullptr)
417 uint8_t* src =
static_cast<uint8_t*
>(rx.addr_);
420 ASSERT(rx.size_ >= (read_back.size_ + 1U));
425 ASSERT(rx.size_ >= read_back.size_);
427 Memory::FastCopy(read_back.addr_, src, read_back.size_);
430 if (ec == ErrorCode::OK)
435 async_running_ =
false;
436 async_dma_size_ = 0U;
437 async_dma_rx_enabled_ =
false;
439 read_back_ = {
nullptr, 0};
441 if (rw_op_.type == OperationRW::OperationType::BLOCK)
443 (void)block_wait_.TryPost(in_isr, ec);
447 rw_op_.UpdateStatus(in_isr, ec);
453 if (!initialized_ || (hw_ ==
nullptr))
455 return ErrorCode::STATE_ERR;
459 return ErrorCode::BUSY;
462 if (config.
prescaler == Prescaler::UNKNOWN)
464 return ErrorCode::ARG_ERR;
467 ((dbuf_rx_block_size_ == 0U) || (dbuf_tx_block_size_ == 0U)))
469 return ErrorCode::ARG_ERR;
472 const uint32_t div = PrescalerToDiv(config.
prescaler);
473 if ((div == 0) || (source_clock_hz_ == 0))
475 return ErrorCode::ARG_ERR;
478 const uint32_t target_hz = source_clock_hz_ / div;
481 return ErrorCode::ARG_ERR;
485 spi_ll_master_set_mode(hw_, mode);
487 const int applied_hz = spi_ll_master_set_clock(hw_,
static_cast<int>(source_clock_hz_),
488 static_cast<int>(target_hz), 128);
491 return ErrorCode::INIT_ERR;
494 spi_ll_apply_config(hw_);
495 GetConfig() = config;
497 dbuf_active_block_ = 0U;
499 return ErrorCode::OK;
502bool ESP32SPI::UseLocalDoubleBuffer()
const
504 return dbuf_enabled_ && (dbuf_rx_block_size_ > 0U) && (dbuf_tx_block_size_ > 0U);
507RawData ESP32SPI::GetRxBuffer()
509 if (UseLocalDoubleBuffer())
511 auto* base =
static_cast<uint8_t*
>(dma_rx_raw_.addr_);
512 return {base +
static_cast<size_t>(dbuf_active_block_) * dbuf_rx_block_size_,
513 dbuf_rx_block_size_};
518RawData ESP32SPI::GetTxBuffer()
520 if (UseLocalDoubleBuffer())
522 auto* base =
static_cast<uint8_t*
>(dma_tx_raw_.addr_);
523 return {base +
static_cast<size_t>(dbuf_active_block_) * dbuf_tx_block_size_,
524 dbuf_tx_block_size_};
529void ESP32SPI::SwitchBufferLocal()
531 if (UseLocalDoubleBuffer())
533 dbuf_active_block_ ^= 1U;
537bool ESP32SPI::CanUseDma(
size_t size)
const
539 return dma_requested_ && dma_enabled_ && (dma_ctx_ !=
nullptr) &&
540 (size > dma_enable_min_size_) && (size <= dma_max_transfer_bytes_);
543ErrorCode ESP32SPI::EnsureReadyAndAcquire()
547 return ErrorCode::INIT_ERR;
551 return ErrorCode::BUSY;
553 return ErrorCode::OK;
556ErrorCode ESP32SPI::FinalizeSyncResult(OperationRW& op,
bool in_isr, ErrorCode ec)
558 if (op.type != OperationRW::OperationType::BLOCK)
560 op.UpdateStatus(in_isr, ec);
565ErrorCode ESP32SPI::CompleteZeroSize(OperationRW& op,
bool in_isr)
567 return FinalizeSyncResult(op, in_isr, ErrorCode::OK);
570ErrorCode ESP32SPI::ReturnAsyncStartResult(ErrorCode ec,
bool started)
579void ESP32SPI::ConfigureTransferRegisters(
size_t size)
581 static constexpr spi_line_mode_t LINE_MODE = {
586 const size_t bitlen = size * 8U;
588 spi_ll_master_set_line_mode(hw_, LINE_MODE);
589 spi_ll_set_mosi_bitlen(hw_, bitlen);
590 spi_ll_set_miso_bitlen(hw_, bitlen);
591 spi_ll_set_command_bitlen(hw_, 0);
592 spi_ll_set_addr_bitlen(hw_, 0);
593 spi_ll_set_command(hw_, 0, 0,
false);
594 spi_ll_set_address(hw_, 0, 0,
false);
595 hw_->user.usr_command = 0;
596 hw_->user.usr_addr = 0;
599ErrorCode ESP32SPI::StartAsyncTransfer(
const uint8_t* tx, uint8_t* rx,
size_t size,
600 bool enable_rx, RawData read_back,
bool mem_read,
601 OperationRW& op,
bool& started)
605 if (!CanUseDma(size))
607 return ErrorCode::NOT_SUPPORT;
609 if ((tx ==
nullptr) || (size == 0U))
611 return ErrorCode::ARG_ERR;
614 spi_dma_ctx_t* ctx = ToDmaCtx(dma_ctx_);
617 return ErrorCode::INIT_ERR;
620 const bool rx_enabled = enable_rx && (rx !=
nullptr);
621 ConfigureTransferRegisters(size);
623#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE || SOC_PSRAM_DMA_CAPABLE
624 if (!CacheSyncDmaBuffer(tx, size,
true))
626 return ErrorCode::FAILED;
630 if (enable_rx && (rx !=
nullptr))
632 spicommon_dma_desc_setup_link(ctx->dmadesc_rx, rx,
static_cast<int>(size),
true);
633 if (DmaReset(ctx->rx_dma_chan) != ESP_OK)
635 return ErrorCode::INIT_ERR;
637 spi_hal_hw_prepare_rx(hw_);
638 if (DmaStart(ctx->rx_dma_chan, ctx->dmadesc_rx) != ESP_OK)
640 return ErrorCode::INIT_ERR;
643#if CONFIG_IDF_TARGET_ESP32
647 spi_ll_dma_rx_enable(hw_,
true);
648 (void)DmaStart(ctx->rx_dma_chan,
nullptr);
652 spicommon_dma_desc_setup_link(ctx->dmadesc_tx, tx,
static_cast<int>(size),
false);
653 if (DmaReset(ctx->tx_dma_chan) != ESP_OK)
655 return ErrorCode::INIT_ERR;
657 spi_hal_hw_prepare_tx(hw_);
658 if (DmaStart(ctx->tx_dma_chan, ctx->dmadesc_tx) != ESP_OK)
660 return ErrorCode::INIT_ERR;
663#if CONFIG_IDF_TARGET_ESP32
664 spicommon_dmaworkaround_transfer_active(ctx->tx_dma_chan.chan_id);
668 read_back_ = read_back;
669 mem_read_ = mem_read;
670 async_dma_size_ = size;
671 async_dma_rx_enabled_ = rx_enabled;
672 if (op.type == OperationRW::OperationType::BLOCK)
674 block_wait_.Start(*op.data.sem_info.sem);
680 spi_ll_enable_mosi(hw_, 1);
681 spi_ll_enable_miso(hw_, rx_enabled ? 1 : 0);
682 spi_ll_clear_int_stat(hw_);
683 spi_ll_enable_int(hw_);
684 async_running_ =
true;
685 spi_ll_apply_config(hw_);
686 spi_ll_user_start(hw_);
689 if (op.type == OperationRW::OperationType::BLOCK)
691 return block_wait_.Wait(op.data.sem_info.timeout);
693 return ErrorCode::OK;
696ErrorCode ESP32SPI::ExecuteChunk(
const uint8_t* tx, uint8_t* rx,
size_t size,
699 if ((size == 0U) || (size > MAX_POLLING_TRANSFER_BYTES))
701 return ErrorCode::SIZE_ERR;
704 static constexpr std::array<uint8_t, MAX_POLLING_TRANSFER_BYTES> ZERO = {};
705 const uint8_t* tx_data = (tx !=
nullptr) ? tx : ZERO.data();
707 ConfigureTransferRegisters(size);
708 spi_ll_enable_mosi(hw_, 1);
709 spi_ll_enable_miso(hw_, enable_rx ? 1 : 0);
710 spi_ll_write_buffer(hw_, tx_data, size * 8U);
711 spi_ll_clear_int_stat(hw_);
712 spi_ll_apply_config(hw_);
713 spi_ll_user_start(hw_);
715 const uint64_t timeout_us = CalcPollingTimeoutUs(size, GetBusSpeed());
716 const uint64_t start_us = GetNowUs();
717 while (!spi_ll_usr_is_done(hw_))
719 if ((GetNowUs() - start_us) > timeout_us)
721 return ErrorCode::TIMEOUT;
725 if (enable_rx && (rx !=
nullptr))
727 spi_ll_read_buffer(hw_, rx, size * 8U);
729 spi_ll_clear_int_stat(hw_);
730 return ErrorCode::OK;
733ErrorCode ESP32SPI::ExecuteTransfer(
const uint8_t* tx, uint8_t* rx,
size_t size,
737 while (offset < size)
739 const size_t remain = size - offset;
740 const size_t chunk = std::min(remain, MAX_POLLING_TRANSFER_BYTES);
741 const uint8_t* tx_chunk = (tx !=
nullptr) ? (tx + offset) :
nullptr;
742 uint8_t* rx_chunk = (enable_rx && (rx !=
nullptr)) ? (rx + offset) :
nullptr;
744 const ErrorCode ec = ExecuteChunk(tx_chunk, rx_chunk, chunk, enable_rx);
745 if (ec != ErrorCode::OK)
752 return ErrorCode::OK;
758 const size_t need = std::max(read_data.
size_, write_data.
size_);
761 return CompleteZeroSize(op, in_isr);
764 const ErrorCode lock_ec = EnsureReadyAndAcquire();
765 if (lock_ec != ErrorCode::OK)
772 ASSERT(rx.
size_ >= need);
773 ASSERT(tx.
size_ >= need);
775 auto* tx_ptr =
static_cast<uint8_t*
>(tx.
addr_);
776 if (write_data.
size_ > 0U)
778 Memory::FastCopy(tx_ptr, write_data.
addr_, write_data.
size_);
780 if (need > write_data.
size_)
782 Memory::FastSet(tx_ptr + write_data.
size_, 0x00, need - write_data.
size_);
787 bool started =
false;
788 const ErrorCode ec = StartAsyncTransfer(tx_ptr,
static_cast<uint8_t*
>(rx.
addr_), need,
789 true, read_data,
false, op, started);
790 return ReturnAsyncStartResult(ec, started);
794 ExecuteTransfer(tx_ptr,
static_cast<uint8_t*
>(rx.
addr_), need,
true);
795 if (ec == ErrorCode::OK)
797 if (read_data.
size_ > 0U)
805 return FinalizeSyncResult(op, in_isr, ec);
810 if (read_data.
size_ == 0U)
812 return CompleteZeroSize(op, in_isr);
815 const ErrorCode lock_ec = EnsureReadyAndAcquire();
816 if (lock_ec != ErrorCode::OK)
823 const size_t total = read_data.
size_ + 1U;
825 ASSERT(rx.
size_ >= total);
826 ASSERT(tx.
size_ >= total);
828 auto* tx_ptr =
static_cast<uint8_t*
>(tx.
addr_);
829 tx_ptr[0] =
static_cast<uint8_t
>(reg | 0x80U);
830 Memory::FastSet(tx_ptr + 1, 0x00, read_data.
size_);
832 if (CanUseDma(total))
834 bool started =
false;
835 const ErrorCode ec = StartAsyncTransfer(tx_ptr,
static_cast<uint8_t*
>(rx.
addr_),
836 total,
true, read_data,
true, op, started);
837 return ReturnAsyncStartResult(ec, started);
841 ExecuteTransfer(tx_ptr,
static_cast<uint8_t*
>(rx.
addr_), total,
true);
842 if (ec == ErrorCode::OK)
844 auto* rx_ptr =
static_cast<uint8_t*
>(rx.
addr_);
845 Memory::FastCopy(read_data.
addr_, rx_ptr + 1, read_data.
size_);
850 return FinalizeSyncResult(op, in_isr, ec);
856 if (write_data.
size_ == 0U)
858 return CompleteZeroSize(op, in_isr);
861 const ErrorCode lock_ec = EnsureReadyAndAcquire();
862 if (lock_ec != ErrorCode::OK)
868 const size_t total = write_data.
size_ + 1U;
869 ASSERT(tx.
size_ >= total);
871 auto* tx_ptr =
static_cast<uint8_t*
>(tx.
addr_);
872 tx_ptr[0] =
static_cast<uint8_t
>(reg & 0x7FU);
873 Memory::FastCopy(tx_ptr + 1, write_data.
addr_, write_data.
size_);
875 if (CanUseDma(total))
877 bool started =
false;
878 const ErrorCode ec = StartAsyncTransfer(tx_ptr,
nullptr, total,
false, {
nullptr, 0},
880 return ReturnAsyncStartResult(ec, started);
883 const ErrorCode ec = ExecuteTransfer(tx_ptr,
nullptr, total,
false);
884 if (ec == ErrorCode::OK)
890 return FinalizeSyncResult(op, in_isr, ec);
897 return CompleteZeroSize(op, in_isr);
900 const ErrorCode lock_ec = EnsureReadyAndAcquire();
901 if (lock_ec != ErrorCode::OK)
908 ASSERT(rx.
size_ >= size);
909 ASSERT(tx.
size_ >= size);
913 bool started =
false;
914 const ErrorCode ec = StartAsyncTransfer(
static_cast<const uint8_t*
>(tx.
addr_),
915 static_cast<uint8_t*
>(rx.
addr_), size,
true,
916 {nullptr, 0},
false, op, started);
917 return ReturnAsyncStartResult(ec, started);
920 const ErrorCode ec = ExecuteTransfer(
static_cast<const uint8_t*
>(tx.
addr_),
921 static_cast<uint8_t*
>(rx.
addr_), size,
true);
922 if (ec == ErrorCode::OK)
928 return FinalizeSyncResult(op, in_isr, ec);
931uint32_t ESP32SPI::GetMaxBusSpeed()
const {
return source_clock_hz_; }
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
ClockPhase
定义 SPI 时钟相位。Defines the SPI clock phase.
@ EDGE_1
在第一个时钟边沿采样数据。Data sampled on the first clock edge.
ClockPolarity
定义 SPI 时钟极性。Defines the SPI clock polarity.
@ LOW
时钟空闲时为低电平。Clock idle low.
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
存储 SPI 配置参数的结构体。Structure for storing SPI configuration parameters.
bool double_buffer
是否使用双缓冲区。Whether to use double buffer.
ClockPhase clock_phase
SPI 时钟相位。SPI clock phase.
Prescaler prescaler
SPI 分频系数。SPI prescaler.
ClockPolarity clock_polarity
SPI 时钟极性。SPI clock polarity.