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