libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
hpm_i2c.cpp
1#include "hpm_i2c.hpp"
2
3#include <cstdint>
4
5using namespace LibXR;
6
7namespace
8{
9
10constexpr uint16_t kSharedMax7BitAddress = 0x7FU;
11constexpr uint16_t kSharedMax10BitAddress = 0x3FFU;
12
13uint16_t ResolveHpmI2cMaxSlaveAddress(HPMI2C::AddressMode mode)
14{
15 return mode == HPMI2C::AddressMode::ADDR_10BIT ? kSharedMax10BitAddress
16 : kSharedMax7BitAddress;
17}
18
19ErrorCode ValidateHpmI2cSlaveAddress(HPMI2C::AddressMode mode, uint16_t slave_addr)
20{
21 return (slave_addr <= ResolveHpmI2cMaxSlaveAddress(mode)) ? ErrorCode::OK
22 : ErrorCode::ARG_ERR;
23}
24
25ErrorCode ResolveHpmI2cMemAddressSize(I2C::MemAddrLength len, uint32_t& addr_size)
26{
27 switch (len)
28 {
29 case I2C::MemAddrLength::BYTE_8:
30 addr_size = 1U;
31 return ErrorCode::OK;
32 case I2C::MemAddrLength::BYTE_16:
33 addr_size = 2U;
34 return ErrorCode::OK;
35 default:
36 addr_size = 0U;
37 return ErrorCode::ARG_ERR;
38 }
39}
40
41void FillHpmI2cMemAddress(uint16_t mem_addr, I2C::MemAddrLength len, uint8_t out[2])
42{
43 if (len == I2C::MemAddrLength::BYTE_16)
44 {
45 out[0] = static_cast<uint8_t>((mem_addr >> 8) & 0xFFU);
46 out[1] = static_cast<uint8_t>(mem_addr & 0xFFU);
47 }
48 else
49 {
50 out[0] = static_cast<uint8_t>(mem_addr & 0xFFU);
51 }
52}
53
54} // namespace
55
57{
58 return ResolveHpmI2cMaxSlaveAddress(mode);
59}
60
61ErrorCode HPMI2C::ValidateSlaveAddress(uint16_t slave_addr) const
62{
63 return ValidateHpmI2cSlaveAddress(address_mode_, slave_addr);
64}
65
66ErrorCode HPMI2C::ResolveMemAddressSize(MemAddrLength len, uint32_t& addr_size)
67{
68 return ResolveHpmI2cMemAddressSize(len, addr_size);
69}
70
71void HPMI2C::FillMemAddress(uint16_t mem_addr, MemAddrLength len, uint8_t out[2])
72{
73 FillHpmI2cMemAddress(mem_addr, len, out);
74}
75
77{
78 if (policy.addr_hit_timeout_us == 0U || policy.stop_timeout_us == 0U ||
79 policy.bus_idle_timeout_us == 0U || policy.transfer_timeout_us == 0U)
80 {
81 return ErrorCode::ARG_ERR;
82 }
83
84#if LIBXR_HPM_I2C_HAS_DMA_MGR
85 if (AsyncTransferActive())
86 {
87 return ErrorCode::BUSY;
88 }
89#endif
90
91 wait_policy_ = policy;
92 return ErrorCode::OK;
93}
94
95#if LIBXR_HPM_I2C_SUPPORTED
96
97#if __has_include("board.h")
98extern "C"
99{
100#include "board.h"
101 void board_i2c_bus_clear(I2C_Type* ptr);
102}
103#define LIBXR_HPM_I2C_HAS_BOARD_HELPER 1
104#else
105#define LIBXR_HPM_I2C_HAS_BOARD_HELPER 0
106#endif
107
108#if __has_include("hpm_interrupt.h")
109#include "hpm_interrupt.h"
110#define LIBXR_HPM_I2C_HAS_INTERRUPT 1
111#else
112#define LIBXR_HPM_I2C_HAS_INTERRUPT 0
113#endif
114
115#if __has_include("hpm_l1c_drv.h")
116#include "hpm_l1c_drv.h"
117#define LIBXR_HPM_I2C_HAS_L1C 1
118#else
119#define LIBXR_HPM_I2C_HAS_L1C 0
120#endif
121
122#if defined(__GNUC__) || defined(__clang__)
128extern "C" void libxr_hpm_i2c_wait_relax_hook(void) __attribute__((weak));
129#define LIBXR_HPM_I2C_HAS_WAIT_RELAX_HOOK 1
130#else
131#define LIBXR_HPM_I2C_HAS_WAIT_RELAX_HOOK 0
132#endif
133
134#if LIBXR_HPM_I2C_HAS_DMA_MGR
135#include "hpm_i2c_platform.hpp"
136#endif
137
138namespace
139{
140
141// Core blocking flags and timeout policy shared by polling and async setup paths.
142constexpr uint16_t kI2CFlagRead = I2C_RD;
143constexpr uint16_t kI2CFlagAddr10Bit = I2C_ADDR_10BIT;
144constexpr uint16_t kI2CFlagNoStart = I2C_NO_START;
145constexpr uint16_t kI2CFlagNoAddress = I2C_NO_ADDRESS;
146constexpr uint16_t kI2CFlagNoStop = I2C_NO_STOP;
147constexpr uint16_t kI2CFlagWriteCheckAck = I2C_WRITE_CHECK_ACK;
148
149// DMA manager state and ISR instance slots stay in this TU to avoid build-system
150// churn; platform resource resolution lives in hpm_i2c_platform.hpp.
151#if LIBXR_HPM_I2C_HAS_DMA_MGR
152static_assert(sizeof(uintptr_t) <= sizeof(uint32_t),
153 "HPM I2C DMA helper assumes a 32-bit address space.");
154
155uint32_t ToHpmI2cDmaAddress(const volatile void* addr)
156{
157 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr));
158}
159
160#if defined(HPM_I2C7)
161constexpr size_t kHpmI2cInstanceCount = 8U;
162#elif defined(HPM_I2C6)
163constexpr size_t kHpmI2cInstanceCount = 7U;
164#elif defined(HPM_I2C5)
165constexpr size_t kHpmI2cInstanceCount = 6U;
166#elif defined(HPM_I2C4)
167constexpr size_t kHpmI2cInstanceCount = 5U;
168#else
169constexpr size_t kHpmI2cInstanceCount = 4U;
170#endif
171HPMI2C* g_hpm_i2c_instance_map[kHpmI2cInstanceCount] = {};
172
173using HPMI2CPlatform::kInvalidDmaSource;
174using HPMI2CPlatform::ResolveBoardI2cDmaSource;
175using HPMI2CPlatform::ResolveBoardI2cIrq;
176using HPMI2CPlatform::ResolveI2cIndex;
177#endif
178
179#if LIBXR_HPM_I2C_HAS_DMA_MGR
180#if LIBXR_HPM_I2C_HAS_L1C
181static bool ResolveDCacheRange(const void* addr, uint32_t size, uint32_t& start,
182 uint32_t& aligned_size)
183{
184 if (addr == nullptr || size == 0U)
185 {
186 start = 0U;
187 aligned_size = 0U;
188 return false;
189 }
190
191 const uint64_t line_size = HPM_L1C_CACHELINE_SIZE;
192 const uint64_t address = ToHpmI2cDmaAddress(addr);
193 const uint64_t end = address + static_cast<uint64_t>(size);
194 constexpr uint64_t kAddressSpaceSize = static_cast<uint64_t>(UINT32_MAX) + 1ULL;
195 if (end > kAddressSpaceSize)
196 {
197 start = 0U;
198 aligned_size = 0U;
199 return false;
200 }
201
202 const uint64_t aligned_start = address - (address % line_size);
203 const uint64_t aligned_end = ((end + line_size - 1U) / line_size) * line_size;
204 const uint64_t range_size = aligned_end - aligned_start;
205 if (aligned_end > kAddressSpaceSize || range_size > UINT32_MAX)
206 {
207 start = 0U;
208 aligned_size = 0U;
209 return false;
210 }
211
212 start = static_cast<uint32_t>(aligned_start);
213 aligned_size = static_cast<uint32_t>(range_size);
214 return aligned_size > 0U;
215}
216#endif
217
218static void FlushDCacheIfNeeded(const void* addr, uint32_t size)
219{
220#if LIBXR_HPM_I2C_HAS_L1C
221 if (addr != nullptr && size > 0U && l1c_dc_is_enabled())
222 {
223 uint32_t start = 0U;
224 uint32_t aligned_size = 0U;
225 if (ResolveDCacheRange(addr, size, start, aligned_size))
226 {
227 l1c_dc_flush(start, aligned_size);
228 }
229 }
230#else
231 UNUSED(addr);
232 UNUSED(size);
233#endif
234}
235#endif
236
237#if LIBXR_HPM_I2C_HAS_DMA_MGR
238static void InvalidateDCacheIfNeeded(const void* addr, uint32_t size)
239{
240#if LIBXR_HPM_I2C_HAS_L1C
241 if (addr != nullptr && size > 0U && l1c_dc_is_enabled())
242 {
243 uint32_t start = 0U;
244 uint32_t aligned_size = 0U;
245 if (ResolveDCacheRange(addr, size, start, aligned_size))
246 {
247 l1c_dc_invalidate(start, aligned_size);
248 }
249 }
250#else
251 UNUSED(addr);
252 UNUSED(size);
253#endif
254}
255#endif
256
257void I2cWaitRelax()
258{
259#if LIBXR_HPM_I2C_HAS_WAIT_RELAX_HOOK
260 if (libxr_hpm_i2c_wait_relax_hook != nullptr)
261 {
262 libxr_hpm_i2c_wait_relax_hook();
263 return;
264 }
265#endif
266 __asm volatile("nop");
267}
268
269uint32_t GetI2cWaitTicksPerUs()
270{
271 static uint32_t ticks_per_us = 0U;
272 if (ticks_per_us == 0U)
273 {
274 ticks_per_us = clock_get_core_clock_ticks_per_us();
275 }
276 return ticks_per_us;
277}
278
279uint64_t GetI2cWaitTimeoutTicks(uint64_t timeout_us)
280{
281 const uint64_t ticks_per_us = GetI2cWaitTicksPerUs();
282 if (ticks_per_us != 0U && timeout_us > (UINT64_MAX / ticks_per_us))
283 {
284 return UINT64_MAX;
285 }
286 return ticks_per_us * timeout_us;
287}
288
289uint64_t GetI2cWaitCycle() { return hpm_csr_get_core_cycle(); }
290
291template <typename Predicate>
292bool WaitUntil(const Predicate& predicate, uint64_t timeout_us)
293{
294 const uint64_t start = GetI2cWaitCycle();
295 const uint64_t timeout_ticks = GetI2cWaitTimeoutTicks(timeout_us);
296 while (!predicate())
297 {
298 if ((GetI2cWaitCycle() - start) > timeout_ticks)
299 {
300 return false;
301 }
302 I2cWaitRelax();
303 }
304 return true;
305}
306
307bool WaitForBusIdle(I2C_Type* i2c, uint64_t timeout_us)
308{
309 return WaitUntil([i2c]()
310 { return (i2c_get_status(i2c) & I2C_STATUS_BUSBUSY_MASK) == 0U; },
311 timeout_us);
312}
313
314void IssueStopAndWait(I2C_Type* i2c, const HPMI2C::WaitPolicy& policy)
315{
316 if (i2c == nullptr)
317 {
318 return;
319 }
320
321 i2c_clear_status(i2c, I2C_STATUS_CMPL_MASK);
322 i2c->CTRL = I2C_CTRL_PHASE_STOP_MASK;
323 i2c_master_issue_data_transmission(i2c);
324 (void)WaitUntil(
325 [i2c]()
326 {
327 const uint32_t status = i2c_get_status(i2c);
328 return ((status & I2C_STATUS_CMPL_MASK) != 0U) ||
329 ((status & I2C_STATUS_BUSBUSY_MASK) == 0U);
330 },
331 policy.stop_timeout_us);
332 i2c_clear_status(
333 i2c, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_BYTETRANS_MASK);
334 i2c_clear_fifo(i2c);
335}
336
337hpm_stat_t DoManualTransferWithFlagsImpl(I2C_Type* i2c, uint16_t slave_addr, RawData data,
338 uint16_t flags, const HPMI2C::WaitPolicy& policy)
339{
340 if (i2c == nullptr || data.addr_ == nullptr || data.size_ == 0U)
341 {
342 return status_invalid_argument;
343 }
344
345 i2c_enable_10bit_address_mode(i2c, (flags & I2C_ADDR_10BIT) != 0U);
346 i2c_clear_status(
347 i2c, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_BYTETRANS_MASK);
348 i2c_clear_fifo(i2c);
349 i2c_master_set_slave_address(i2c, slave_addr);
350
351 if ((flags & I2C_RD) != 0U)
352 {
353 i2c_set_direction(i2c, I2C_DIR_MASTER_READ);
354 }
355 else
356 {
357 i2c_set_direction(i2c, I2C_DIR_MASTER_WRITE);
358 }
359
360 if ((flags & I2C_NO_START) != 0U)
361 {
362 i2c_master_disable_start_phase(i2c);
363 }
364 else
365 {
366 i2c_master_enable_start_phase(i2c);
367 }
368
369 if ((flags & I2C_NO_ADDRESS) != 0U)
370 {
371 i2c_master_disable_addr_phase(i2c);
372 }
373 else
374 {
375 i2c_master_enable_addr_phase(i2c);
376 }
377
378 if ((flags & I2C_NO_STOP) != 0U)
379 {
380 i2c_master_disable_stop_phase(i2c);
381 }
382 else
383 {
384 i2c_master_enable_stop_phase(i2c);
385 }
386
387 i2c_master_enable_data_phase(i2c);
388 i2c_set_data_count(i2c, static_cast<uint32_t>(data.size_));
389 const uint32_t saved_inten = i2c->INTEN;
390 i2c->INTEN = saved_inten | I2C_EVENT_BYTE_RECEIVED;
391 i2c_master_issue_data_transmission(i2c);
392
393 hpm_stat_t raw_status = status_success;
394 auto* bytes = static_cast<uint8_t*>(data.addr_);
395 uint32_t left = static_cast<uint32_t>(data.size_);
396
397 if ((flags & I2C_NO_ADDRESS) == 0U)
398 {
399 const bool addr_hit = WaitUntil(
400 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_ADDRHIT_MASK) != 0U; },
401 policy.addr_hit_timeout_us);
402 if (!addr_hit)
403 {
404 raw_status = status_i2c_no_addr_hit;
405 }
406 else
407 {
408 i2c_clear_status(i2c, I2C_STATUS_ADDRHIT_MASK);
409 }
410 }
411
412 if (raw_status == status_success && (flags & I2C_RD) != 0U)
413 {
414 while (left > 0U)
415 {
416 const bool ready = WaitUntil(
417 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_FIFOEMPTY_MASK) == 0U; },
418 policy.transfer_timeout_us);
419 if (!ready)
420 {
421 raw_status = status_timeout;
422 break;
423 }
424
425 *(bytes++) = i2c_read_byte(i2c);
426 left--;
427 if (left == 0U)
428 {
429 i2c_respond_Nack(i2c);
430 }
431 else if ((flags & I2C_NO_READ_ACK) == 0U)
432 {
433 i2c_respond_ack(i2c);
434 }
435 }
436 }
437 else if (raw_status == status_success)
438 {
439 while (left > 0U)
440 {
441 if ((flags & I2C_WRITE_CHECK_ACK) != 0U)
442 {
443 i2c_write_byte(i2c, *(bytes++));
444 left--;
445
446 const bool ready = WaitUntil(
447 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_BYTETRANS_MASK) != 0U; },
448 policy.transfer_timeout_us);
449 if (!ready)
450 {
451 raw_status = status_timeout;
452 break;
453 }
454
455 const uint32_t status = i2c_get_status(i2c);
456 i2c_clear_status(i2c, I2C_STATUS_BYTETRANS_MASK);
457 if (!I2C_STATUS_ACK_GET(status))
458 {
459 raw_status = status_i2c_no_ack;
460 break;
461 }
462 }
463 else
464 {
465 const bool ready = WaitUntil(
466 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_FIFOFULL_MASK) == 0U; },
467 policy.transfer_timeout_us);
468 if (!ready)
469 {
470 raw_status = status_timeout;
471 break;
472 }
473
474 i2c_write_byte(i2c, *(bytes++));
475 left--;
476 }
477 }
478 }
479
480 if (raw_status == status_success)
481 {
482 const bool complete =
483 WaitUntil([i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_CMPL_MASK) != 0U; },
484 policy.transfer_timeout_us);
485 if (!complete)
486 {
487 raw_status = status_timeout;
488 }
489 else
490 {
491 i2c_clear_status(i2c, I2C_STATUS_CMPL_MASK);
492 if (i2c_get_data_count(i2c) != 0U)
493 {
494 raw_status = status_i2c_transmit_not_completed;
495 }
496 }
497 }
498
499 if (raw_status != status_success)
500 {
501 IssueStopAndWait(i2c, policy);
502 i2c_clear_status(
503 i2c, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_BYTETRANS_MASK);
504 i2c_master_disable_data_phase(i2c);
505 i2c_master_disable_addr_phase(i2c);
506 i2c_master_disable_start_phase(i2c);
507 i2c_master_disable_stop_phase(i2c);
508 }
509
510 i2c->INTEN = saved_inten;
511 return raw_status;
512}
513
514} // namespace
515
516#if LIBXR_HPM_I2C_HAS_DMA_MGR && LIBXR_HPM_I2C_HAS_INTERRUPT
517extern "C" void libxr_hpm_i2c_process_interrupt(I2C_Type* ptr)
518{
519 const int32_t index = ResolveI2cIndex(ptr);
520 if (index >= 0 && static_cast<size_t>(index) < kHpmI2cInstanceCount &&
521 g_hpm_i2c_instance_map[index] != nullptr)
522 {
523 g_hpm_i2c_instance_map[index]->HandleAsyncInterrupt(true);
524 }
525}
526
527#if defined(IRQn_I2C0) && defined(HPM_I2C0)
528SDK_DECLARE_EXT_ISR_M(IRQn_I2C0, libxr_hpm_i2c0_isr)
529void libxr_hpm_i2c0_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C0); }
530#endif
531#if defined(IRQn_I2C1) && defined(HPM_I2C1)
532SDK_DECLARE_EXT_ISR_M(IRQn_I2C1, libxr_hpm_i2c1_isr)
533void libxr_hpm_i2c1_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C1); }
534#endif
535#if defined(IRQn_I2C2) && defined(HPM_I2C2)
536SDK_DECLARE_EXT_ISR_M(IRQn_I2C2, libxr_hpm_i2c2_isr)
537void libxr_hpm_i2c2_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C2); }
538#endif
539#if defined(IRQn_I2C3) && defined(HPM_I2C3)
540SDK_DECLARE_EXT_ISR_M(IRQn_I2C3, libxr_hpm_i2c3_isr)
541void libxr_hpm_i2c3_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C3); }
542#endif
543#if defined(IRQn_I2C4) && defined(HPM_I2C4)
544SDK_DECLARE_EXT_ISR_M(IRQn_I2C4, libxr_hpm_i2c4_isr)
545void libxr_hpm_i2c4_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C4); }
546#endif
547#if defined(IRQn_I2C5) && defined(HPM_I2C5)
548SDK_DECLARE_EXT_ISR_M(IRQn_I2C5, libxr_hpm_i2c5_isr)
549void libxr_hpm_i2c5_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C5); }
550#endif
551#if defined(IRQn_I2C6) && defined(HPM_I2C6)
552SDK_DECLARE_EXT_ISR_M(IRQn_I2C6, libxr_hpm_i2c6_isr)
553void libxr_hpm_i2c6_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C6); }
554#endif
555#if defined(IRQn_I2C7) && defined(HPM_I2C7)
556SDK_DECLARE_EXT_ISR_M(IRQn_I2C7, libxr_hpm_i2c7_isr)
557void libxr_hpm_i2c7_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C7); }
558#endif
559#else
560extern "C" void libxr_hpm_i2c_process_interrupt(I2C_Type* ptr) { UNUSED(ptr); }
561#endif
562
563HPMI2C::HPMI2C(I2C_Type* i2c, clock_name_t clock, bool auto_board_init,
564 I2C::Configuration config)
565 : i2c_(i2c), clock_(clock), current_config_(config), auto_board_init_(auto_board_init)
566{
567 ASSERT(i2c_ != nullptr);
568
569#if LIBXR_HPM_I2C_HAS_BOARD_HELPER
571 {
572 source_clock_hz_ = board_init_i2c_clock(i2c_);
573 init_i2c_pins(i2c_);
575 }
576#else
577 (void)auto_board_init_;
578#endif
579
580 if (source_clock_hz_ == 0)
581 {
582 clock_add_to_group(clock_, 0);
583 source_clock_hz_ = clock_get_frequency(clock_);
584 }
585
586 ASSERT(source_clock_hz_ != 0);
587 const ErrorCode ans = SetConfig(config);
588 ASSERT(ans == ErrorCode::OK);
589}
590
591ErrorCode HPMI2C::SetAddressMode(AddressMode mode)
592{
593 if (i2c_ == nullptr)
594 {
595 return ErrorCode::PTR_NULL;
596 }
597
598 if (address_mode_ == mode && configured_)
599 {
600 return ErrorCode::OK;
601 }
602
603#if LIBXR_HPM_I2C_HAS_DMA_MGR
604 if (AsyncTransferActive())
605 {
606 return ErrorCode::BUSY;
607 }
608 DisableAsyncI2cIrq();
609 StopAsyncDma();
610#endif
611 IssueStopAndWait(i2c_, wait_policy_);
612 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
613
614 const AddressMode previous_mode = address_mode_;
615 address_mode_ = mode;
617 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
618 if (ans != ErrorCode::OK)
619 {
620 address_mode_ = previous_mode;
621 if (configured_)
622 {
624 }
625 }
626 return ans;
627}
628
629ErrorCode HPMI2C::ConvertStatus(hpm_stat_t status)
630{
631 switch (status)
632 {
633 case status_success:
634 return ErrorCode::OK;
635 case status_timeout:
636 return ErrorCode::TIMEOUT;
637 case status_invalid_argument:
638 return ErrorCode::ARG_ERR;
639 case status_i2c_bus_busy:
640 return ErrorCode::BUSY;
641 case status_i2c_not_supported:
643 case status_i2c_no_ack:
644 case status_i2c_no_addr_hit:
646 case status_i2c_invalid_data:
648 case status_i2c_transmit_not_completed:
649 return ErrorCode::FAILED;
650 default:
651 return ErrorCode::FAILED;
652 }
653}
654
655ErrorCode HPMI2C::ResolveMode(uint32_t clock_speed, i2c_mode_t& mode)
656{
657 if (clock_speed == 100000UL)
658 {
659 mode = i2c_mode_normal;
660 }
661 else if (clock_speed == 400000UL)
662 {
663 mode = i2c_mode_fast;
664 }
665 else if (clock_speed == 1000000UL)
666 {
667 mode = i2c_mode_fast_plus;
668 }
669 else if (clock_speed == 0)
670 {
671 return ErrorCode::ARG_ERR;
672 }
673 else
674 {
676 }
677
678 return ErrorCode::OK;
679}
680
681#if LIBXR_HPM_I2C_HAS_DMA_MGR
682ErrorCode HPMI2C::ConvertDmaStatus(hpm_stat_t status)
683{
684 switch (status)
685 {
686 case status_success:
687 return ErrorCode::OK;
688 case status_invalid_argument:
689 return ErrorCode::ARG_ERR;
690 case status_dma_mgr_no_resource:
691 return ErrorCode::FULL;
692 default:
693 return ErrorCode::FAILED;
694 }
695}
696#endif
697
698i2c_seq_transfer_opt_t HPMI2C::ConvertSequenceFrame(SequenceFrame frame)
699{
700 switch (frame)
701 {
703 return i2c_frist_frame;
705 return i2c_next_frame;
707 default:
708 return i2c_last_frame;
709 }
710}
711
712uint16_t HPMI2C::BuildTransferFlags(uint16_t flags) const
713{
714 return (address_mode_ == AddressMode::ADDR_10BIT) ? (flags | kI2CFlagAddr10Bit) : flags;
715}
716
718{
719 if (i2c_ == nullptr)
720 {
721 return ErrorCode::PTR_NULL;
722 }
723
724 if (source_clock_hz_ != 0)
725 {
726 return ErrorCode::OK;
727 }
728
729 clock_add_to_group(clock_, 0);
730 source_clock_hz_ = clock_get_frequency(clock_);
731 if (source_clock_hz_ == 0)
732 {
733 return ErrorCode::INIT_ERR;
734 }
735
736 return ErrorCode::OK;
737}
738
740{
741 if (i2c_ == nullptr)
742 {
743 return ErrorCode::PTR_NULL;
744 }
745
746 if (configured_)
747 {
748 return ErrorCode::OK;
749 }
750
752}
753
754ErrorCode HPMI2C::ApplyConfig(const Configuration& config)
755{
756 if (i2c_ == nullptr)
757 {
758 return ErrorCode::PTR_NULL;
759 }
760
761 i2c_mode_t mode = i2c_mode_normal;
762 ErrorCode ans = ResolveMode(config.clock_speed, mode);
763 if (ans != ErrorCode::OK)
764 {
765 return ans;
766 }
767
768 ans = EnsureClockReady();
769 if (ans != ErrorCode::OK)
770 {
771 return ans;
772 }
773
774 i2c_config_t i2c_config{};
775 i2c_config.i2c_mode = mode;
776 i2c_config.is_10bit_addressing = (address_mode_ == AddressMode::ADDR_10BIT);
777
778 ans = ConvertStatus(i2c_init_master(i2c_, source_clock_hz_, &i2c_config));
779 if (ans == ErrorCode::OK)
780 {
781 current_config_ = config;
782 configured_ = true;
783 }
784
785 return ans;
786}
787
788bool HPMI2C::ShouldRecover(hpm_stat_t status)
789{
790 switch (status)
791 {
792 case status_timeout:
793 case status_i2c_bus_busy:
794 case status_i2c_no_ack:
795 case status_i2c_no_addr_hit:
796 return true;
797 default:
798 return false;
799 }
800}
801
803{
804 if (i2c_ == nullptr)
805 {
806 return;
807 }
808
809 IssueStopAndWait(i2c_, wait_policy_);
810 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
812 i2c_reset(i2c_);
813 if (configured_)
814 {
816 }
817 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
818}
819
821{
822 if (i2c_ == nullptr)
823 {
824 return;
825 }
826
827#if LIBXR_HPM_I2C_HAS_BOARD_HELPER
829 {
830 if (i2c_get_line_scl_status(i2c_) && !i2c_get_line_sda_status(i2c_))
831 {
832 board_i2c_bus_clear(i2c_);
833 }
834 return;
835 }
836#endif
837
838#if defined(HPM_IP_FEATURE_I2C_SUPPORT_RESET) && (HPM_IP_FEATURE_I2C_SUPPORT_RESET == 1)
839 if (i2c_get_line_scl_status(i2c_) && !i2c_get_line_sda_status(i2c_))
840 {
841 i2c_gen_reset_signal(i2c_, 9);
842 }
843#endif
844}
845
846#if LIBXR_HPM_I2C_HAS_DMA_MGR
847uint32_t HPMI2C::ToSystemAddress(const void* addr)
848{
849 return core_local_mem_to_sys_address(HPM_CORE0, ToHpmI2cDmaAddress(addr));
850}
851
852ErrorCode HPMI2C::PrepareAsyncTransfer(uint16_t slave_addr, uint16_t flags, uint32_t size,
853 bool clear_fifo, bool require_bus_idle)
854{
855 if (i2c_ == nullptr)
856 {
857 return ErrorCode::PTR_NULL;
858 }
859
860 if (require_bus_idle)
861 {
862 if (!WaitForBusIdle(i2c_, wait_policy_.transfer_timeout_us))
863 {
864 return ErrorCode::BUSY;
865 }
866 }
867
868 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK);
869 if (clear_fifo)
870 {
871 i2c_clear_fifo(i2c_);
872 }
873
874 const uint16_t final_flags = BuildTransferFlags(flags);
875 i2c_master_set_slave_address(i2c_, slave_addr);
876 if ((final_flags & I2C_RD) != 0U)
877 {
878 i2c_set_direction(i2c_, I2C_DIR_MASTER_READ);
879 }
880 else
881 {
882 i2c_set_direction(i2c_, I2C_DIR_MASTER_WRITE);
883 }
884
885 if ((final_flags & I2C_NO_START) != 0U)
886 {
887 i2c_master_disable_start_phase(i2c_);
888 }
889 else
890 {
891 i2c_master_enable_start_phase(i2c_);
892 }
893
894 if ((final_flags & I2C_NO_ADDRESS) != 0U)
895 {
896 i2c_master_disable_addr_phase(i2c_);
897 }
898 else
899 {
900 i2c_master_enable_addr_phase(i2c_);
901 }
902
903 if ((final_flags & I2C_NO_STOP) != 0U)
904 {
905 i2c_master_disable_stop_phase(i2c_);
906 }
907 else
908 {
909 i2c_master_enable_stop_phase(i2c_);
910 }
911
912 if (size > 0U)
913 {
914 i2c_master_enable_data_phase(i2c_);
915 i2c_set_data_count(i2c_, size);
916 }
917 else
918 {
919 i2c_master_disable_data_phase(i2c_);
920 }
921
922 i2c_dma_disable(i2c_);
923 i2c_master_issue_data_transmission(i2c_);
924
925 if ((final_flags & I2C_NO_ADDRESS) == 0U)
926 {
927 const bool addr_hit = WaitUntil(
928 [this]() { return (i2c_get_status(i2c_) & I2C_STATUS_ADDRHIT_MASK) != 0U; },
929 wait_policy_.addr_hit_timeout_us);
930 if (!addr_hit)
931 {
932 StopAndReleaseAsyncBus();
934 }
935 i2c_clear_status(i2c_, I2C_STATUS_ADDRHIT_MASK);
936 }
937
938 return ErrorCode::OK;
939}
940
941ErrorCode HPMI2C::StartAsyncReadDma(void* dst, uint32_t size)
942{
943 if (i2c_ == nullptr || dst == nullptr || size == 0U)
944 {
945 return ErrorCode::ARG_ERR;
946 }
947 ErrorCode ans = EnsureAsyncDmaReady();
948 if (ans != ErrorCode::OK)
949 {
950 return ans;
951 }
952
953 FlushDCacheIfNeeded(dst, size);
954
955 hpm_stat_t status =
956 dma_mgr_set_chn_dst_addr(&async_dma_resource_, ToSystemAddress(dst));
957 if (status != status_success)
958 {
959 return ConvertDmaStatus(status);
960 }
961 status =
962 dma_mgr_set_chn_dst_work_mode(&async_dma_resource_, DMA_MGR_HANDSHAKE_MODE_NORMAL);
963 if (status != status_success)
964 {
965 return ConvertDmaStatus(status);
966 }
967 status = dma_mgr_set_chn_dst_addr_ctrl(&async_dma_resource_,
968 DMA_MGR_ADDRESS_CONTROL_INCREMENT);
969 if (status != status_success)
970 {
971 return ConvertDmaStatus(status);
972 }
973 status =
974 dma_mgr_set_chn_src_addr(&async_dma_resource_, ToHpmI2cDmaAddress(&i2c_->DATA));
975 if (status != status_success)
976 {
977 return ConvertDmaStatus(status);
978 }
979 status = dma_mgr_set_chn_src_work_mode(&async_dma_resource_,
980 DMA_MGR_HANDSHAKE_MODE_HANDSHAKE);
981 if (status != status_success)
982 {
983 return ConvertDmaStatus(status);
984 }
985 status =
986 dma_mgr_set_chn_src_addr_ctrl(&async_dma_resource_, DMA_MGR_ADDRESS_CONTROL_FIXED);
987 if (status != status_success)
988 {
989 return ConvertDmaStatus(status);
990 }
991 status = dma_mgr_set_chn_src_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
992 if (status != status_success)
993 {
994 return ConvertDmaStatus(status);
995 }
996 status = dma_mgr_set_chn_dst_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
997 if (status != status_success)
998 {
999 return ConvertDmaStatus(status);
1000 }
1001 status = dma_mgr_set_chn_transize(&async_dma_resource_, size);
1002 if (status != status_success)
1003 {
1004 return ConvertDmaStatus(status);
1005 }
1006
1007 i2c_dma_enable(i2c_);
1008 dma_clear_transfer_status(async_dma_resource_.base, async_dma_resource_.channel);
1009 status = dma_mgr_enable_channel(&async_dma_resource_);
1010 if (status != status_success)
1011 {
1012 i2c_dma_disable(i2c_);
1013 return ConvertDmaStatus(status);
1014 }
1015 return ErrorCode::OK;
1016}
1017
1018ErrorCode HPMI2C::StartAsyncWriteDma(const void* src, uint32_t size)
1019{
1020 if (i2c_ == nullptr || src == nullptr || size == 0U)
1021 {
1022 return ErrorCode::ARG_ERR;
1023 }
1024 ErrorCode ans = EnsureAsyncDmaReady();
1025 if (ans != ErrorCode::OK)
1026 {
1027 return ans;
1028 }
1029
1030 FlushDCacheIfNeeded(src, size);
1031
1032 hpm_stat_t status =
1033 dma_mgr_set_chn_src_addr(&async_dma_resource_, ToSystemAddress(src));
1034 if (status != status_success)
1035 {
1036 return ConvertDmaStatus(status);
1037 }
1038 status =
1039 dma_mgr_set_chn_src_work_mode(&async_dma_resource_, DMA_MGR_HANDSHAKE_MODE_NORMAL);
1040 if (status != status_success)
1041 {
1042 return ConvertDmaStatus(status);
1043 }
1044 status = dma_mgr_set_chn_src_addr_ctrl(&async_dma_resource_,
1045 DMA_MGR_ADDRESS_CONTROL_INCREMENT);
1046 if (status != status_success)
1047 {
1048 return ConvertDmaStatus(status);
1049 }
1050 status =
1051 dma_mgr_set_chn_dst_addr(&async_dma_resource_, ToHpmI2cDmaAddress(&i2c_->DATA));
1052 if (status != status_success)
1053 {
1054 return ConvertDmaStatus(status);
1055 }
1056 status = dma_mgr_set_chn_dst_work_mode(&async_dma_resource_,
1057 DMA_MGR_HANDSHAKE_MODE_HANDSHAKE);
1058 if (status != status_success)
1059 {
1060 return ConvertDmaStatus(status);
1061 }
1062 status =
1063 dma_mgr_set_chn_dst_addr_ctrl(&async_dma_resource_, DMA_MGR_ADDRESS_CONTROL_FIXED);
1064 if (status != status_success)
1065 {
1066 return ConvertDmaStatus(status);
1067 }
1068 status = dma_mgr_set_chn_src_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
1069 if (status != status_success)
1070 {
1071 return ConvertDmaStatus(status);
1072 }
1073 status = dma_mgr_set_chn_dst_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
1074 if (status != status_success)
1075 {
1076 return ConvertDmaStatus(status);
1077 }
1078 status = dma_mgr_set_chn_transize(&async_dma_resource_, size);
1079 if (status != status_success)
1080 {
1081 return ConvertDmaStatus(status);
1082 }
1083
1084 i2c_dma_enable(i2c_);
1085 dma_clear_transfer_status(async_dma_resource_.base, async_dma_resource_.channel);
1086 status = dma_mgr_enable_channel(&async_dma_resource_);
1087 if (status != status_success)
1088 {
1089 i2c_dma_disable(i2c_);
1090 return ConvertDmaStatus(status);
1091 }
1092 return ErrorCode::OK;
1093}
1094
1095void HPMI2C::StopAsyncDma()
1096{
1097 if (async_dma_ready_)
1098 {
1099 (void)dma_mgr_disable_channel(&async_dma_resource_);
1100 }
1101 if (i2c_ != nullptr)
1102 {
1103 i2c_dma_disable(i2c_);
1104 }
1105}
1106
1107void HPMI2C::StopAndReleaseAsyncBus()
1108{
1109 IssueStopAndWait(i2c_, wait_policy_);
1110 ReleaseAsyncBus();
1111}
1112
1113void HPMI2C::AsyncCompletionStateMachine::Reset(AsyncTransferContext& ctx)
1114{
1115 ctx.final_status.store(status_success, std::memory_order_release);
1116 ctx.should_recover.store(false, std::memory_order_release);
1117 ctx.dma_done.store(false, std::memory_order_release);
1118 ctx.cmpl_done.store(false, std::memory_order_release);
1119}
1120
1121void HPMI2C::AsyncCompletionStateMachine::MarkDmaDone(AsyncTransferContext& ctx)
1122{
1123 ctx.dma_done.store(true, std::memory_order_release);
1124}
1125
1126void HPMI2C::AsyncCompletionStateMachine::MarkI2cDone(AsyncTransferContext& ctx,
1127 hpm_stat_t status, bool recover)
1128{
1129 ctx.cmpl_done.store(true, std::memory_order_release);
1130 ctx.final_status.store(status, std::memory_order_release);
1131 ctx.should_recover.store(recover, std::memory_order_release);
1132}
1133
1134void HPMI2C::AsyncCompletionStateMachine::MarkFailure(AsyncTransferContext& ctx,
1135 hpm_stat_t status, bool recover)
1136{
1137 ctx.final_status.store(status, std::memory_order_release);
1138 ctx.should_recover.store(recover, std::memory_order_release);
1139}
1140
1141void HPMI2C::AsyncCompletionStateMachine::SetFinalStatus(AsyncTransferContext& ctx,
1142 hpm_stat_t status)
1143{
1144 ctx.final_status.store(status, std::memory_order_release);
1145}
1146
1147bool HPMI2C::AsyncCompletionStateMachine::DmaDone(const AsyncTransferContext& ctx)
1148{
1149 return ctx.dma_done.load(std::memory_order_acquire);
1150}
1151
1152bool HPMI2C::AsyncCompletionStateMachine::Ready(const AsyncTransferContext& ctx)
1153{
1154 return DmaDone(ctx) && ctx.cmpl_done.load(std::memory_order_acquire);
1155}
1156
1157hpm_stat_t HPMI2C::AsyncCompletionStateMachine::FinalStatus(
1158 const AsyncTransferContext& ctx)
1159{
1160 return ctx.final_status.load(std::memory_order_acquire);
1161}
1162
1163bool HPMI2C::AsyncCompletionStateMachine::ShouldRecover(const AsyncTransferContext& ctx)
1164{
1165 return ctx.should_recover.load(std::memory_order_acquire);
1166}
1167
1168void HPMI2C::ClearAsyncContext()
1169{
1170 async_ctx_.kind = AsyncTransferKind::NONE;
1171 async_ctx_.slave_addr = 0U;
1172 async_ctx_.mem_addr_size = MemAddrLength::BYTE_8;
1173 async_ctx_.mem_addr = 0U;
1174 async_ctx_.mem_addr_size_in_byte = 0U;
1175 async_ctx_.mem_addr_bytes[0] = 0U;
1176 async_ctx_.mem_addr_bytes[1] = 0U;
1177 async_ctx_.flags = 0U;
1178 async_ctx_.read_data = {nullptr, 0};
1179 async_ctx_.write_data = {nullptr, 0};
1180 async_ctx_.read_op = {};
1181 async_ctx_.write_op = {};
1182 AsyncCompletionStateMachine::Reset(async_ctx_);
1183}
1184
1185void HPMI2C::ResetAsyncState()
1186{
1187 ClearAsyncContext();
1188 async_busy_.store(0U, std::memory_order_release);
1189 async_completion_claim_.store(0U, std::memory_order_release);
1190}
1191
1192void HPMI2C::AbortAsyncStart(bool stop_dma, bool disable_irq, bool recover_controller)
1193{
1194 if (stop_dma)
1195 {
1196 StopAsyncDma();
1197 }
1198 if (disable_irq)
1199 {
1200 DisableAsyncI2cIrq();
1201 }
1202
1203 if (recover_controller)
1204 {
1206 }
1207 else
1208 {
1209 ReleaseAsyncBus();
1210 }
1211
1212 ResetAsyncState();
1213}
1214
1215void HPMI2C::CompleteAsyncTransfer(bool in_isr, ErrorCode ans)
1216{
1217 if (!TryClaimAsyncCompletion())
1218 {
1219 return;
1220 }
1221 DisableAsyncI2cIrq();
1222 StopAsyncDma();
1223 ReleaseAsyncBus();
1224
1225 const bool should_recover = AsyncCompletionStateMachine::ShouldRecover(async_ctx_);
1226 if (ans != ErrorCode::OK && should_recover)
1227 {
1229 }
1230
1231 const AsyncTransferKind kind = async_ctx_.kind;
1232 ReadOperation read_op = async_ctx_.read_op;
1233 WriteOperation write_op = async_ctx_.write_op;
1234 async_ctx_.kind = AsyncTransferKind::NONE;
1235 ResetAsyncState();
1236
1237 if (kind == AsyncTransferKind::WRITE)
1238 {
1239 CompleteAsyncOperation(write_op, in_isr, ans);
1240 }
1241 else
1242 {
1243 CompleteAsyncOperation(read_op, in_isr, ans);
1244 }
1245}
1246
1247ErrorCode HPMI2C::StartWriteAsync(uint16_t slave_addr, ConstRawData write_data,
1248 WriteOperation& op)
1249{
1250 if (AsyncTransferActive())
1251 {
1252 return ErrorCode::BUSY;
1253 }
1254
1256 if (ans != ErrorCode::OK)
1257 {
1258 return ans;
1259 }
1260
1261 async_busy_.store(1U, std::memory_order_release);
1262 ClearAsyncContext();
1263 async_ctx_.kind = AsyncTransferKind::WRITE;
1264 async_ctx_.slave_addr = slave_addr;
1265 async_ctx_.write_data = write_data;
1266 async_ctx_.write_op = op;
1267 async_ctx_.flags = BuildTransferFlags(kI2CFlagWriteCheckAck);
1268 async_completion_claim_.store(0U, std::memory_order_release);
1269
1270 StartAsyncBlockWaitIfNeeded(op);
1271
1272 ans = EnableAsyncI2cIrq();
1273 if (ans != ErrorCode::OK)
1274 {
1275 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1276 AbortAsyncStart(false, false, false);
1277 CancelAsyncBlockWaitIfNeeded(op);
1279 }
1280
1281 i2c_clear_fifo(i2c_);
1282 ans = StartAsyncWriteDma(write_data.addr_, static_cast<uint32_t>(write_data.size_));
1283 if (ans != ErrorCode::OK)
1284 {
1285 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1286 AbortAsyncStart(false, true, false);
1287 CancelAsyncBlockWaitIfNeeded(op);
1288 return ans;
1289 }
1290
1291 hpm_stat_t start_status = i2c_master_start_dma_write(
1292 i2c_, slave_addr, static_cast<uint32_t>(write_data.size_));
1293 ans = ConvertStatus(start_status);
1294 if (ans != ErrorCode::OK)
1295 {
1296 AsyncCompletionStateMachine::MarkFailure(async_ctx_, start_status,
1297 ShouldRecover(start_status));
1298 AbortAsyncStart(true, true, ShouldRecover(start_status));
1299 CancelAsyncBlockWaitIfNeeded(op);
1300 return ans;
1301 }
1302
1303 op.MarkAsRunning();
1304 if (op.type == WriteOperation::OperationType::BLOCK)
1305 {
1306 return WaitForAsyncBlockResult(op.data.sem_info.timeout);
1307 }
1308 return ErrorCode::OK;
1309}
1310
1311ErrorCode HPMI2C::StartReadAsync(uint16_t slave_addr, RawData read_data,
1312 ReadOperation& op)
1313{
1314 if (AsyncTransferActive())
1315 {
1316 return ErrorCode::BUSY;
1317 }
1318
1320 if (ans != ErrorCode::OK)
1321 {
1322 return ans;
1323 }
1324
1325 async_busy_.store(1U, std::memory_order_release);
1326 ClearAsyncContext();
1327 async_ctx_.kind = AsyncTransferKind::READ;
1328 async_ctx_.slave_addr = slave_addr;
1329 async_ctx_.read_data = read_data;
1330 async_ctx_.read_op = op;
1331 async_ctx_.flags = kI2CFlagRead;
1332 async_completion_claim_.store(0U, std::memory_order_release);
1333
1334 StartAsyncBlockWaitIfNeeded(op);
1335
1336 ans = EnableAsyncI2cIrq();
1337 if (ans != ErrorCode::OK)
1338 {
1339 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1340 AbortAsyncStart(false, false, false);
1341 CancelAsyncBlockWaitIfNeeded(op);
1343 }
1344
1345 i2c_clear_fifo(i2c_);
1346 ans = StartAsyncReadDma(read_data.addr_, static_cast<uint32_t>(read_data.size_));
1347 if (ans != ErrorCode::OK)
1348 {
1349 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1350 AbortAsyncStart(false, true, false);
1351 CancelAsyncBlockWaitIfNeeded(op);
1352 return ans;
1353 }
1354
1355 hpm_stat_t start_status =
1356 i2c_master_start_dma_read(i2c_, slave_addr, static_cast<uint32_t>(read_data.size_));
1357 ans = ConvertStatus(start_status);
1358 if (ans != ErrorCode::OK)
1359 {
1360 AsyncCompletionStateMachine::MarkFailure(async_ctx_, start_status,
1361 ShouldRecover(start_status));
1362 AbortAsyncStart(true, true, ShouldRecover(start_status));
1363 CancelAsyncBlockWaitIfNeeded(op);
1364 return ans;
1365 }
1366
1367 op.MarkAsRunning();
1368 if (op.type == ReadOperation::OperationType::BLOCK)
1369 {
1370 return WaitForAsyncBlockResult(op.data.sem_info.timeout);
1371 }
1372 return ErrorCode::OK;
1373}
1374
1375ErrorCode HPMI2C::StartMemReadAsync(uint16_t slave_addr, uint16_t mem_addr,
1376 RawData read_data, ReadOperation& op,
1377 MemAddrLength mem_addr_size)
1378{
1379 if (AsyncTransferActive())
1380 {
1381 return ErrorCode::BUSY;
1382 }
1383
1384 uint32_t addr_size = 0U;
1385 ErrorCode ans = ResolveMemAddressSize(mem_addr_size, addr_size);
1386 if (ans != ErrorCode::OK)
1387 {
1388 return ans;
1389 }
1390 if (addr_size > I2C_SOC_TRANSFER_COUNT_MAX)
1391 {
1392 return ErrorCode::SIZE_ERR;
1393 }
1394
1395 ans = EnsureControllerReady();
1396 if (ans != ErrorCode::OK)
1397 {
1398 return ans;
1399 }
1400
1401 async_busy_.store(1U, std::memory_order_release);
1402 ClearAsyncContext();
1403 async_ctx_.kind = AsyncTransferKind::MEM_READ;
1404 async_ctx_.slave_addr = slave_addr;
1405 async_ctx_.mem_addr = mem_addr;
1406 async_ctx_.mem_addr_size = mem_addr_size;
1407 async_ctx_.mem_addr_size_in_byte = addr_size;
1408 FillMemAddress(mem_addr, mem_addr_size, async_ctx_.mem_addr_bytes);
1409 async_ctx_.read_data = read_data;
1410 async_ctx_.read_op = op;
1411 async_ctx_.flags = kI2CFlagRead;
1412 async_completion_claim_.store(0U, std::memory_order_release);
1413
1414 StartAsyncBlockWaitIfNeeded(op);
1415
1416 ans = PrepareAsyncTransfer(slave_addr, kI2CFlagNoStop, async_ctx_.mem_addr_size_in_byte,
1417 true, true);
1418 if (ans != ErrorCode::OK)
1419 {
1420 ResetAsyncState();
1421 CancelAsyncBlockWaitIfNeeded(op);
1422 return ans;
1423 }
1424
1425 for (uint32_t i = 0U; i < async_ctx_.mem_addr_size_in_byte; ++i)
1426 {
1427 i2c_write_byte(i2c_, async_ctx_.mem_addr_bytes[i]);
1428 }
1429
1430 const bool mem_addr_complete =
1431 WaitUntil([this]() { return (i2c_get_status(i2c_) & I2C_STATUS_CMPL_MASK) != 0U; },
1432 wait_policy_.transfer_timeout_us);
1433 if (!mem_addr_complete)
1434 {
1435 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_timeout, true);
1436 StopAndReleaseAsyncBus();
1437 ResetAsyncState();
1438 CancelAsyncBlockWaitIfNeeded(op);
1439 return ErrorCode::TIMEOUT;
1440 }
1441 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK);
1442 i2c_clear_fifo(i2c_);
1443
1444 const uint16_t final_flags = BuildTransferFlags(kI2CFlagRead);
1445 i2c_master_set_slave_address(i2c_, slave_addr);
1446 i2c_set_direction(i2c_, I2C_DIR_MASTER_READ);
1447 i2c_master_enable_start_phase(i2c_);
1448 i2c_master_enable_addr_phase(i2c_);
1449 i2c_master_enable_stop_phase(i2c_);
1450 i2c_master_enable_data_phase(i2c_);
1451 i2c_set_data_count(i2c_, static_cast<uint32_t>(read_data.size_));
1452 i2c_dma_disable(i2c_);
1453 if ((final_flags & kI2CFlagAddr10Bit) != 0U)
1454 {
1455 i2c_enable_10bit_address_mode(i2c_, true);
1456 }
1457
1458 ans = EnableAsyncI2cIrq();
1459 if (ans != ErrorCode::OK)
1460 {
1461 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1462 StopAndReleaseAsyncBus();
1463 ResetAsyncState();
1464 CancelAsyncBlockWaitIfNeeded(op);
1466 }
1467
1468 ans = StartAsyncReadDma(read_data.addr_, static_cast<uint32_t>(read_data.size_));
1469 if (ans != ErrorCode::OK)
1470 {
1471 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1472 DisableAsyncI2cIrq();
1473 StopAndReleaseAsyncBus();
1474 ResetAsyncState();
1475 CancelAsyncBlockWaitIfNeeded(op);
1476 return ans;
1477 }
1478
1479 i2c_master_issue_data_transmission(i2c_);
1480 const bool addr_hit = WaitUntil(
1481 [this]() { return (i2c_get_status(i2c_) & I2C_STATUS_ADDRHIT_MASK) != 0U; },
1482 wait_policy_.addr_hit_timeout_us);
1483 if (!addr_hit)
1484 {
1485 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_i2c_no_addr_hit, true);
1486 AbortAsyncStart(true, true, true);
1487 CancelAsyncBlockWaitIfNeeded(op);
1489 }
1490 i2c_clear_status(i2c_, I2C_STATUS_ADDRHIT_MASK);
1491
1492 op.MarkAsRunning();
1493 if (op.type == ReadOperation::OperationType::BLOCK)
1494 {
1495 return WaitForAsyncBlockResult(op.data.sem_info.timeout);
1496 }
1497 return ErrorCode::OK;
1498}
1499
1500ErrorCode HPMI2C::EnsureAsyncDmaReady()
1501{
1502 if (async_dma_ready_)
1503 {
1504 return ErrorCode::OK;
1505 }
1506
1507 if (i2c_ == nullptr)
1508 {
1509 return ErrorCode::PTR_NULL;
1510 }
1511
1512 async_dma_source_ = ResolveBoardI2cDmaSource(i2c_);
1513 if (async_dma_source_ == kInvalidDmaSource)
1514 {
1516 }
1517
1518 dma_mgr_init();
1519#if defined(BOARD_APP_I2C_DMA)
1520 hpm_stat_t status =
1521 dma_mgr_request_specified_resource(&async_dma_resource_, BOARD_APP_I2C_DMA);
1522#else
1523 hpm_stat_t status = status_fail;
1524#endif
1525 if (status != status_success)
1526 {
1527 status = dma_mgr_request_resource(&async_dma_resource_);
1528 if (status != status_success)
1529 {
1530 return ConvertDmaStatus(status);
1531 }
1532 }
1533
1534 dma_mgr_chn_conf_t cfg{};
1535 dma_mgr_get_default_chn_config(&cfg);
1536 cfg.src_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
1537 cfg.dst_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
1538 cfg.en_dmamux = true;
1539 cfg.dmamux_src = async_dma_source_;
1540 cfg.interrupt_mask = DMA_MGR_INTERRUPT_MASK_ALL;
1541 status = dma_mgr_setup_channel(&async_dma_resource_, &cfg);
1542 if (status != status_success)
1543 {
1544 (void)dma_mgr_release_resource(&async_dma_resource_);
1545 async_dma_resource_ = {nullptr, 0U, -1};
1546 return ConvertDmaStatus(status);
1547 }
1548
1549 status = dma_mgr_install_chn_tc_callback(&async_dma_resource_, &HPMI2C::OnDmaTcCallback,
1550 this);
1551 if (status != status_success)
1552 {
1553 (void)dma_mgr_release_resource(&async_dma_resource_);
1554 async_dma_resource_ = {nullptr, 0U, -1};
1555 return ConvertDmaStatus(status);
1556 }
1557 status = dma_mgr_install_chn_error_callback(&async_dma_resource_,
1558 &HPMI2C::OnDmaErrorCallback, this);
1559 if (status != status_success)
1560 {
1561 (void)dma_mgr_release_resource(&async_dma_resource_);
1562 async_dma_resource_ = {nullptr, 0U, -1};
1563 return ConvertDmaStatus(status);
1564 }
1565 status = dma_mgr_install_chn_abort_callback(&async_dma_resource_,
1566 &HPMI2C::OnDmaAbortCallback, this);
1567 if (status != status_success)
1568 {
1569 (void)dma_mgr_release_resource(&async_dma_resource_);
1570 async_dma_resource_ = {nullptr, 0U, -1};
1571 return ConvertDmaStatus(status);
1572 }
1573 status = dma_mgr_enable_chn_irq(&async_dma_resource_, DMA_MGR_INTERRUPT_MASK_TC |
1574 DMA_MGR_INTERRUPT_MASK_ERROR |
1575 DMA_MGR_INTERRUPT_MASK_ABORT);
1576 if (status != status_success)
1577 {
1578 (void)dma_mgr_release_resource(&async_dma_resource_);
1579 async_dma_resource_ = {nullptr, 0U, -1};
1580 return ConvertDmaStatus(status);
1581 }
1582 status = dma_mgr_enable_dma_irq_with_priority(&async_dma_resource_, 1U);
1583 if (status != status_success)
1584 {
1585 (void)dma_mgr_release_resource(&async_dma_resource_);
1586 async_dma_resource_ = {nullptr, 0U, -1};
1587 return ConvertDmaStatus(status);
1588 }
1589
1590 async_dma_ready_ = true;
1591 return ErrorCode::OK;
1592}
1593
1594ErrorCode HPMI2C::WaitForAsyncBlockResult(uint32_t timeout)
1595{
1596 const ErrorCode ans = block_wait_.Wait(timeout);
1597 if (ans == ErrorCode::TIMEOUT && AsyncTransferActive())
1598 {
1599 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_timeout, true);
1600 CompleteAsyncTransfer(false, ErrorCode::TIMEOUT);
1601 }
1602 return ans;
1603}
1604
1605void HPMI2C::ReleaseAsyncBus()
1606{
1607 if (i2c_ == nullptr)
1608 {
1609 return;
1610 }
1611
1612 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK);
1613 i2c_master_disable_data_phase(i2c_);
1614 i2c_master_disable_addr_phase(i2c_);
1615 i2c_master_disable_start_phase(i2c_);
1616 i2c_master_disable_stop_phase(i2c_);
1617 i2c_master_issue_data_transmission(i2c_);
1618}
1619
1620ErrorCode HPMI2C::EnableAsyncI2cIrq()
1621{
1622#if !LIBXR_HPM_I2C_HAS_INTERRUPT
1624#else
1625 const int32_t irq = ResolveBoardI2cIrq(i2c_);
1626 const int32_t index = ResolveI2cIndex(i2c_);
1627 if (irq < 0 || index < 0 || static_cast<size_t>(index) >= kHpmI2cInstanceCount)
1628 {
1630 }
1631 if (g_hpm_i2c_instance_map[index] != nullptr && g_hpm_i2c_instance_map[index] != this)
1632 {
1634 }
1635
1636 g_hpm_i2c_instance_map[index] = this;
1637 i2c_clear_status(
1638 i2c_, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_ARBLOSE_MASK);
1639 i2c_enable_irq(i2c_, I2C_EVENT_TRANSACTION_COMPLETE | I2C_EVENT_LOSS_ARBITRATION);
1640 intc_m_enable_irq_with_priority(static_cast<uint32_t>(irq), 1U);
1641 return ErrorCode::OK;
1642#endif
1643}
1644
1645void HPMI2C::DisableAsyncI2cIrq()
1646{
1647#if LIBXR_HPM_I2C_HAS_INTERRUPT
1648 if (i2c_ != nullptr)
1649 {
1650 i2c_disable_irq(i2c_, I2C_EVENT_TRANSACTION_COMPLETE | I2C_EVENT_LOSS_ARBITRATION);
1651 const int32_t irq = ResolveBoardI2cIrq(i2c_);
1652 if (irq >= 0)
1653 {
1654 intc_m_disable_irq(static_cast<uint32_t>(irq));
1655 }
1656 }
1657 const int32_t index = ResolveI2cIndex(i2c_);
1658 if (index >= 0 && static_cast<size_t>(index) < kHpmI2cInstanceCount &&
1659 g_hpm_i2c_instance_map[index] == this)
1660 {
1661 g_hpm_i2c_instance_map[index] = nullptr;
1662 }
1663#endif
1664}
1665
1666void HPMI2C::HandleAsyncInterrupt(bool in_isr)
1667{
1668 if (!AsyncTransferActive() || i2c_ == nullptr)
1669 {
1670 return;
1671 }
1672
1673 const uint32_t status = i2c_get_status(i2c_);
1674 if ((status & I2C_STATUS_ARBLOSE_MASK) != 0U)
1675 {
1676 i2c_clear_status(i2c_, I2C_STATUS_ARBLOSE_MASK);
1677 AsyncCompletionStateMachine::MarkI2cDone(async_ctx_, status_timeout, true);
1678 CompleteAsyncTransfer(in_isr, ErrorCode::TIMEOUT);
1679 return;
1680 }
1681
1682 if ((status & I2C_STATUS_CMPL_MASK) != 0U)
1683 {
1684 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK);
1685 if (async_ctx_.kind == AsyncTransferKind::WRITE &&
1686 (async_ctx_.flags & kI2CFlagWriteCheckAck) != 0U && !I2C_STATUS_ACK_GET(status))
1687 {
1688 AsyncCompletionStateMachine::MarkI2cDone(async_ctx_, status_i2c_no_ack, true);
1689 }
1690 else
1691 {
1692 AsyncCompletionStateMachine::MarkI2cDone(async_ctx_, status_success, false);
1693 }
1694 }
1695
1696 MaybeCompleteAsyncTransfer(in_isr);
1697}
1698
1699void HPMI2C::MaybeCompleteAsyncTransfer(bool in_isr)
1700{
1701 if (!AsyncTransferActive() || !AsyncCompletionStateMachine::Ready(async_ctx_))
1702 {
1703 return;
1704 }
1705
1706 if (async_ctx_.kind == AsyncTransferKind::READ ||
1707 async_ctx_.kind == AsyncTransferKind::MEM_READ)
1708 {
1709 InvalidateDCacheIfNeeded(async_ctx_.read_data.addr_,
1710 static_cast<uint32_t>(async_ctx_.read_data.size_));
1711 }
1712 hpm_stat_t final_status = AsyncCompletionStateMachine::FinalStatus(async_ctx_);
1713 if (final_status == status_success && i2c_get_data_count(i2c_) != 0U)
1714 {
1715 final_status = status_i2c_transmit_not_completed;
1716 AsyncCompletionStateMachine::SetFinalStatus(async_ctx_, final_status);
1717 }
1718 CompleteAsyncTransfer(in_isr, ConvertStatus(final_status));
1719}
1720
1721bool HPMI2C::TryClaimAsyncCompletion()
1722{
1723 uint32_t expected = 0U;
1724 return async_completion_claim_.compare_exchange_strong(
1725 expected, 1U, std::memory_order_acq_rel, std::memory_order_acquire);
1726}
1727
1728void HPMI2C::OnDmaTcCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr)
1729{
1730 UNUSED(base);
1731 UNUSED(channel);
1732 auto* self = static_cast<HPMI2C*>(cb_data_ptr);
1733 if (self == nullptr || !self->AsyncTransferActive())
1734 {
1735 return;
1736 }
1737
1738 AsyncCompletionStateMachine::MarkDmaDone(self->async_ctx_);
1739 self->MaybeCompleteAsyncTransfer(true);
1740}
1741
1742void HPMI2C::OnDmaErrorCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr)
1743{
1744 UNUSED(base);
1745 UNUSED(channel);
1746 auto* self = static_cast<HPMI2C*>(cb_data_ptr);
1747 if (self == nullptr || !self->AsyncTransferActive())
1748 {
1749 return;
1750 }
1751 if (AsyncCompletionStateMachine::DmaDone(self->async_ctx_))
1752 {
1753 return;
1754 }
1755 AsyncCompletionStateMachine::MarkFailure(self->async_ctx_, status_fail, true);
1756 self->CompleteAsyncTransfer(true, ErrorCode::FAILED);
1757}
1758
1759void HPMI2C::OnDmaAbortCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr)
1760{
1761 UNUSED(base);
1762 UNUSED(channel);
1763 auto* self = static_cast<HPMI2C*>(cb_data_ptr);
1764 if (self == nullptr || !self->AsyncTransferActive())
1765 {
1766 return;
1767 }
1768 if (AsyncCompletionStateMachine::DmaDone(self->async_ctx_))
1769 {
1770 return;
1771 }
1772 AsyncCompletionStateMachine::MarkFailure(self->async_ctx_, status_fail, true);
1773 self->CompleteAsyncTransfer(true, ErrorCode::FAILED);
1774}
1775#endif
1776
1777ErrorCode HPMI2C::ValidateTransferArgs(uint16_t slave_addr, RawData data,
1778 bool allow_zero_size) const
1779{
1780 if (data.size_ == 0)
1781 {
1782 return allow_zero_size ? ErrorCode::OK : ErrorCode::ARG_ERR;
1783 }
1784 if (data.addr_ == nullptr)
1785 {
1786 return ErrorCode::PTR_NULL;
1787 }
1788 if (data.size_ > I2C_SOC_TRANSFER_COUNT_MAX)
1789 {
1790 return ErrorCode::SIZE_ERR;
1791 }
1792 return ValidateSlaveAddress(slave_addr);
1793}
1794
1795ErrorCode HPMI2C::ValidateTransferArgs(uint16_t slave_addr, ConstRawData data,
1796 bool allow_zero_size) const
1797{
1798 if (data.size_ == 0)
1799 {
1800 return allow_zero_size ? ErrorCode::OK : ErrorCode::ARG_ERR;
1801 }
1802 if (data.addr_ == nullptr)
1803 {
1804 return ErrorCode::PTR_NULL;
1805 }
1806 if (data.size_ > I2C_SOC_TRANSFER_COUNT_MAX)
1807 {
1808 return ErrorCode::SIZE_ERR;
1809 }
1810 return ValidateSlaveAddress(slave_addr);
1811}
1812
1813ErrorCode HPMI2C::ValidateMemWriteArgs(uint16_t slave_addr, ConstRawData write_data,
1814 MemAddrLength mem_addr_size,
1815 uint32_t& addr_size) const
1816{
1817 if (write_data.size_ > 0 && write_data.addr_ == nullptr)
1818 {
1819 return ErrorCode::PTR_NULL;
1820 }
1821
1822 ErrorCode ans = ResolveMemAddressSize(mem_addr_size, addr_size);
1823 if (ans != ErrorCode::OK)
1824 {
1825 return ans;
1826 }
1827 if ((addr_size + write_data.size_) > I2C_SOC_TRANSFER_COUNT_MAX)
1828 {
1829 return ErrorCode::SIZE_ERR;
1830 }
1831 return ValidateSlaveAddress(slave_addr);
1832}
1833
1834ErrorCode HPMI2C::SetConfig(Configuration config)
1835{
1836 if (i2c_ == nullptr)
1837 {
1838 return ErrorCode::PTR_NULL;
1839 }
1840
1841 return ApplyConfig(config);
1842}
1843
1844ErrorCode HPMI2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
1845 bool in_isr)
1846{
1847 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, read_data, true);
1848 if (arg_ans != ErrorCode::OK || read_data.size_ == 0)
1849 {
1850 return FinishOperation(op, in_isr, arg_ans);
1851 }
1852
1853#if LIBXR_HPM_I2C_HAS_DMA_MGR
1854 if (AsyncTransferActive())
1855 {
1856 return FinishOperation(op, in_isr, ErrorCode::BUSY);
1857 }
1858
1859 if (op.type != ReadOperation::OperationType::BLOCK)
1860 {
1861 const ErrorCode ans = StartReadAsync(slave_addr, read_data, op);
1862 if (ans != ErrorCode::OK)
1863 {
1864 op.UpdateStatus(in_isr, ans);
1865 }
1866 return ans;
1867 }
1868#endif
1869
1871 if (ans != ErrorCode::OK)
1872 {
1873 return FinishOperation(op, in_isr, ans);
1874 }
1875
1876 hpm_stat_t status =
1877 i2c_master_read(i2c_, slave_addr, static_cast<uint8_t*>(read_data.addr_),
1878 static_cast<uint32_t>(read_data.size_));
1879 ans = ConvertStatus(status);
1880 if (ShouldRecover(status))
1881 {
1883 }
1884 return FinishOperation(op, in_isr, ans);
1885}
1886
1887ErrorCode HPMI2C::DoSequenceWrite(uint16_t slave_addr, ConstRawData write_data,
1888 SequenceFrame frame, bool check_ack)
1889{
1890#if LIBXR_HPM_I2C_HAS_DMA_MGR
1891 if (AsyncTransferActive())
1892 {
1893 return ErrorCode::BUSY;
1894 }
1895#endif
1896
1898 if (ans != ErrorCode::OK)
1899 {
1900 return ans;
1901 }
1902
1903 hpm_stat_t status;
1905 {
1906 uint16_t flags = kI2CFlagWriteCheckAck;
1907 if (!check_ack)
1908 {
1909 flags = 0U;
1910 }
1911 switch (frame)
1912 {
1914 flags |= 0U;
1915 flags |= kI2CFlagAddr10Bit;
1916 flags |= kI2CFlagNoStop;
1917 break;
1919 flags |= kI2CFlagAddr10Bit | I2C_NO_START | I2C_NO_ADDRESS | kI2CFlagNoStop;
1920 break;
1922 default:
1923 flags |= kI2CFlagAddr10Bit | I2C_NO_START | I2C_NO_ADDRESS;
1924 break;
1925 }
1926 const hpm_stat_t raw_status = DoManualTransferWithFlags(
1927 slave_addr, RawData(const_cast<void*>(write_data.addr_), write_data.size_),
1928 flags);
1929 status = raw_status;
1930 }
1931 else
1932 {
1933 status = i2c_master_seq_transmit_check_ack(
1934 i2c_, slave_addr,
1935 const_cast<uint8_t*>(static_cast<const uint8_t*>(write_data.addr_)),
1936 static_cast<uint32_t>(write_data.size_), ConvertSequenceFrame(frame), check_ack);
1937 }
1938
1939 ans = ConvertStatus(status);
1940 if (ShouldRecover(status))
1941 {
1943 }
1944 return ans;
1945}
1946
1947ErrorCode HPMI2C::DoSequenceRead(uint16_t slave_addr, RawData read_data,
1948 SequenceFrame frame)
1949{
1950#if LIBXR_HPM_I2C_HAS_DMA_MGR
1951 if (AsyncTransferActive())
1952 {
1953 return ErrorCode::BUSY;
1954 }
1955#endif
1956
1958 if (ans != ErrorCode::OK)
1959 {
1960 return ans;
1961 }
1962
1963 hpm_stat_t status;
1965 {
1966 uint16_t flags = kI2CFlagRead | kI2CFlagAddr10Bit;
1967 switch (frame)
1968 {
1970 flags |= kI2CFlagNoStop;
1971 break;
1973 flags |= I2C_NO_START | I2C_NO_ADDRESS | kI2CFlagNoStop;
1974 break;
1976 default:
1977 flags |= I2C_NO_START | I2C_NO_ADDRESS;
1978 break;
1979 }
1980 status = DoManualTransferWithFlags(slave_addr, read_data, flags);
1981 }
1982 else
1983 {
1984 status = i2c_master_seq_receive(
1985 i2c_, slave_addr, static_cast<uint8_t*>(read_data.addr_),
1986 static_cast<uint32_t>(read_data.size_), ConvertSequenceFrame(frame));
1987 }
1988
1989 ans = ConvertStatus(status);
1990 if (ShouldRecover(status))
1991 {
1993 }
1994 return ans;
1995}
1996
1997ErrorCode HPMI2C::DoTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags)
1998{
1999#if LIBXR_HPM_I2C_HAS_DMA_MGR
2000 if (AsyncTransferActive())
2001 {
2002 return ErrorCode::BUSY;
2003 }
2004#endif
2005
2007 if (ans != ErrorCode::OK)
2008 {
2009 return ans;
2010 }
2011
2012 const uint16_t final_flags = BuildTransferFlags(flags);
2013 const hpm_stat_t status = DoManualTransferWithFlags(slave_addr, data, final_flags);
2014 ans = ConvertStatus(status);
2015 if (ShouldRecover(status))
2016 {
2018 }
2019 return ans;
2020}
2021
2022hpm_stat_t HPMI2C::DoManualTransferWithFlags(uint16_t slave_addr, RawData data,
2023 uint16_t flags)
2024{
2025#if LIBXR_HPM_I2C_HAS_DMA_MGR
2026 if (AsyncTransferActive())
2027 {
2028 return status_i2c_bus_busy;
2029 }
2030#endif
2031
2032 return DoManualTransferWithFlagsImpl(i2c_, slave_addr, data, flags, wait_policy_);
2033}
2034
2035ErrorCode HPMI2C::SequenceWrite(uint16_t slave_addr, ConstRawData write_data,
2036 SequenceFrame frame, bool check_ack, WriteOperation& op,
2037 bool in_isr)
2038{
2039 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, write_data, false);
2040 if (arg_ans != ErrorCode::OK)
2041 {
2042 return FinishOperation(op, in_isr, arg_ans);
2043 }
2044#if LIBXR_HPM_I2C_HAS_DMA_MGR
2045 if (AsyncTransferActive())
2046 {
2047 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2048 }
2049#endif
2050 return FinishOperation(op, in_isr,
2051 DoSequenceWrite(slave_addr, write_data, frame, check_ack));
2052}
2053
2054ErrorCode HPMI2C::SequenceRead(uint16_t slave_addr, RawData read_data,
2055 SequenceFrame frame, ReadOperation& op, bool in_isr)
2056{
2057 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, read_data, false);
2058 if (arg_ans != ErrorCode::OK)
2059 {
2060 return FinishOperation(op, in_isr, arg_ans);
2061 }
2062#if LIBXR_HPM_I2C_HAS_DMA_MGR
2063 if (AsyncTransferActive())
2064 {
2065 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2066 }
2067#endif
2068 return FinishOperation(op, in_isr, DoSequenceRead(slave_addr, read_data, frame));
2069}
2070
2071ErrorCode HPMI2C::TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags,
2072 ReadOperation& op, bool in_isr)
2073{
2074 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, data, false);
2075 if (arg_ans != ErrorCode::OK)
2076 {
2077 return FinishOperation(op, in_isr, arg_ans);
2078 }
2079#if LIBXR_HPM_I2C_HAS_DMA_MGR
2080 if (AsyncTransferActive())
2081 {
2082 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2083 }
2084#endif
2085 return FinishOperation(op, in_isr, DoTransferWithFlags(slave_addr, data, flags));
2086}
2087
2088ErrorCode HPMI2C::TransferWithFlags(uint16_t slave_addr, ConstRawData data,
2089 uint16_t flags, WriteOperation& op, bool in_isr)
2090{
2091 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, data, false);
2092 if (arg_ans != ErrorCode::OK)
2093 {
2094 return FinishOperation(op, in_isr, arg_ans);
2095 }
2096#if LIBXR_HPM_I2C_HAS_DMA_MGR
2097 if (AsyncTransferActive())
2098 {
2099 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2100 }
2101#endif
2102 return FinishOperation(
2103 op, in_isr,
2104 DoTransferWithFlags(slave_addr, RawData(const_cast<void*>(data.addr_), data.size_),
2105 static_cast<uint16_t>(flags & ~kI2CFlagRead)));
2106}
2107
2108ErrorCode HPMI2C::Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation& op,
2109 bool in_isr)
2110{
2111 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, write_data, true);
2112 if (arg_ans != ErrorCode::OK || write_data.size_ == 0)
2113 {
2114 return FinishOperation(op, in_isr, arg_ans);
2115 }
2116
2117#if LIBXR_HPM_I2C_HAS_DMA_MGR
2118 if (AsyncTransferActive())
2119 {
2120 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2121 }
2122
2123 if (op.type != WriteOperation::OperationType::BLOCK)
2124 {
2125 const ErrorCode ans = StartWriteAsync(slave_addr, write_data, op);
2126 if (ans != ErrorCode::OK)
2127 {
2128 op.UpdateStatus(in_isr, ans);
2129 }
2130 return ans;
2131 }
2132#endif
2133
2135 if (ans != ErrorCode::OK)
2136 {
2137 return FinishOperation(op, in_isr, ans);
2138 }
2139
2140 hpm_stat_t status = i2c_master_write(
2141 i2c_, slave_addr,
2142 const_cast<uint8_t*>(static_cast<const uint8_t*>(write_data.addr_)),
2143 static_cast<uint32_t>(write_data.size_));
2144 ans = ConvertStatus(status);
2145 if (ShouldRecover(status))
2146 {
2148 }
2149 return FinishOperation(op, in_isr, ans);
2150}
2151
2152ErrorCode HPMI2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
2153 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
2154{
2155 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, read_data, true);
2156 if (arg_ans != ErrorCode::OK || read_data.size_ == 0)
2157 {
2158 return FinishOperation(op, in_isr, arg_ans);
2159 }
2160
2161#if LIBXR_HPM_I2C_HAS_DMA_MGR
2162 if (AsyncTransferActive())
2163 {
2164 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2165 }
2166
2167 if (op.type != ReadOperation::OperationType::BLOCK)
2168 {
2169 const ErrorCode ans =
2170 StartMemReadAsync(slave_addr, mem_addr, read_data, op, mem_addr_size);
2171 if (ans != ErrorCode::OK)
2172 {
2173 op.UpdateStatus(in_isr, ans);
2174 }
2175 return ans;
2176 }
2177#endif
2178
2179 uint32_t addr_size = 0;
2180 ErrorCode ans = ResolveMemAddressSize(mem_addr_size, addr_size);
2181 if (ans != ErrorCode::OK)
2182 {
2183 return FinishOperation(op, in_isr, ans);
2184 }
2185 if (addr_size > I2C_SOC_TRANSFER_COUNT_MAX)
2186 {
2187 return FinishOperation(op, in_isr, ErrorCode::SIZE_ERR);
2188 }
2189
2190 ans = EnsureControllerReady();
2191 if (ans != ErrorCode::OK)
2192 {
2193 return FinishOperation(op, in_isr, ans);
2194 }
2195
2196 uint8_t addr[2] = {};
2197 FillMemAddress(mem_addr, mem_addr_size, addr);
2198
2200 {
2201 ans = DoSequenceWrite(slave_addr, ConstRawData(addr, addr_size), SequenceFrame::FIRST,
2202 true);
2203 if (ans == ErrorCode::OK)
2204 {
2205 ans = DoSequenceRead(slave_addr, read_data, SequenceFrame::LAST);
2206 }
2207 }
2208 else
2209 {
2210 const hpm_stat_t status = i2c_master_address_read(
2211 i2c_, slave_addr, addr, addr_size, static_cast<uint8_t*>(read_data.addr_),
2212 static_cast<uint32_t>(read_data.size_));
2213 ans = ConvertStatus(status);
2214 if (ShouldRecover(status))
2215 {
2217 }
2218 }
2219 return FinishOperation(op, in_isr, ans);
2220}
2221
2222ErrorCode HPMI2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
2223 ConstRawData write_data, WriteOperation& op,
2224 MemAddrLength mem_addr_size, bool in_isr)
2225{
2226 uint32_t addr_size = 0;
2227 ErrorCode ans = ValidateMemWriteArgs(slave_addr, write_data, mem_addr_size, addr_size);
2228 if (ans != ErrorCode::OK)
2229 {
2230 return FinishOperation(op, in_isr, ans);
2231 }
2232
2233#if LIBXR_HPM_I2C_HAS_DMA_MGR
2234 if (AsyncTransferActive())
2235 {
2236 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2237 }
2238#endif
2239
2240 ans = EnsureControllerReady();
2241 if (ans != ErrorCode::OK)
2242 {
2243 return FinishOperation(op, in_isr, ans);
2244 }
2245
2246 uint8_t addr[2] = {};
2247 FillMemAddress(mem_addr, mem_addr_size, addr);
2248
2250 {
2251 if (write_data.size_ == 0)
2252 {
2253 hpm_stat_t status =
2254 DoManualTransferWithFlags(slave_addr, RawData(addr, addr_size),
2255 kI2CFlagAddr10Bit | kI2CFlagWriteCheckAck);
2256 ans = ConvertStatus(status);
2257 if (ShouldRecover(status))
2258 {
2260 }
2261 }
2262 else
2263 {
2264 ans = DoSequenceWrite(slave_addr, ConstRawData(addr, addr_size),
2265 SequenceFrame::FIRST, true);
2266 if (ans == ErrorCode::OK)
2267 {
2268 ans = DoSequenceWrite(slave_addr, write_data, SequenceFrame::LAST, true);
2269 }
2270 }
2271 }
2272 else
2273 {
2274 hpm_stat_t status;
2275 if (write_data.size_ == 0)
2276 {
2277 status = i2c_master_write(i2c_, slave_addr, addr, addr_size);
2278 }
2279 else
2280 {
2281 status = i2c_master_address_write(
2282 i2c_, slave_addr, addr, addr_size,
2283 const_cast<uint8_t*>(static_cast<const uint8_t*>(write_data.addr_)),
2284 static_cast<uint32_t>(write_data.size_));
2285 }
2286
2287 ans = ConvertStatus(status);
2288 if (ShouldRecover(status))
2289 {
2291 }
2292 }
2293 return FinishOperation(op, in_isr, ans);
2294}
2295
2296#else
2297
2298extern "C" void libxr_hpm_i2c_process_interrupt(LibXRHpmI2cType* ptr) { UNUSED(ptr); }
2299
2300HPMI2C::HPMI2C(LibXRHpmI2cType* i2c, clock_name_t clock, bool auto_board_init,
2301 I2C::Configuration config)
2302 : i2c_(i2c), clock_(clock), current_config_(config), auto_board_init_(auto_board_init)
2303{
2304 (void)i2c_;
2305 (void)clock_;
2306 (void)auto_board_init_;
2307}
2308
2314
2316{
2317 UNUSED(status);
2319}
2320
2321uint16_t HPMI2C::BuildTransferFlags(uint16_t flags) const { return flags; }
2322
2323ErrorCode HPMI2C::DoSequenceWrite(uint16_t slave_addr, ConstRawData write_data,
2324 SequenceFrame frame, bool check_ack)
2325{
2326 UNUSED(slave_addr);
2327 UNUSED(write_data);
2328 UNUSED(frame);
2329 UNUSED(check_ack);
2331}
2332
2333ErrorCode HPMI2C::DoSequenceRead(uint16_t slave_addr, RawData read_data,
2334 SequenceFrame frame)
2335{
2336 UNUSED(slave_addr);
2337 UNUSED(read_data);
2338 UNUSED(frame);
2340}
2341
2342ErrorCode HPMI2C::DoTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags)
2343{
2344 UNUSED(slave_addr);
2345 UNUSED(data);
2346 UNUSED(flags);
2348}
2349
2350hpm_stat_t HPMI2C::DoManualTransferWithFlags(uint16_t slave_addr, RawData data,
2351 uint16_t flags)
2352{
2353 UNUSED(slave_addr);
2354 UNUSED(data);
2355 UNUSED(flags);
2356 return status_fail;
2357}
2358
2360
2362
2364{
2365 current_config_ = config;
2366 configured_ = false;
2368}
2369
2370bool HPMI2C::ShouldRecover(hpm_stat_t status)
2371{
2372 UNUSED(status);
2373 return false;
2374}
2375
2377
2379
2381{
2382 current_config_ = config;
2383 configured_ = false;
2385}
2386
2387ErrorCode HPMI2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
2388 bool in_isr)
2389{
2390 UNUSED(slave_addr);
2391 UNUSED(read_data);
2392 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2393}
2394
2395ErrorCode HPMI2C::Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation& op,
2396 bool in_isr)
2397{
2398 UNUSED(slave_addr);
2399 UNUSED(write_data);
2400 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2401}
2402
2403ErrorCode HPMI2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
2404 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
2405{
2406 UNUSED(slave_addr);
2407 UNUSED(mem_addr);
2408 UNUSED(read_data);
2409 UNUSED(mem_addr_size);
2410 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2411}
2412
2413ErrorCode HPMI2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
2414 ConstRawData write_data, WriteOperation& op,
2415 MemAddrLength mem_addr_size, bool in_isr)
2416{
2417 UNUSED(slave_addr);
2418 UNUSED(mem_addr);
2419 UNUSED(write_data);
2420 UNUSED(mem_addr_size);
2421 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2422}
2423
2424ErrorCode HPMI2C::SequenceWrite(uint16_t slave_addr, ConstRawData write_data,
2425 SequenceFrame frame, bool check_ack, WriteOperation& op,
2426 bool in_isr)
2427{
2428 UNUSED(slave_addr);
2429 UNUSED(write_data);
2430 UNUSED(frame);
2431 UNUSED(check_ack);
2432 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2433}
2434
2435ErrorCode HPMI2C::SequenceRead(uint16_t slave_addr, RawData read_data,
2436 SequenceFrame frame, ReadOperation& op, bool in_isr)
2437{
2438 UNUSED(slave_addr);
2439 UNUSED(read_data);
2440 UNUSED(frame);
2441 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2442}
2443
2444ErrorCode HPMI2C::TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags,
2445 ReadOperation& op, bool in_isr)
2446{
2447 UNUSED(slave_addr);
2448 UNUSED(data);
2449 UNUSED(flags);
2450 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2451}
2452
2454 uint16_t flags, WriteOperation& op, bool in_isr)
2455{
2456 UNUSED(slave_addr);
2457 UNUSED(data);
2458 UNUSED(flags);
2459 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2460}
2461
2462#endif
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
HPM SDK I2C 主机驱动,适配 LibXR I2C 接口 / HPM SDK based I2C master driver for the LibXR I2C interface.
Definition hpm_i2c.hpp:147
ErrorCode MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data, ReadOperation &op, MemAddrLength mem_addr_size=MemAddrLength::BYTE_8, bool in_isr=false) override
从 I2C 从设备寄存器或存储器地址读取字节 / Read bytes from an I2C slave register or memory address.
Definition hpm_i2c.cpp:2403
ErrorCode DoTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags)
执行一段扩展标志事务,不做状态分发 / Execute one flag-based transfer without LibXR status dispatch.
Definition hpm_i2c.cpp:2342
void TryRecoverBusLines()
在 SDA 被拉低且硬件支持时尝试发出 I2C reset clocks / Try to generate I2C reset clocks when SDA is stuck low and the...
Definition hpm_i2c.cpp:2378
ErrorCode TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags, ReadOperation &op, bool in_isr=false)
执行一段 HPM 扩展标志主机事务 / Execute one HPM master transfer with extended SDK flags.
Definition hpm_i2c.cpp:2444
WaitPolicy wait_policy_
当前忙等超时策略 / Current busy-wait timeout policy.
Definition hpm_i2c.hpp:924
static bool ShouldRecover(hpm_stat_t status)
判断失败后是否需要重建控制器 / Decide whether the controller should be reinitialized after a failure.
Definition hpm_i2c.cpp:2370
ErrorCode SequenceRead(uint16_t slave_addr, RawData read_data, SequenceFrame frame, ReadOperation &op, bool in_isr=false)
执行一段 HPM 主机顺序读事务 / Execute one HPM master sequential read frame.
Definition hpm_i2c.cpp:2435
ErrorCode ValidateTransferArgs(uint16_t slave_addr, RawData data, bool allow_zero_size) const
校验普通读写事务入口参数 / Validate common read/write entry arguments.
ErrorCode ValidateMemWriteArgs(uint16_t slave_addr, ConstRawData write_data, MemAddrLength mem_addr_size, uint32_t &addr_size) const
校验寄存器写事务入口参数并解析寄存器地址长度 / Validate memory-write entry arguments and resolve memory-address length.
ErrorCode SetWaitPolicy(WaitPolicy policy)
设置当前实例的忙等超时策略 / Set the busy-wait timeout policy for this instance.
Definition hpm_i2c.cpp:76
ErrorCode DoSequenceRead(uint16_t slave_addr, RawData read_data, SequenceFrame frame)
执行一段顺序读事务,不做状态分发 / Execute one sequential read frame without LibXR status dispatch.
Definition hpm_i2c.cpp:2333
ErrorCode EnsureClockReady()
确保 I2C 源时钟已可用 / Ensure the I2C source clock is available.
Definition hpm_i2c.cpp:2359
ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation &op, bool in_isr=false) override
向 I2C 从设备写入字节 / Write bytes to an I2C slave.
Definition hpm_i2c.cpp:2395
ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation &op, bool in_isr=false) override
从 I2C 从设备读取字节 / Read bytes from an I2C slave.
Definition hpm_i2c.cpp:2387
static ErrorCode FinishOperation(Op &op, bool in_isr, ErrorCode ans)
完成 LibXR 操作状态更新或回调 / Complete LibXR operation status update or callback dispatch.
Definition hpm_i2c.hpp:910
static ErrorCode ConvertStatus(hpm_stat_t status)
将 HPM SDK I2C 状态码转换为 LibXR 错误码 / Convert HPM SDK I2C status to LibXR ErrorCode.
Definition hpm_i2c.cpp:2315
AddressMode address_mode_
当前主机寻址模式 / Current master addressing mode.
Definition hpm_i2c.hpp:926
ErrorCode SetAddressMode(AddressMode mode)
设置 HPM 主机寻址模式并重建控制器 / Set HPM master addressing mode and rebuild the controller.
Definition hpm_i2c.cpp:2309
ErrorCode ApplyConfig(const Configuration &config)
按当前后端限制下发配置并缓存成功配置 / Apply configuration under current backend limits and cache it on success.
Definition hpm_i2c.cpp:2363
ErrorCode MemWrite(uint16_t slave_addr, uint16_t mem_addr, ConstRawData write_data, WriteOperation &op, MemAddrLength mem_addr_size=MemAddrLength::BYTE_8, bool in_isr=false) override
向 I2C 从设备寄存器或存储器地址写入字节 / Write bytes to an I2C slave register or memory address.
Definition hpm_i2c.cpp:2413
AddressMode
HPM I2C 主机寻址模式 / HPM I2C master addressing mode.
Definition hpm_i2c.hpp:153
@ ADDR_10BIT
10-bit 从地址 / 10-bit slave addressing.
bool auto_board_init_
是否自动调用板级初始化 / Whether board init is automatic.
Definition hpm_i2c.hpp:943
AsyncTransferKind
HPM I2C 后台事务类型 / HPM I2C asynchronous transfer kind.
Definition hpm_i2c.hpp:197
clock_name_t clock_
I2C 源时钟名称 / I2C source clock name.
Definition hpm_i2c.hpp:920
ErrorCode EnsureControllerReady()
确保控制器已完成一次可用配置 / Ensure the controller has a usable configuration applied.
Definition hpm_i2c.cpp:2361
static void FillMemAddress(uint16_t mem_addr, MemAddrLength len, uint8_t out[2])
按 BYTE_8/BYTE_16 格式填充寄存器地址字节 / Fill register address bytes according to BYTE_8/BYTE_16 format.
Definition hpm_i2c.cpp:71
static uint16_t GetMaxSlaveAddress(AddressMode mode)
获取指定寻址模式可接受的最大从地址 / Get the maximum valid slave address for the given mode.
Definition hpm_i2c.cpp:56
SequenceFrame
HPM 主机顺序事务分段类型 / HPM master sequential transfer frame type.
Definition hpm_i2c.hpp:162
@ FIRST
带 START 和地址阶段 / Includes START and address phase.
@ NEXT
中间段,不带 START/STOP / Middle frame without START/STOP.
@ LAST
末段,带 STOP / Final frame with STOP.
ErrorCode ValidateSlaveAddress(uint16_t slave_addr) const
校验当前寻址模式下的从地址 / Validate slave address for the current addressing mode.
Definition hpm_i2c.cpp:61
LibXRHpmI2cType * i2c_
I2C 外设实例 / I2C peripheral instance.
Definition hpm_i2c.hpp:919
hpm_stat_t DoManualTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags)
通过手工 phase 编排执行一笔 blocking 事务 / Execute one blocking transfer through manual phase orchestration.
Definition hpm_i2c.cpp:2350
Configuration current_config_
最近一次成功总线时序配置 / Most recent successful bus-timing config.
Definition hpm_i2c.hpp:922
ErrorCode SequenceWrite(uint16_t slave_addr, ConstRawData write_data, SequenceFrame frame, bool check_ack, WriteOperation &op, bool in_isr=false)
执行一段 HPM 主机顺序写事务 / Execute one HPM master sequential write frame.
Definition hpm_i2c.cpp:2424
static ErrorCode ResolveMemAddressSize(MemAddrLength len, uint32_t &addr_size)
解析寄存器地址宽度枚举到字节数 / Resolve register-address enum to byte count.
Definition hpm_i2c.cpp:66
HPMI2C(LibXRHpmI2cType *i2c, clock_name_t clock, bool auto_board_init=true, I2C::Configuration config={100000})
构造 HPM I2C 主机对象 / Construct an HPM I2C master object.
Definition hpm_i2c.cpp:2300
uint32_t source_clock_hz_
缓存的源时钟频率 / Cached source clock frequency.
Definition hpm_i2c.hpp:921
ErrorCode DoSequenceWrite(uint16_t slave_addr, ConstRawData write_data, SequenceFrame frame, bool check_ack)
执行一段顺序写事务,不做状态分发 / Execute one sequential write frame without LibXR status dispatch.
Definition hpm_i2c.cpp:2323
bool configured_
是否已有成功配置 / Whether a valid config was applied.
Definition hpm_i2c.hpp:928
ErrorCode SetConfig(Configuration config) override
应用 I2C 时序配置 / Apply I2C timing configuration.
Definition hpm_i2c.cpp:2380
void RecoverController()
复位并按缓存配置重建 I2C 控制器 / Reset and reinitialize the I2C controller with cached configuration.
Definition hpm_i2c.cpp:2376
uint16_t BuildTransferFlags(uint16_t flags) const
根据目标固定速率解析 HPM I2C 工作模式 / Resolve HPM I2C operating mode from a fixed target clock rate.
Definition hpm_i2c.cpp:2321
union LibXR::Operation::@5 data
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
OperationType type
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
HPM I2C 主机驱动适配头文件 / Adapter header for the HPM I2C master driver.
HPM I2C 平台资源解析 helper / Platform resource resolver for HPM I2C.
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ TIMEOUT
超时 | Timeout
@ SIZE_ERR
尺寸错误 | Size error
@ CHECK_ERR
校验错误 | Check error
@ INIT_ERR
初始化错误 | Initialization error
@ BUSY
忙碌 | Busy
@ NO_RESPONSE
无响应 | No response
@ PTR_NULL
空指针 | Null pointer
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ FULL
已满 | Full
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
HPM I2C 忙等超时策略 / HPM I2C busy-wait timeout policy.
Definition hpm_i2c.hpp:215
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.
Definition i2c.hpp:24