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