libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
esp_i2c.cpp
1#include "esp_i2c.hpp"
2
3#include <algorithm>
4#include <array>
5
6#include "esp_clk_tree.h"
7#include "esp_private/periph_ctrl.h"
8#include "esp_rom_gpio.h"
9#include "esp_rom_sys.h"
10#include "esp_timer.h"
11#include "libxr_def.hpp"
12#include "timebase.hpp"
13
14namespace LibXR
15{
16namespace
17{
18
19constexpr uint8_t ACK_VALUE = I2C_MASTER_ACK;
20constexpr uint8_t NACK_VALUE = I2C_MASTER_NACK;
21constexpr uint8_t CHECK_ACK = 1U;
22constexpr uint8_t NO_CHECK_ACK = 0U;
23
24uint64_t ToTimeoutUs(uint32_t timeout_ms)
25{
26 return (timeout_ms == UINT32_MAX) ? UINT64_MAX
27 : static_cast<uint64_t>(timeout_ms) * 1000ULL;
28}
29
30uint64_t GetNowUs() { return static_cast<uint64_t>(Timebase::GetMicroseconds()); }
31
32inline void SetBusClockAtomic(i2c_port_t port, bool enable)
33{
34#if defined(__GNUC__)
35#pragma GCC diagnostic push
36#pragma GCC diagnostic ignored "-Wunused-variable"
37#endif
38 PERIPH_RCC_ATOMIC() { i2c_ll_enable_bus_clock(port, enable); }
39#if defined(__GNUC__)
40#pragma GCC diagnostic pop
41#endif
42}
43
44inline void ResetBusRegisterAtomic(i2c_port_t port)
45{
46#if defined(__GNUC__)
47#pragma GCC diagnostic push
48#pragma GCC diagnostic ignored "-Wunused-variable"
49#endif
50 PERIPH_RCC_ATOMIC() { i2c_ll_reset_register(port); }
51#if defined(__GNUC__)
52#pragma GCC diagnostic pop
53#endif
54}
55
56void WriteCommand(i2c_dev_t* dev, int cmd_idx, uint8_t op_code, uint8_t ack_val,
57 uint8_t ack_exp, uint8_t ack_en, uint8_t byte_num)
58{
59 i2c_ll_hw_cmd_t cmd = {};
60 cmd.op_code = op_code;
61 cmd.ack_val = ack_val;
62 cmd.ack_exp = ack_exp;
63 cmd.ack_en = ack_en;
64 cmd.byte_num = byte_num;
65 i2c_ll_master_write_cmd_reg(dev, cmd, cmd_idx);
66}
67
68ErrorCode WaitSegmentDone(i2c_hal_context_t& hal, int done_cmd_idx, uint64_t timeout_us)
69{
70 const uint64_t start_us = GetNowUs();
71
72 auto recover_after_error = [&]()
73 {
74 i2c_ll_clear_intr_mask(hal.dev, I2C_LL_INTR_MASK);
75 i2c_hal_master_fsm_rst(&hal);
76 i2c_ll_update(hal.dev);
77 };
78
79 while (true)
80 {
81 const uint32_t intr = hal.dev->int_raw.val;
82
83 if ((intr & I2C_LL_INTR_NACK) != 0U)
84 {
85 recover_after_error();
87 }
88 if ((intr & I2C_LL_INTR_TIMEOUT) != 0U)
89 {
90 recover_after_error();
91 return ErrorCode::TIMEOUT;
92 }
93 if ((intr & I2C_LL_INTR_ARBITRATION) != 0U)
94 {
95 recover_after_error();
96 return ErrorCode::FAILED;
97 }
98
99 if (i2c_ll_master_is_cmd_done(hal.dev, done_cmd_idx) ||
100 ((intr & (I2C_LL_INTR_MST_COMPLETE | I2C_LL_INTR_END_DETECT)) != 0U))
101 {
102 return ErrorCode::OK;
103 }
104
105 if ((timeout_us != UINT64_MAX) && ((GetNowUs() - start_us) > timeout_us))
106 {
107 recover_after_error();
108 return ErrorCode::TIMEOUT;
109 }
110 }
111}
112
113ErrorCode StartAndWaitSegment(i2c_hal_context_t& hal, int done_cmd_idx,
114 uint64_t timeout_us)
115{
116 i2c_ll_clear_intr_mask(hal.dev, I2C_LL_INTR_MASK);
117 i2c_hal_master_trans_start(&hal);
118 return WaitSegmentDone(hal, done_cmd_idx, timeout_us);
119}
120
121template <typename OperationType>
122ErrorCode Complete(OperationType& op, bool in_isr, ErrorCode result)
123{
124 // Synchronous fast path: BLOCK ops return directly without post+wait
125 // round-trip.
126 if (op.type != OperationType::OperationType::BLOCK)
127 {
128 op.UpdateStatus(in_isr, result);
129 }
130 return result;
131}
132
133} // namespace
134
135ESP32I2C::ESP32I2C(i2c_port_t port_num, int scl_pin, int sda_pin, uint32_t clock_speed,
136 bool enable_internal_pullup, uint32_t timeout_ms,
137 uint32_t isr_enable_min_size)
138 : port_num_(port_num),
139 scl_pin_(scl_pin),
140 sda_pin_(sda_pin),
141 enable_internal_pullup_(enable_internal_pullup),
142 timeout_ms_(timeout_ms),
143 isr_enable_min_size_(isr_enable_min_size),
144 config_{clock_speed}
145{
146 ASSERT(port_num_ >= 0);
147 ASSERT(port_num_ < SOC_I2C_NUM);
148 ASSERT(GPIO_IS_VALID_OUTPUT_GPIO(static_cast<gpio_num_t>(scl_pin_)));
149 ASSERT(GPIO_IS_VALID_OUTPUT_GPIO(static_cast<gpio_num_t>(sda_pin_)));
150 ASSERT(config_.clock_speed > 0U);
151 static_assert(FIFO_LEN > 2U);
152
153 if (InitHardware() != ErrorCode::OK)
154 {
155 REQUIRE(false);
156 return;
157 }
158}
159
160bool ESP32I2C::Acquire() { return !busy_.TestAndSet(); }
161
162void ESP32I2C::Release() { busy_.Clear(); }
163
164bool ESP32I2C::IsValid7BitAddr(uint16_t addr) { return addr <= 0x7FU; }
165
166ErrorCode ESP32I2C::EnsureInitialized(bool in_isr)
167{
168 if (initialized_)
169 {
170 return ErrorCode::OK;
171 }
172 if (in_isr)
173 {
174 return ErrorCode::INIT_ERR;
175 }
176 return InitHardware();
177}
178
179size_t ESP32I2C::MemAddrBytes(MemAddrLength mem_addr_size)
180{
181 return (mem_addr_size == MemAddrLength::BYTE_16) ? 2U : 1U;
182}
183
184void ESP32I2C::EncodeMemAddr(uint16_t mem_addr, size_t mem_len, uint8_t* out)
185{
186 DEV_ASSERT(out != nullptr);
187 if (mem_len == 2U)
188 {
189 out[0] = static_cast<uint8_t>((mem_addr >> 8) & 0xFFU);
190 out[1] = static_cast<uint8_t>(mem_addr & 0xFFU);
191 return;
192 }
193
194 out[0] = static_cast<uint8_t>(mem_addr & 0xFFU);
195}
196
197ErrorCode ESP32I2C::ResolveClockSource(uint32_t& source_hz)
198{
199 source_hz = 0U;
200 const esp_err_t err =
201 esp_clk_tree_src_get_freq_hz(static_cast<soc_module_clk_t>(I2C_CLK_SRC_DEFAULT),
202 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &source_hz);
203 if ((err != ESP_OK) || (source_hz == 0U))
204 {
205 return ErrorCode::INIT_ERR;
206 }
207 return ErrorCode::OK;
208}
209
210ErrorCode ESP32I2C::ApplyConfig()
211{
212 if ((hal_.dev == nullptr) || (config_.clock_speed == 0U))
213 {
214 return ErrorCode::ARG_ERR;
215 }
216
217 uint32_t source_clock_hz = 0U;
218 if (ResolveClockSource(source_clock_hz) != ErrorCode::OK)
219 {
220 return ErrorCode::INIT_ERR;
221 }
222
223 // ESP-IDF supports Standard/Fast mode. Reject values before entering the
224 // LL timing calculation, whose preconditions are enforced with assertions.
225 if (config_.clock_speed > 400000U || config_.clock_speed > source_clock_hz / 28U)
226 {
227 return ErrorCode::NOT_SUPPORT;
228 }
229#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
230 // These targets have no module-clock divider and 10-bit START/STOP counters.
231 if (source_clock_hz / config_.clock_speed / 2U > I2C_SCL_START_HOLD_TIME_V)
232 {
233 return ErrorCode::NOT_SUPPORT;
234 }
235#else
236 // The LL implementation uses an 8-bit module-clock divider (encoded minus one).
237 if (source_clock_hz / (config_.clock_speed * 1024U) + 1U > 256U)
238 {
239 return ErrorCode::NOT_SUPPORT;
240 }
241#endif
242
243 source_clock_hz_ = source_clock_hz;
244 PERIPH_RCC_ATOMIC() { i2c_ll_set_source_clk(hal_.dev, I2C_CLK_SRC_DEFAULT); }
245 // ESP32's timing calculation compensates for the currently selected filter.
246 i2c_ll_master_set_filter(hal_.dev, 7U);
247 _i2c_hal_set_bus_timing(&hal_, static_cast<int>(config_.clock_speed),
248 I2C_CLK_SRC_DEFAULT, static_cast<int>(source_clock_hz_));
249 i2c_ll_update(hal_.dev);
250
251 return ErrorCode::OK;
252}
253
254ErrorCode ESP32I2C::InitHardware()
255{
256 if (initialized_)
257 {
258 return ErrorCode::OK;
259 }
260
261 if ((port_num_ < 0) || (port_num_ >= SOC_I2C_NUM) ||
262 (static_cast<size_t>(port_num_) >= SOC_I2C_NUM))
263 {
264 return ErrorCode::OUT_OF_RANGE;
265 }
266
267 if (!GPIO_IS_VALID_OUTPUT_GPIO(static_cast<gpio_num_t>(scl_pin_)) ||
268 !GPIO_IS_VALID_OUTPUT_GPIO(static_cast<gpio_num_t>(sda_pin_)))
269 {
270 return ErrorCode::ARG_ERR;
271 }
272
273 SetBusClockAtomic(port_num_, true);
274 ResetBusRegisterAtomic(port_num_);
275
276 _i2c_hal_init(&hal_, static_cast<int>(port_num_));
277 if (hal_.dev == nullptr)
278 {
279 return ErrorCode::INIT_ERR;
280 }
281
282 i2c_hal_master_init(&hal_);
283 i2c_ll_disable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
284 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
285
286 ErrorCode err = ConfigurePins();
287 if (err != ErrorCode::OK)
288 {
289 return err;
290 }
291
292 err = InstallInterrupt();
293 if (err != ErrorCode::OK)
294 {
295 return err;
296 }
297
298 err = ApplyConfig();
299 if (err != ErrorCode::OK)
300 {
301 return err;
302 }
303
304 initialized_ = true;
305 return ErrorCode::OK;
306}
307
308ErrorCode ESP32I2C::ConfigurePins()
309{
310 if (hal_.dev == nullptr)
311 {
312 return ErrorCode::STATE_ERR;
313 }
314
315 const auto& sig = i2c_periph_signal[port_num_];
316 const gpio_num_t sda_gpio = static_cast<gpio_num_t>(sda_pin_);
317 const gpio_num_t scl_gpio = static_cast<gpio_num_t>(scl_pin_);
318
319 gpio_set_level(sda_gpio, 1);
320 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(sda_pin_));
321 gpio_set_direction(sda_gpio, GPIO_MODE_INPUT_OUTPUT_OD);
322 gpio_set_pull_mode(sda_gpio,
323 enable_internal_pullup_ ? GPIO_PULLUP_ONLY : GPIO_FLOATING);
324 esp_rom_gpio_connect_out_signal(sda_pin_, sig.sda_out_sig, false, false);
325 esp_rom_gpio_connect_in_signal(sda_pin_, sig.sda_in_sig, false);
326
327 gpio_set_level(scl_gpio, 1);
328 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(scl_pin_));
329 gpio_set_direction(scl_gpio, GPIO_MODE_INPUT_OUTPUT_OD);
330 gpio_set_pull_mode(scl_gpio,
331 enable_internal_pullup_ ? GPIO_PULLUP_ONLY : GPIO_FLOATING);
332 esp_rom_gpio_connect_out_signal(scl_pin_, sig.scl_out_sig, false, false);
333 esp_rom_gpio_connect_in_signal(scl_pin_, sig.scl_in_sig, false);
334
335 return ErrorCode::OK;
336}
337
338ErrorCode ESP32I2C::RecoverController()
339{
340 if (hal_.dev == nullptr)
341 {
342 return ErrorCode::INIT_ERR;
343 }
344
345#if SOC_I2C_SUPPORT_HW_FSM_RST
346 i2c_hal_master_fsm_rst(&hal_);
347 i2c_ll_update(hal_.dev);
348#else
349 // Reset the controller before clearing the external bus. Restore source
350 // clock and timing first because the hardware clear FSM needs a live I2C
351 // clock after the register reset.
352 ResetBusRegisterAtomic(port_num_);
353 i2c_hal_master_init(&hal_);
354 i2c_ll_disable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
355 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
356 const ErrorCode config_ec = ApplyConfig();
357 if (config_ec != ErrorCode::OK)
358 {
359 return config_ec;
360 }
361#endif
362
363#if SOC_I2C_SUPPORT_HW_CLR_BUS
364 constexpr uint64_t BUS_CLEAR_TIMEOUT_US = 50000ULL;
365 const uint64_t start_us = GetNowUs();
366 i2c_ll_master_clr_bus(hal_.dev, I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT, true);
367 while (i2c_ll_master_is_bus_clear_done(hal_.dev))
368 {
369 if ((GetNowUs() - start_us) > BUS_CLEAR_TIMEOUT_US)
370 {
371 i2c_ll_master_clr_bus(hal_.dev, 0, false);
372 i2c_ll_update(hal_.dev);
373 return ErrorCode::TIMEOUT;
374 }
375 }
376 i2c_ll_update(hal_.dev);
377#else
378 // Software fallback for targets without the hardware bus-clear state
379 // machine. A slave interrupted mid-byte may keep SDA low across an MCU
380 // reset, so clock it through at most one byte and then generate STOP.
381 constexpr int BUS_CLEAR_SCL_PULSES = 9;
382 constexpr uint32_t BUS_CLEAR_HALF_PERIOD_US = 5U;
383
384 const gpio_num_t scl_gpio = static_cast<gpio_num_t>(scl_pin_);
385 const gpio_num_t sda_gpio = static_cast<gpio_num_t>(sda_pin_);
386 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(scl_pin_));
387 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(sda_pin_));
388 gpio_set_level(scl_gpio, 0);
389 gpio_set_level(sda_gpio, 1);
390 gpio_set_direction(scl_gpio, GPIO_MODE_OUTPUT_OD);
391 gpio_set_direction(sda_gpio, GPIO_MODE_INPUT_OUTPUT_OD);
392 gpio_set_pull_mode(scl_gpio,
393 enable_internal_pullup_ ? GPIO_PULLUP_ONLY : GPIO_FLOATING);
394 gpio_set_pull_mode(sda_gpio,
395 enable_internal_pullup_ ? GPIO_PULLUP_ONLY : GPIO_FLOATING);
396 esp_rom_delay_us(BUS_CLEAR_HALF_PERIOD_US);
397
398 int pulse_count = 0;
399 while ((gpio_get_level(sda_gpio) == 0) && (pulse_count++ < BUS_CLEAR_SCL_PULSES))
400 {
401 gpio_set_level(scl_gpio, 1);
402 esp_rom_delay_us(BUS_CLEAR_HALF_PERIOD_US);
403 gpio_set_level(scl_gpio, 0);
404 esp_rom_delay_us(BUS_CLEAR_HALF_PERIOD_US);
405 }
406
407 // Generate STOP: SDA low -> high while SCL is high.
408 gpio_set_level(sda_gpio, 0);
409 gpio_set_level(scl_gpio, 1);
410 esp_rom_delay_us(BUS_CLEAR_HALF_PERIOD_US);
411 gpio_set_level(sda_gpio, 1);
412 esp_rom_delay_us(BUS_CLEAR_HALF_PERIOD_US);
413#endif
414
415 // Software clear temporarily selects GPIO mode; re-applying the matrix
416 // routing is harmless on hardware-clear targets and restores it here.
417 const ErrorCode pin_ec = ConfigurePins();
418 if (pin_ec != ErrorCode::OK)
419 {
420 return pin_ec;
421 }
422
423 return ErrorCode::OK;
424}
425
426bool ESP32I2C::ShouldUseInterruptAsync(size_t total_size) const
427{
428 if (!intr_installed_)
429 {
430 return false;
431 }
432 return (isr_enable_min_size_ > 0U) &&
433 (total_size >= static_cast<size_t>(isr_enable_min_size_));
434}
435
436ErrorCode ESP32I2C::StartAsyncTransaction(uint16_t slave_addr,
437 const uint8_t* write_prefix_payload,
438 size_t write_prefix_size,
439 const uint8_t* write_payload, size_t write_size,
440 uint8_t* read_payload, size_t read_size,
441 ReadOperation& op, bool in_isr)
442{
443 if (!initialized_ || (hal_.dev == nullptr))
444 {
445 return ErrorCode::INIT_ERR;
446 }
447 if (!IsValid7BitAddr(slave_addr))
448 {
449 return ErrorCode::ARG_ERR;
450 }
451 if ((write_prefix_size > 0U) && (write_prefix_payload == nullptr))
452 {
453 return ErrorCode::PTR_NULL;
454 }
455 if (write_prefix_size > async_write_prefix_.size())
456 {
457 return ErrorCode::SIZE_ERR;
458 }
459 if ((write_size > 0U) && (write_payload == nullptr))
460 {
461 return ErrorCode::PTR_NULL;
462 }
463 if ((read_size > 0U) && (read_payload == nullptr))
464 {
465 return ErrorCode::PTR_NULL;
466 }
467 if (async_running_)
468 {
469 return ErrorCode::BUSY;
470 }
471
472 if (i2c_ll_is_bus_busy(hal_.dev))
473 {
474 if (in_isr)
475 {
476 return ErrorCode::BUSY;
477 }
478 const ErrorCode ec = RecoverController();
479 if (ec != ErrorCode::OK)
480 {
481 return ec;
482 }
483 }
484
485 i2c_ll_txfifo_rst(hal_.dev);
486 i2c_ll_rxfifo_rst(hal_.dev);
487 i2c_ll_disable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
488 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
489
490 async_op_ = op;
491 op.MarkAsRunning();
492 async_running_ = true;
493 async_slave_addr_ = slave_addr;
494 async_write_prefix_size_ = write_prefix_size;
495 async_write_prefix_offset_ = 0U;
496 if (write_prefix_size > 0U)
497 {
498 Memory::FastCopy(async_write_prefix_.data(), write_prefix_payload, write_prefix_size);
499 }
500 async_write_payload_ = write_payload;
501 async_write_size_ = write_size;
502 async_write_offset_ = 0U;
503 async_read_payload_ = read_payload;
504 async_read_size_ = read_size;
505 async_read_offset_ = 0U;
506 async_pending_read_chunk_ = 0U;
507 async_write_phase_done_ =
508 !((write_prefix_size > 0U) || (write_size > 0U) || (read_size == 0U));
509 async_write_addr_sent_ = false;
510 async_write_stop_sent_ = false;
511 async_read_addr_sent_ = false;
512
513 const ErrorCode kick = KickAsyncTransaction();
514 if ((kick == ErrorCode::PENDING) || (kick == ErrorCode::OK))
515 {
516 if (kick == ErrorCode::OK)
517 {
518 FinishAsync(false, ErrorCode::OK);
519 }
520 return ErrorCode::OK;
521 }
522
523 async_running_ = false;
524 async_write_prefix_size_ = 0U;
525 async_write_prefix_offset_ = 0U;
526 async_write_payload_ = nullptr;
527 async_write_size_ = 0U;
528 async_write_offset_ = 0U;
529 async_read_payload_ = nullptr;
530 async_read_size_ = 0U;
531 async_read_offset_ = 0U;
532 async_pending_read_chunk_ = 0U;
533 async_write_phase_done_ = true;
534 async_write_addr_sent_ = false;
535 async_write_stop_sent_ = false;
536 async_read_addr_sent_ = false;
537 return kick;
538}
539
540ErrorCode ESP32I2C::KickAsyncTransaction()
541{
542 if (!async_running_ || (hal_.dev == nullptr))
543 {
544 return ErrorCode::STATE_ERR;
545 }
546
547 const uint8_t write_addr =
548 static_cast<uint8_t>((async_slave_addr_ << 1U) | I2C_MASTER_WRITE);
549 const uint8_t read_addr =
550 static_cast<uint8_t>((async_slave_addr_ << 1U) | I2C_MASTER_READ);
551 const size_t fifo_len = FIFO_LEN;
552 const size_t write_chunk_cap = (fifo_len > 1U) ? (fifo_len - 1U) : 0U;
553 static_assert(write_chunk_cap > 0U);
554
555 while (true)
556 {
557 if (async_pending_read_chunk_ > 0U)
558 {
559 i2c_ll_read_rxfifo(hal_.dev, async_read_payload_ + async_read_offset_,
560 static_cast<uint8_t>(async_pending_read_chunk_));
561 async_read_offset_ += async_pending_read_chunk_;
562 async_pending_read_chunk_ = 0U;
563 }
564
565 int cmd_idx = 0;
566
567 if (!async_write_phase_done_)
568 {
569 if (!async_write_addr_sent_)
570 {
571 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_RESTART, ACK_VALUE, ACK_VALUE,
572 NO_CHECK_ACK, 0U);
573 i2c_ll_write_txfifo(hal_.dev, &write_addr, 1U);
574 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE,
575 CHECK_ACK, 1U);
576 async_write_addr_sent_ = true;
577 }
578
579 if (async_write_prefix_offset_ < async_write_prefix_size_)
580 {
581 const size_t chunk = std::min(
582 async_write_prefix_size_ - async_write_prefix_offset_, write_chunk_cap);
583 i2c_ll_write_txfifo(hal_.dev,
584 async_write_prefix_.data() + async_write_prefix_offset_,
585 static_cast<uint8_t>(chunk));
586 async_write_prefix_offset_ += chunk;
587
588 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE,
589 CHECK_ACK, static_cast<uint8_t>(chunk));
590 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
591 NO_CHECK_ACK, 0U);
592 }
593 else if (async_write_offset_ < async_write_size_)
594 {
595 const size_t chunk =
596 std::min(async_write_size_ - async_write_offset_, write_chunk_cap);
597 i2c_ll_write_txfifo(hal_.dev, async_write_payload_ + async_write_offset_,
598 static_cast<uint8_t>(chunk));
599 async_write_offset_ += chunk;
600
601 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE,
602 CHECK_ACK, static_cast<uint8_t>(chunk));
603 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
604 NO_CHECK_ACK, 0U);
605 }
606 else if (async_read_size_ == 0U)
607 {
608 if (!async_write_stop_sent_)
609 {
610 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_STOP, ACK_VALUE, ACK_VALUE,
611 NO_CHECK_ACK, 0U);
612#if SOC_I2C_STOP_INDEPENDENT
613 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
614 NO_CHECK_ACK, 0U);
615#endif
616 async_write_stop_sent_ = true;
617 }
618 async_write_phase_done_ = async_write_stop_sent_;
619 }
620 else
621 {
622 async_write_phase_done_ = true;
623 }
624
625 if (cmd_idx > 0)
626 {
627 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
628 i2c_ll_enable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
629 i2c_hal_master_trans_start(&hal_);
630 return ErrorCode::PENDING;
631 }
632
633 continue;
634 }
635
636 if (async_read_size_ > 0U)
637 {
638 if (!async_read_addr_sent_)
639 {
640 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_RESTART, ACK_VALUE, ACK_VALUE,
641 NO_CHECK_ACK, 0U);
642 i2c_ll_write_txfifo(hal_.dev, &read_addr, 1U);
643 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE,
644 CHECK_ACK, 1U);
645 async_read_addr_sent_ = true;
646 }
647
648 if (async_read_offset_ < async_read_size_)
649 {
650 const size_t chunk = std::min(async_read_size_ - async_read_offset_, fifo_len);
651 const bool is_last = (async_read_offset_ + chunk) >= async_read_size_;
652
653 if (!is_last)
654 {
655 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, ACK_VALUE, ACK_VALUE,
656 NO_CHECK_ACK, static_cast<uint8_t>(chunk));
657 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
658 NO_CHECK_ACK, 0U);
659 }
660 else if (chunk == 1U)
661 {
662 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, NACK_VALUE, ACK_VALUE,
663 NO_CHECK_ACK, 1U);
664 }
665 else
666 {
667 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, ACK_VALUE, ACK_VALUE,
668 NO_CHECK_ACK, static_cast<uint8_t>(chunk - 1U));
669 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, NACK_VALUE, ACK_VALUE,
670 NO_CHECK_ACK, 1U);
671 }
672
673 if (is_last)
674 {
675 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_STOP, ACK_VALUE, ACK_VALUE,
676 NO_CHECK_ACK, 0U);
677#if SOC_I2C_STOP_INDEPENDENT
678 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
679 NO_CHECK_ACK, 0U);
680#endif
681 }
682
683 async_pending_read_chunk_ = chunk;
684 }
685
686 if (cmd_idx > 0)
687 {
688 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
689 i2c_ll_enable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
690 i2c_hal_master_trans_start(&hal_);
691 return ErrorCode::PENDING;
692 }
693 }
694
695 return ErrorCode::OK;
696 }
697}
698
699void ESP32I2C::FinishAsync(bool in_isr, ErrorCode ec)
700{
701 if (!async_running_)
702 {
703 return;
704 }
705
706 if (hal_.dev != nullptr)
707 {
708 i2c_ll_disable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
709 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
710 }
711
712 ReadOperation op = async_op_;
713 async_op_ = {};
714 async_running_ = false;
715 async_write_prefix_size_ = 0U;
716 async_write_prefix_offset_ = 0U;
717 async_write_payload_ = nullptr;
718 async_write_size_ = 0U;
719 async_write_offset_ = 0U;
720 async_read_payload_ = nullptr;
721 async_read_size_ = 0U;
722 async_read_offset_ = 0U;
723 async_pending_read_chunk_ = 0U;
724 async_write_phase_done_ = true;
725 async_write_addr_sent_ = false;
726 async_write_stop_sent_ = false;
727 async_read_addr_sent_ = false;
728
729 Release();
730 if (op.type == ReadOperation::OperationType::BLOCK)
731 {
732 (void)block_wait_.TryPost(in_isr, ec);
733 }
734 else
735 {
736 op.UpdateStatus(in_isr, ec);
737 }
738}
739
740ErrorCode ESP32I2C::InstallInterrupt()
741{
742 if (intr_installed_)
743 {
744 return ErrorCode::OK;
745 }
746
747 const int irq = i2c_periph_signal[port_num_].irq;
748 if (irq <= 0)
749 {
750 return ErrorCode::NOT_SUPPORT;
751 }
752
753 if (esp_intr_alloc(irq, 0, I2cIsrEntry, this, &intr_handle_) != ESP_OK)
754 {
755 intr_handle_ = nullptr;
756 return ErrorCode::INIT_ERR;
757 }
758
759 intr_installed_ = true;
760 return ErrorCode::OK;
761}
762
763void ESP32I2C::I2cIsrEntry(void* arg)
764{
765 auto* self = static_cast<ESP32I2C*>(arg);
766 if (self != nullptr)
767 {
768 self->HandleInterrupt();
769 }
770}
771
772void ESP32I2C::HandleInterrupt()
773{
774 if (hal_.dev == nullptr)
775 {
776 return;
777 }
778
779 const uint32_t intr = hal_.dev->int_raw.val;
780 if ((intr & I2C_LL_MASTER_EVENT_INTR) == 0U)
781 {
782 return;
783 }
784
785 if (!async_running_)
786 {
787 i2c_ll_disable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
788 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
789 return;
790 }
791
792 i2c_ll_disable_intr_mask(hal_.dev, I2C_LL_MASTER_EVENT_INTR);
793 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
794
795 if ((intr & I2C_LL_INTR_NACK) != 0U)
796 {
797 i2c_hal_master_fsm_rst(&hal_);
798 i2c_ll_update(hal_.dev);
799 FinishAsync(true, ErrorCode::NO_RESPONSE);
800 return;
801 }
802 if ((intr & I2C_LL_INTR_TIMEOUT) != 0U)
803 {
804 i2c_hal_master_fsm_rst(&hal_);
805 i2c_ll_update(hal_.dev);
806 FinishAsync(true, ErrorCode::TIMEOUT);
807 return;
808 }
809 if ((intr & I2C_LL_INTR_ARBITRATION) != 0U)
810 {
811 i2c_hal_master_fsm_rst(&hal_);
812 i2c_ll_update(hal_.dev);
813 FinishAsync(true, ErrorCode::FAILED);
814 return;
815 }
816
817 if ((intr & (I2C_LL_INTR_MST_COMPLETE | I2C_LL_INTR_END_DETECT)) == 0U)
818 {
819 return;
820 }
821
822 const ErrorCode kick = KickAsyncTransaction();
823 if (kick == ErrorCode::PENDING)
824 {
825 return;
826 }
827
828 FinishAsync(true, kick);
829}
830
831ErrorCode ESP32I2C::ExecuteTransaction(uint16_t slave_addr, const uint8_t* write_payload,
832 size_t write_size, uint8_t* read_payload,
833 size_t read_size, bool in_isr)
834{
835 if (!initialized_ || (hal_.dev == nullptr))
836 {
837 return ErrorCode::INIT_ERR;
838 }
839 if (!IsValid7BitAddr(slave_addr))
840 {
841 return ErrorCode::ARG_ERR;
842 }
843 if ((write_size > 0U) && (write_payload == nullptr))
844 {
845 return ErrorCode::PTR_NULL;
846 }
847 if ((read_size > 0U) && (read_payload == nullptr))
848 {
849 return ErrorCode::PTR_NULL;
850 }
851
852 if (i2c_ll_is_bus_busy(hal_.dev))
853 {
854 if (in_isr)
855 {
856 return ErrorCode::BUSY;
857 }
858 const ErrorCode ec = RecoverController();
859 if (ec != ErrorCode::OK)
860 {
861 return ec;
862 }
863 }
864
865 i2c_ll_txfifo_rst(hal_.dev);
866 i2c_ll_rxfifo_rst(hal_.dev);
867 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
868
869 const uint64_t timeout_us = ToTimeoutUs(timeout_ms_);
870 const uint8_t write_addr = static_cast<uint8_t>((slave_addr << 1U) | I2C_MASTER_WRITE);
871 const uint8_t read_addr = static_cast<uint8_t>((slave_addr << 1U) | I2C_MASTER_READ);
872 const size_t fifo_len = FIFO_LEN;
873 const size_t write_chunk_cap = (fifo_len > 1U) ? (fifo_len - 1U) : 0U;
874 static_assert(write_chunk_cap > 0U);
875
876 int cmd_idx = 0;
877
878 auto start_and_wait = [&](int done_cmd) -> ErrorCode
879 { return StartAndWaitSegment(hal_, done_cmd, timeout_us); };
880
881 if ((write_size > 0U) || (read_size == 0U))
882 {
883 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_RESTART, ACK_VALUE, ACK_VALUE,
884 NO_CHECK_ACK, 0U);
885
886 i2c_ll_write_txfifo(hal_.dev, &write_addr, 1U);
887 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE, CHECK_ACK,
888 1U);
889
890 size_t write_offset = 0U;
891 while (write_offset < write_size)
892 {
893 const size_t chunk = std::min(write_size - write_offset, write_chunk_cap);
894 i2c_ll_write_txfifo(hal_.dev,
895 static_cast<const uint8_t*>(write_payload) + write_offset,
896 static_cast<uint8_t>(chunk));
897 write_offset += chunk;
898
899 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE, CHECK_ACK,
900 static_cast<uint8_t>(chunk));
901 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
902 NO_CHECK_ACK, 0U);
903
904 const ErrorCode ec = start_and_wait(cmd_idx - 1);
905 if (ec != ErrorCode::OK)
906 {
907 if (!in_isr)
908 {
909 (void)RecoverController();
910 }
911 return ec;
912 }
913 cmd_idx = 0;
914 }
915
916 if (write_size == 0U)
917 {
918 if (read_size == 0U)
919 {
920 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_STOP, ACK_VALUE, ACK_VALUE,
921 NO_CHECK_ACK, 0U);
922#if SOC_I2C_STOP_INDEPENDENT
923 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
924 NO_CHECK_ACK, 0U);
925#endif
926 }
927 const ErrorCode ec = start_and_wait(cmd_idx - 1);
928 if (ec != ErrorCode::OK)
929 {
930 if (!in_isr)
931 {
932 (void)RecoverController();
933 }
934 return ec;
935 }
936 cmd_idx = 0;
937 }
938 else if (read_size == 0U)
939 {
940 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_STOP, ACK_VALUE, ACK_VALUE,
941 NO_CHECK_ACK, 0U);
942#if SOC_I2C_STOP_INDEPENDENT
943 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
944 NO_CHECK_ACK, 0U);
945#endif
946 const ErrorCode ec = start_and_wait(cmd_idx - 1);
947 if (ec != ErrorCode::OK)
948 {
949 if (!in_isr)
950 {
951 (void)RecoverController();
952 }
953 return ec;
954 }
955 cmd_idx = 0;
956 }
957 }
958
959 if (read_size > 0U)
960 {
961 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_RESTART, ACK_VALUE, ACK_VALUE,
962 NO_CHECK_ACK, 0U);
963 i2c_ll_write_txfifo(hal_.dev, &read_addr, 1U);
964 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_WRITE, ACK_VALUE, ACK_VALUE, CHECK_ACK,
965 1U);
966
967 size_t read_offset = 0U;
968 while (read_offset < read_size)
969 {
970 const size_t chunk = std::min(read_size - read_offset, fifo_len);
971 const bool is_last = (read_offset + chunk) >= read_size;
972
973 if (!is_last)
974 {
975 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, ACK_VALUE, ACK_VALUE,
976 NO_CHECK_ACK, static_cast<uint8_t>(chunk));
977 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
978 NO_CHECK_ACK, 0U);
979 }
980 else if (chunk == 1U)
981 {
982 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, NACK_VALUE, ACK_VALUE,
983 NO_CHECK_ACK, 1U);
984 }
985 else
986 {
987 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, ACK_VALUE, ACK_VALUE,
988 NO_CHECK_ACK, static_cast<uint8_t>(chunk - 1U));
989 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_READ, NACK_VALUE, ACK_VALUE,
990 NO_CHECK_ACK, 1U);
991 }
992
993 if (is_last)
994 {
995 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_STOP, ACK_VALUE, ACK_VALUE,
996 NO_CHECK_ACK, 0U);
997#if SOC_I2C_STOP_INDEPENDENT
998 WriteCommand(hal_.dev, cmd_idx++, I2C_LL_CMD_END, ACK_VALUE, ACK_VALUE,
999 NO_CHECK_ACK, 0U);
1000#endif
1001 }
1002
1003 const ErrorCode ec = start_and_wait(cmd_idx - 1);
1004 if (ec != ErrorCode::OK)
1005 {
1006 if (!in_isr)
1007 {
1008 (void)RecoverController();
1009 }
1010 return ec;
1011 }
1012
1013 i2c_ll_read_rxfifo(hal_.dev, read_payload + read_offset,
1014 static_cast<uint8_t>(chunk));
1015 read_offset += chunk;
1016 cmd_idx = 0;
1017 }
1018 }
1019
1020 i2c_ll_clear_intr_mask(hal_.dev, I2C_LL_INTR_MASK);
1021 return ErrorCode::OK;
1022}
1023
1024ErrorCode ESP32I2C::SetConfig(Configuration config)
1025{
1026 if (config.clock_speed == 0U)
1027 {
1028 return ErrorCode::ARG_ERR;
1029 }
1030
1031 if (!initialized_)
1032 {
1033 const ErrorCode init_err = InitHardware();
1034 if (init_err != ErrorCode::OK)
1035 {
1036 return init_err;
1037 }
1038 }
1039
1040 if (!Acquire())
1041 {
1042 return ErrorCode::BUSY;
1043 }
1044
1045 if (i2c_ll_is_bus_busy(hal_.dev))
1046 {
1047 Release();
1048 return ErrorCode::BUSY;
1049 }
1050
1051 const Configuration previous_config = config_;
1052 config_ = config;
1053 const ErrorCode ans = ApplyConfig();
1054 if (ans != ErrorCode::OK)
1055 {
1056 config_ = previous_config;
1057 }
1058 Release();
1059 return ans;
1060}
1061
1062ErrorCode ESP32I2C::Write(uint16_t slave_addr, ConstRawData write_data,
1063 WriteOperation& op, bool in_isr)
1064{
1065 const ErrorCode init_ec = EnsureInitialized(in_isr);
1066 if (init_ec != ErrorCode::OK)
1067 {
1068 return Complete(op, in_isr, init_ec);
1069 }
1070
1071 if (!IsValid7BitAddr(slave_addr))
1072 {
1073 return Complete(op, in_isr, ErrorCode::ARG_ERR);
1074 }
1075
1076 if ((write_data.size_ > 0U) && (write_data.addr_ == nullptr))
1077 {
1078 return Complete(op, in_isr, ErrorCode::PTR_NULL);
1079 }
1080
1081 if (!Acquire())
1082 {
1083 return Complete(op, in_isr, ErrorCode::BUSY);
1084 }
1085
1086 const size_t total_size = write_data.size_;
1087 if (ShouldUseInterruptAsync(total_size))
1088 {
1089 if (op.type == WriteOperation::OperationType::BLOCK)
1090 {
1091 block_wait_.Start(*op.data.sem_info.sem);
1092 }
1093 const ErrorCode ans = StartAsyncTransaction(
1094 slave_addr, nullptr, 0U, static_cast<const uint8_t*>(write_data.addr_),
1095 write_data.size_, nullptr, 0U, op, in_isr);
1096 if (ans != ErrorCode::OK)
1097 {
1098 if (op.type == WriteOperation::OperationType::BLOCK)
1099 {
1100 block_wait_.Cancel();
1101 }
1102 Release();
1103 return Complete(op, in_isr, ans);
1104 }
1105 if (op.type == WriteOperation::OperationType::BLOCK)
1106 {
1107 ASSERT(!in_isr);
1108 return block_wait_.Wait(op.data.sem_info.timeout);
1109 }
1110 return ErrorCode::OK;
1111 }
1112
1113 const ErrorCode ans =
1114 ExecuteTransaction(slave_addr, static_cast<const uint8_t*>(write_data.addr_),
1115 write_data.size_, nullptr, 0U, in_isr);
1116 Release();
1117 return Complete(op, in_isr, ans);
1118}
1119
1120ErrorCode ESP32I2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
1121 bool in_isr)
1122{
1123 const ErrorCode init_ec = EnsureInitialized(in_isr);
1124 if (init_ec != ErrorCode::OK)
1125 {
1126 return Complete(op, in_isr, init_ec);
1127 }
1128
1129 if (!IsValid7BitAddr(slave_addr))
1130 {
1131 return Complete(op, in_isr, ErrorCode::ARG_ERR);
1132 }
1133
1134 if ((read_data.size_ > 0U) && (read_data.addr_ == nullptr))
1135 {
1136 return Complete(op, in_isr, ErrorCode::PTR_NULL);
1137 }
1138
1139 if (!Acquire())
1140 {
1141 return Complete(op, in_isr, ErrorCode::BUSY);
1142 }
1143
1144 const size_t total_size = read_data.size_;
1145 if (ShouldUseInterruptAsync(total_size))
1146 {
1147 if (op.type == ReadOperation::OperationType::BLOCK)
1148 {
1149 block_wait_.Start(*op.data.sem_info.sem);
1150 }
1151 const ErrorCode ans = StartAsyncTransaction(slave_addr, nullptr, 0U, nullptr, 0U,
1152 static_cast<uint8_t*>(read_data.addr_),
1153 read_data.size_, op, in_isr);
1154 if (ans != ErrorCode::OK)
1155 {
1156 if (op.type == ReadOperation::OperationType::BLOCK)
1157 {
1158 block_wait_.Cancel();
1159 }
1160 Release();
1161 return Complete(op, in_isr, ans);
1162 }
1163 if (op.type == ReadOperation::OperationType::BLOCK)
1164 {
1165 ASSERT(!in_isr);
1166 return block_wait_.Wait(op.data.sem_info.timeout);
1167 }
1168 return ErrorCode::OK;
1169 }
1170
1171 const ErrorCode ans =
1172 ExecuteTransaction(slave_addr, nullptr, 0U, static_cast<uint8_t*>(read_data.addr_),
1173 read_data.size_, in_isr);
1174 Release();
1175 return Complete(op, in_isr, ans);
1176}
1177
1178ErrorCode ESP32I2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
1179 ConstRawData write_data, WriteOperation& op,
1180 MemAddrLength mem_addr_size, bool in_isr)
1181{
1182 const ErrorCode init_ec = EnsureInitialized(in_isr);
1183 if (init_ec != ErrorCode::OK)
1184 {
1185 return Complete(op, in_isr, init_ec);
1186 }
1187
1188 if (!IsValid7BitAddr(slave_addr))
1189 {
1190 return Complete(op, in_isr, ErrorCode::ARG_ERR);
1191 }
1192
1193 if ((write_data.size_ > 0U) && (write_data.addr_ == nullptr))
1194 {
1195 return Complete(op, in_isr, ErrorCode::PTR_NULL);
1196 }
1197
1198 const size_t mem_len = MemAddrBytes(mem_addr_size);
1199 if (mem_len > MAX_WRITE_PAYLOAD)
1200 {
1201 return Complete(op, in_isr, ErrorCode::SIZE_ERR);
1202 }
1203
1204 if (!Acquire())
1205 {
1206 return Complete(op, in_isr, ErrorCode::BUSY);
1207 }
1208
1209 std::array<uint8_t, 2> mem_raw = {};
1210 EncodeMemAddr(mem_addr, mem_len, mem_raw.data());
1211
1212 const size_t total_size = mem_len + write_data.size_;
1213 if (ShouldUseInterruptAsync(total_size))
1214 {
1215 if (op.type == WriteOperation::OperationType::BLOCK)
1216 {
1217 block_wait_.Start(*op.data.sem_info.sem);
1218 }
1219 const ErrorCode ans =
1220 StartAsyncTransaction(slave_addr, mem_raw.data(), mem_len,
1221 static_cast<const uint8_t*>(write_data.addr_),
1222 write_data.size_, nullptr, 0U, op, in_isr);
1223 if (ans != ErrorCode::OK)
1224 {
1225 if (op.type == WriteOperation::OperationType::BLOCK)
1226 {
1227 block_wait_.Cancel();
1228 }
1229 Release();
1230 return Complete(op, in_isr, ans);
1231 }
1232 if (op.type == WriteOperation::OperationType::BLOCK)
1233 {
1234 ASSERT(!in_isr);
1235 return block_wait_.Wait(op.data.sem_info.timeout);
1236 }
1237 return ErrorCode::OK;
1238 }
1239
1240 std::array<uint8_t, FIFO_LEN> staging = {};
1241 const size_t max_chunk = MAX_WRITE_PAYLOAD - mem_len;
1242 auto* src = static_cast<const uint8_t*>(write_data.addr_);
1243 size_t offset = 0U;
1244 ErrorCode ans = ErrorCode::OK;
1245
1246 if (write_data.size_ == 0U)
1247 {
1248 EncodeMemAddr(mem_addr, mem_len, staging.data());
1249 ans = ExecuteTransaction(slave_addr, staging.data(), mem_len, nullptr, 0U, in_isr);
1250 }
1251 else
1252 {
1253 while (offset < write_data.size_)
1254 {
1255 const size_t chunk = std::min(write_data.size_ - offset, max_chunk);
1256 const uint16_t cur_mem = static_cast<uint16_t>(mem_addr + offset);
1257 EncodeMemAddr(cur_mem, mem_len, staging.data());
1258 Memory::FastCopy(staging.data() + mem_len, src + offset, chunk);
1259 ans = ExecuteTransaction(slave_addr, staging.data(), mem_len + chunk, nullptr, 0U,
1260 in_isr);
1261 if (ans != ErrorCode::OK)
1262 {
1263 break;
1264 }
1265 offset += chunk;
1266 }
1267 }
1268
1269 Release();
1270 return Complete(op, in_isr, ans);
1271}
1272
1273ErrorCode ESP32I2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
1274 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
1275{
1276 const ErrorCode init_ec = EnsureInitialized(in_isr);
1277 if (init_ec != ErrorCode::OK)
1278 {
1279 return Complete(op, in_isr, init_ec);
1280 }
1281
1282 if (!IsValid7BitAddr(slave_addr))
1283 {
1284 return Complete(op, in_isr, ErrorCode::ARG_ERR);
1285 }
1286
1287 if ((read_data.size_ > 0U) && (read_data.addr_ == nullptr))
1288 {
1289 return Complete(op, in_isr, ErrorCode::PTR_NULL);
1290 }
1291
1292 const size_t mem_len = MemAddrBytes(mem_addr_size);
1293 if (mem_len > MAX_WRITE_READ_PREFIX)
1294 {
1295 return Complete(op, in_isr, ErrorCode::SIZE_ERR);
1296 }
1297
1298 if (!Acquire())
1299 {
1300 return Complete(op, in_isr, ErrorCode::BUSY);
1301 }
1302
1303 std::array<uint8_t, 2> mem_raw = {};
1304 EncodeMemAddr(mem_addr, mem_len, mem_raw.data());
1305
1306 auto* dst = static_cast<uint8_t*>(read_data.addr_);
1307 const size_t total_size = mem_len + read_data.size_;
1308 if ((read_data.size_ > 0U) && ShouldUseInterruptAsync(total_size))
1309 {
1310 if (op.type == ReadOperation::OperationType::BLOCK)
1311 {
1312 block_wait_.Start(*op.data.sem_info.sem);
1313 }
1314 const ErrorCode ans =
1315 StartAsyncTransaction(slave_addr, mem_raw.data(), mem_len, nullptr, 0U, dst,
1316 read_data.size_, op, in_isr);
1317 if (ans != ErrorCode::OK)
1318 {
1319 if (op.type == ReadOperation::OperationType::BLOCK)
1320 {
1321 block_wait_.Cancel();
1322 }
1323 Release();
1324 return Complete(op, in_isr, ans);
1325 }
1326 if (op.type == ReadOperation::OperationType::BLOCK)
1327 {
1328 ASSERT(!in_isr);
1329 return block_wait_.Wait(op.data.sem_info.timeout);
1330 }
1331 return ErrorCode::OK;
1332 }
1333
1334 size_t offset = 0U;
1335 ErrorCode ans = ErrorCode::OK;
1336
1337 while (offset < read_data.size_)
1338 {
1339 const size_t chunk = std::min(read_data.size_ - offset, MAX_READ_PAYLOAD);
1340 const uint16_t cur_mem = static_cast<uint16_t>(mem_addr + offset);
1341 EncodeMemAddr(cur_mem, mem_len, mem_raw.data());
1342
1343 ans = ExecuteTransaction(slave_addr, mem_raw.data(), mem_len, dst + offset, chunk,
1344 in_isr);
1345 if (ans != ErrorCode::OK)
1346 {
1347 break;
1348 }
1349 offset += chunk;
1350 }
1351
1352 Release();
1353 return Complete(op, in_isr, ans);
1354}
1355
1356} // namespace LibXR
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
uint32_t timeout
等待超时值 / Wait timeout.
union LibXR::Operation::@6 data
完成通知对象,由 type 选择有效成员 / Notification target selected by type.
Semaphore * sem
借用的信号量 / Borrowed semaphore.
OperationType type
当前通知方式 / Current notification mode.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
static MicrosecondTimestamp GetMicroseconds()
获取当前时间的微秒级时间戳。 Gets the current timestamp in microseconds.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ TIMEOUT
超时 / Timeout
@ NO_RESPONSE
无响应 / No response
@ FAILED
操作失败 / Operation failed
@ OK
操作成功 / Operation successful
Operation< ErrorCode > ReadOperation
读操作的完成通知描述符 / Read completion descriptor.
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.
Definition i2c.hpp:24
uint32_t clock_speed
I2C 通信时钟速率(单位:Hz) / The I2C clock speed (in Hz).
Definition i2c.hpp:26