libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
hpm_i2c.hpp
Go to the documentation of this file.
1#pragma once
2
23#include <atomic>
24
25#include "hpm_clock_drv.h"
26#include "hpm_soc.h"
27#include "i2c.hpp"
28#include "libxr_rw.hpp"
29
30#if defined(HPMSOC_HAS_HPMSDK_I2C) && __has_include("hpm_i2c_drv.h")
31#include "hpm_i2c_drv.h"
32#define LIBXR_HPM_I2C_SUPPORTED 1
33using LibXRHpmI2cType = I2C_Type;
34#else
35#define LIBXR_HPM_I2C_SUPPORTED 0
36using LibXRHpmI2cType = void;
37#endif
38
39#include "hpm_dma.hpp"
40
41extern "C" void libxr_hpm_i2c_process_interrupt(LibXRHpmI2cType* ptr);
42
43namespace LibXR
44{
45
142class HPMI2C final : public I2C
143{
144 public:
148 enum class AddressMode : uint8_t
149 {
150 ADDR_7BIT,
152 };
153
157 enum class SequenceFrame : uint8_t
158 {
159 FIRST,
160 NEXT,
161 LAST
162 };
163
167 enum class TransferFlag : uint16_t
168 {
169 NONE = 0,
170#if LIBXR_HPM_I2C_SUPPORTED
171 READ = I2C_RD,
172 ADDR_10BIT = I2C_ADDR_10BIT,
173 NO_START = I2C_NO_START,
174 NO_ADDRESS = I2C_NO_ADDRESS,
175 NO_READ_ACK = I2C_NO_READ_ACK,
176 NO_STOP = I2C_NO_STOP,
177 WRITE_CHECK_ACK = I2C_WRITE_CHECK_ACK
178#else
179 READ = 0x0001U,
180 ADDR_10BIT = 0x0002U,
181 NO_START = 0x0004U,
182 NO_ADDRESS = 0x0008U,
183 NO_READ_ACK = 0x0010U,
184 NO_STOP = 0x0020U,
185 WRITE_CHECK_ACK = 0x0040U
186#endif
187 };
188
192 enum class AsyncTransferKind : uint8_t
193 {
194 NONE,
195 READ,
196 WRITE,
197 MEM_READ
198 };
199
211 {
212 uint64_t addr_hit_timeout_us;
213 uint64_t stop_timeout_us;
214 uint64_t bus_idle_timeout_us;
215 uint64_t transfer_timeout_us;
216 };
217
222 static constexpr WaitPolicy DefaultWaitPolicy()
223 {
224 return {500ULL, 1000ULL, 1000ULL, 500000ULL};
225 }
226
248 HPMI2C(LibXRHpmI2cType* i2c, clock_name_t clock, I2C::Configuration config);
249
266
275 ErrorCode SetWaitPolicy(WaitPolicy policy);
276
281 WaitPolicy GetWaitPolicy() const { return wait_policy_; }
282
287 AddressMode GetAddressMode() const { return address_mode_; }
288
301 ErrorCode SequenceWrite(uint16_t slave_addr, ConstRawData write_data,
302 SequenceFrame frame, bool check_ack, WriteOperation& op,
303 bool in_isr = false);
304
316 ErrorCode SequenceRead(uint16_t slave_addr, RawData read_data, SequenceFrame frame,
317 ReadOperation& op, bool in_isr = false);
318
331 ErrorCode TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags,
332 ReadOperation& op, bool in_isr = false);
333
346 ErrorCode TransferWithFlags(uint16_t slave_addr, ConstRawData data, uint16_t flags,
347 WriteOperation& op, bool in_isr = false);
348
371 ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
372 bool in_isr = false) override;
373
396 ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation& op,
397 bool in_isr = false) override;
398
431 ErrorCode MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
432 ReadOperation& op,
433 MemAddrLength mem_addr_size = MemAddrLength::BYTE_8,
434 bool in_isr = false) override;
435
468 ErrorCode MemWrite(uint16_t slave_addr, uint16_t mem_addr, ConstRawData write_data,
469 WriteOperation& op,
470 MemAddrLength mem_addr_size = MemAddrLength::BYTE_8,
471 bool in_isr = false) override;
472
484 ErrorCode SetConfig(Configuration config) override;
485
491 uint32_t GetClockFreq() const { return source_clock_hz_; }
492
499 void CompleteAsyncTransfer(bool in_isr, ErrorCode ans);
500
501 private:
502 friend void ::libxr_hpm_i2c_process_interrupt(LibXRHpmI2cType* ptr);
503
508 struct AsyncTransferContext
509 {
510 AsyncTransferKind kind = AsyncTransferKind::NONE;
511 uint16_t slave_addr = 0U;
512 MemAddrLength mem_addr_size = MemAddrLength::BYTE_8;
513 uint16_t mem_addr = 0U;
514 uint32_t mem_addr_size_in_byte = 0U;
515 uint8_t mem_addr_bytes[2] = {};
516 uint16_t flags = 0U;
517 RawData read_data = {nullptr, 0};
518 ConstRawData write_data = {nullptr, 0};
519 ReadOperation read_op = {};
520 WriteOperation write_op = {};
521 std::atomic<hpm_stat_t> final_status{
522 status_success};
523 std::atomic<bool> should_recover{
524 false};
525 std::atomic<bool> dma_done{
526 false};
527 std::atomic<bool> cmpl_done{false};
528 };
529
539 struct AsyncCompletionStateMachine
540 {
541 static void Reset(AsyncTransferContext& ctx);
542 static void MarkDmaDone(AsyncTransferContext& ctx);
543 static void MarkI2cDone(AsyncTransferContext& ctx, hpm_stat_t status, bool recover);
544 static void MarkFailure(AsyncTransferContext& ctx, hpm_stat_t status, bool recover);
545 static void SetFinalStatus(AsyncTransferContext& ctx, hpm_stat_t status);
546 static bool DmaDone(const AsyncTransferContext& ctx);
547 static bool Ready(const AsyncTransferContext& ctx);
548 static hpm_stat_t FinalStatus(const AsyncTransferContext& ctx);
549 static bool ShouldRecover(const AsyncTransferContext& ctx);
550 };
551
556 static constexpr uint16_t kMax7BitAddress = 0x7FU;
557
562 static constexpr uint16_t kMax10BitAddress = 0x3FFU;
563
568 static ErrorCode ConvertStatus(hpm_stat_t status);
569
574#if LIBXR_HPM_I2C_SUPPORTED
575 static ErrorCode ResolveMode(uint32_t clock_speed, i2c_mode_t& mode);
576#endif
577
582 static ErrorCode ConvertDmaStatus(hpm_stat_t status);
583
588#if LIBXR_HPM_I2C_SUPPORTED
589 static i2c_seq_transfer_opt_t ConvertSequenceFrame(SequenceFrame frame);
590#endif
591
596 uint16_t BuildTransferFlags(uint16_t flags) const;
597
602 static uint16_t GetMaxSlaveAddress(AddressMode mode);
603
608 ErrorCode ValidateSlaveAddress(uint16_t slave_addr) const;
609
613 ErrorCode ValidateTransferArgs(uint16_t slave_addr, RawData data,
614 bool allow_zero_size) const;
615
619 ErrorCode ValidateTransferArgs(uint16_t slave_addr, ConstRawData data,
620 bool allow_zero_size) const;
621
626 ErrorCode ValidateMemWriteArgs(uint16_t slave_addr, ConstRawData write_data,
627 MemAddrLength mem_addr_size, uint32_t& addr_size) const;
628
633 static ErrorCode ResolveMemAddressSize(MemAddrLength len, uint32_t& addr_size);
634
639 static void FillMemAddress(uint16_t mem_addr, MemAddrLength len, uint8_t out[2]);
640
645 ErrorCode DoSequenceWrite(uint16_t slave_addr, ConstRawData write_data,
646 SequenceFrame frame, bool check_ack);
647
652 ErrorCode DoSequenceRead(uint16_t slave_addr, RawData read_data, SequenceFrame frame);
653
658 ErrorCode DoTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags);
659
664 hpm_stat_t DoManualTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags);
665
670 ErrorCode PrepareAsyncTransfer(uint16_t slave_addr, uint16_t flags, uint32_t size,
671 bool clear_fifo = true, bool require_bus_idle = true);
672
677 static uint32_t ToSystemAddress(const void* addr);
678
683 ErrorCode StartAsyncReadDma(void* dst, uint32_t size);
684
689 ErrorCode StartAsyncWriteDma(const void* src, uint32_t size);
690
695 void StopAsyncDma();
696
701 void StopAndReleaseAsyncBus();
702
706 void ResetAsyncState();
707
712 void ClearAsyncContext();
713
717 void AbortAsyncStart(bool stop_dma, bool disable_irq, bool recover_controller);
718
722 template <typename Op>
723 void StartAsyncBlockWaitIfNeeded(Op& op)
724 {
725 if (op.type == Op::OperationType::BLOCK)
726 {
727 block_wait_.Start(*op.data.sem_info.sem);
728 }
729 }
730
734 template <typename Op>
735 void CancelAsyncBlockWaitIfNeeded(Op& op)
736 {
737 if (op.type == Op::OperationType::BLOCK)
738 {
739 block_wait_.Cancel();
740 }
741 }
742
746 template <typename Op>
747 void CompleteAsyncOperation(Op& op, bool in_isr, ErrorCode ans)
748 {
749 if (op.type == Op::OperationType::BLOCK)
750 {
751 (void)block_wait_.TryPost(in_isr, ans);
752 }
753 else
754 {
755 op.UpdateStatus(in_isr, ans);
756 }
757 }
758
763 ErrorCode StartWriteAsync(uint16_t slave_addr, ConstRawData write_data,
764 WriteOperation& op);
765
770 ErrorCode StartReadAsync(uint16_t slave_addr, RawData read_data, ReadOperation& op);
771
776 ErrorCode StartMemReadAsync(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
777 ReadOperation& op, MemAddrLength mem_addr_size);
778
782 ErrorCode EnsureAsyncDmaReady();
783
788 ErrorCode WaitForAsyncBlockResult(uint32_t timeout);
789
793 void ReleaseAsyncBus();
794
799 ErrorCode EnableAsyncI2cIrq();
800
805 void DisableAsyncI2cIrq();
806
817 void HandleAsyncInterrupt(bool in_isr);
818
823 void MaybeCompleteAsyncTransfer(bool in_isr);
824
829 bool TryClaimAsyncCompletion();
830
834 static void OnDmaTcCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr);
835
839 static void OnDmaErrorCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr);
840
844 static void OnDmaAbortCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr);
845
850 bool AsyncTransferActive() const
851 {
852 return async_busy_.load(std::memory_order_acquire) != 0U;
853 }
854
859 ErrorCode EnsureClockReady();
860
865 ErrorCode EnsureControllerReady();
866
871 ErrorCode ApplyConfig(const Configuration& config);
872
877 static bool ShouldRecover(hpm_stat_t status);
878
883 void RecoverController();
884
889 void TryRecoverBusLines();
890
895 template <typename Op>
896 static ErrorCode FinishOperation(Op& op, bool in_isr, ErrorCode ans)
897 {
898 if (op.type != Op::OperationType::BLOCK)
899 {
900 op.UpdateStatus(in_isr, ans);
901 }
902 return ans;
903 }
904
905 LibXRHpmI2cType* i2c_;
906 clock_name_t clock_;
907 uint32_t source_clock_hz_ = 0;
908 Configuration current_config_{
909 100000};
910 WaitPolicy wait_policy_ =
912 AddressMode address_mode_ =
914 bool configured_ = false;
915 std::atomic<uint32_t> async_busy_{
916 0U};
917 AsyncTransferContext async_ctx_{};
918 AsyncBlockWait block_wait_{};
919 std::atomic<uint32_t> async_completion_claim_{
920 0U};
921 dma_resource_t async_dma_resource_{nullptr, 0U,
922 -1};
923 uint8_t async_dma_source_ =
924 0U;
925 bool async_dma_ready_ =
926 false;
927};
928
929} // namespace LibXR
bool TryPost(bool in_isr, ErrorCode ec)
尝试认领完成并唤醒调用者 / Try to claim completion and wake the caller.
void Start(Semaphore &sem)
绑定信号量并开始等待 / Bind a semaphore and start waiting.
void Cancel()
清除等待状态,不发送通知 / Clear the wait state without posting.
只读原始数据视图 / Immutable raw data view
HPM SDK I2C 主机驱动,适配 LibXR I2C 接口 / HPM SDK based I2C master driver for the LibXR I2C interface.
Definition hpm_i2c.hpp:143
WaitPolicy GetWaitPolicy() const
获取当前实例的忙等超时策略 / Get the current busy-wait timeout policy.
Definition hpm_i2c.hpp:281
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:2333
AddressMode GetAddressMode() const
获取当前 HPM 主机寻址模式 / Get current HPM master addressing mode.
Definition hpm_i2c.hpp:287
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:2374
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:2365
HPMI2C(LibXRHpmI2cType *i2c, clock_name_t clock, I2C::Configuration config)
构造 HPM I2C 主机对象 / Construct an HPM I2C master object.
Definition hpm_i2c.cpp:2232
TransferFlag
HPM 主机扩展事务标志 / HPM master extended transfer flags.
Definition hpm_i2c.hpp:168
ErrorCode SetWaitPolicy(WaitPolicy policy)
设置当前实例的忙等超时策略 / Set the busy-wait timeout policy for this instance.
Definition hpm_i2c.cpp:76
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:2325
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:2317
uint32_t GetClockFreq() const
获取当前缓存的 I2C 源时钟频率 / Get cached I2C source clock frequency.
Definition hpm_i2c.hpp:491
ErrorCode SetAddressMode(AddressMode mode)
设置 HPM 主机寻址模式并重建控制器 / Set HPM master addressing mode and rebuild the controller.
Definition hpm_i2c.cpp:2239
static constexpr WaitPolicy DefaultWaitPolicy()
返回默认 HPM I2C 忙等超时策略 / Return the default HPM I2C wait policy.
Definition hpm_i2c.hpp:222
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:2343
AddressMode
HPM I2C 主机寻址模式 / HPM I2C master addressing mode.
Definition hpm_i2c.hpp:149
@ ADDR_10BIT
10-bit 从地址 / 10-bit slave addressing.
@ ADDR_7BIT
7-bit 从地址 / 7-bit slave addressing.
AsyncTransferKind
HPM I2C 后台事务类型 / HPM I2C asynchronous transfer kind.
Definition hpm_i2c.hpp:193
SequenceFrame
HPM 主机顺序事务分段类型 / HPM master sequential transfer frame type.
Definition hpm_i2c.hpp:158
@ FIRST
带 START 和地址阶段 / Includes START and address phase.
@ NEXT
中间段,不带 START/STOP / Middle frame without START/STOP.
@ LAST
末段,带 STOP / Final frame with STOP.
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:2354
void CompleteAsyncTransfer(bool in_isr, ErrorCode ans)
供 DMA / 中断完成路径调用的完成入口 / Completion entry used by DMA / interrupt driven paths.
ErrorCode SetConfig(Configuration config) override
应用 I2C 时序配置 / Apply I2C timing configuration.
Definition hpm_i2c.cpp:2310
I2C(Inter-Integrated Circuit)接口类。 I2C (Inter-Integrated Circuit) interface class.
Definition i2c.hpp:17
可写原始数据视图 / Mutable raw data view
HPM DMA 管理内部 helper / Internal HPM DMA management helper.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
Operation< ErrorCode > ReadOperation
读操作的完成通知描述符 / Read completion descriptor.
Operation< ErrorCode > WriteOperation
写操作的完成通知描述符 / Write completion descriptor.
HPM I2C 忙等超时策略 / HPM I2C busy-wait timeout policy.
Definition hpm_i2c.hpp:211
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.
Definition i2c.hpp:24