Skip to content

feat(i2c): Add i2c support and stabilize c_board transfer#41

Open
gqsdjhh wants to merge 3 commits intoAlliance-Algorithm:mainfrom
gqsdjhh:i2c
Open

feat(i2c): Add i2c support and stabilize c_board transfer#41
gqsdjhh wants to merge 3 commits intoAlliance-Algorithm:mainfrom
gqsdjhh:i2c

Conversation

@gqsdjhh
Copy link
Copy Markdown

@gqsdjhh gqsdjhh commented Apr 9, 2026

This PR adds end-to-end I2C support across the protocol, host SDK, and firmware.

It starts by introducing the I2C protocol and RmcsBoard support, then adds c_board I2C2 transport support, and finally improves c_board
reliability by replacing the previous queued interrupt-driven implementation with blocking HAL I2C transfers.

The main motivation for the last change is to avoid internal queue-overflow failures during bursty workloads such as OLED initialization and full-screen updates.

Included Changes

  • Add I2C protocol definitions and serializer/deserializer support
  • Add host-side I2C APIs for RmcsBoard
  • Add firmware-side I2C support for rmcs_board
  • Add host-side I2C APIs for CBoard
  • Add firmware-side I2C2 transport support for c_board
  • Configure the required c_board CubeMX I2C and interrupt plumbing
  • Replace queued async I2C handling on c_board with blocking HAL I2C operations
  • Keep the I2C address contract unchanged: host-provided slave addresses are still treated as 7-bit addresses

I2C 支持端到端实现与 c_board 传输稳定化

协议与数据结构

  • 新增 DataId::kI2c0 = 16 标识符用于 I2C 0 通道。
  • 新增 I2cDataView 结构体,包含从机地址、有效负载跨度及可选的寄存器寻址字段 (has_register/reg_address)。
  • 新增 I2cReadConfigView 结构体,定义 I2C 读取配置,包含从机地址、读取长度及可选的寄存器信息。
  • 新增 I2cHeader 位域结构体 (utility::Bitfield<3>),定义有效负载类型枚举 (kWrite = 0kReadRequest = 1kReadResult = 2kError = 3) 及相关位字段成员 (PayloadType、HasRegister、ErrorFlag、SlaveAddress、DataLength)。
  • 扩展 DataCallback 接口,新增 i2c_receive_callback()i2c_error_callback() 两个纯虚函数。

协议序列化与反序列化

  • 实现了完整的 I2C 协议序列化支持,包含 write_i2c_write()write_i2c_read_config()write_i2c_read_result()write_i2c_error() 方法,均包含参数验证 (如从机地址 ≤ 0x7F)、缓冲区分配检查及条件性有效负载复制。
  • 新增 required_i2c_size() 辅助函数,用于计算所需缓冲区大小,验证有效负载/数据长度约束。
  • 实现反序列化协程 process_i2c_field(),解析 I2cHeader、可选的寄存器字节,根据有效负载类型分发到相应的反序列化回调 (i2c_write_deserialized_callbacki2c_read_config_deserialized_callbacki2c_read_result_deserialized_callbacki2c_error_deserialized_callback)。

C Board 固件 (STM32F4xx)

  • 新增 i2c::I2c 类,通过 STM32 HAL 提供 阻塞式 I2C 传输 替代之前的队列驱动异步方式,从而避免 I2C 队列溢出故障。
  • 提供 handle_downlink_write()handle_downlink_read_config() 方法,分别调用 HAL_I2C_Master_Transmit()/HAL_I2C_Mem_Write()HAL_I2C_Master_Receive()/HAL_I2C_Mem_Read(),均使用固定超时和内部固定大小缓冲区。
  • 全局单例 i2c0 绑定至 data::DataId::kI2c0 和 HAL 句柄 &hi2c2
  • CubeMX 配置:
    • 启用 HAL I2C 模块 (HAL_I2C_MODULE_ENABLED)。
    • 配置 I2C2 (100 kHz,7 位寻址),映射至 GPIOF 的 PF0 (SDA) 和 PF1 (SCL)。
    • 新增 I2C2 事件/错误中断处理器 (I2C2_EV_IRQHandlerI2C2_ER_IRQHandler),委托至 HAL 驱动。
    • 更新 CMake 配置以编译 i2c.c 及 STM32 HAL I2C 驱动实现 (stm32f4xx_hal_i2c.cstm32f4xx_hal_i2c_ex.c)。
  • USB 下行接口集成:反序列化回调将 DataId::kI2c0 路由至 i2c::i2c0 的处理方法。

RmcsBoard 固件 (HPM SDK)

  • 新增 i2c::I2c 类,封装 I2C 初始化和下行处理,支持寄存器寻址和原始从机访问。
  • 提供 handle_downlink_write()handle_downlink_read_config() 方法,分别调用 i2c_master_address_write()/i2c_master_write()i2c_master_address_read()/i2c_master_read()
  • 全局单例 i2c0 使用 HPM_I2C0_BASE 或可配置的 BOARD_APP_I2C_BASE
  • 故障处理通过 USB 序列化器向主机回传 I2C 错误。
  • 更新底层 SDK 子模块至新版本,包含相应 I2C 驱动支持。

主机端 API

RmcsBoard

  • PacketBuilder 新增 i2c0_write(const I2cDataView&)i2c0_read(const I2cReadConfigView&) 方法,均进行输入验证 (非空有效负载/非零读取长度)。
  • 新增虚拟回调钩子 i2c0_receive_callback()i2c0_error_callback(),缺省为空操作。

CBoard

  • PacketBuilder 新增 i2c0_write()i2c0_read() 方法,同样进行输入验证。
  • 新增虚拟回调钩子 i2c0_receive_callback()i2c0_error_callback(),缺省为空操作。

协议处理层 (Handler)

  • PacketBuilder 新增 write_i2c()write_i2c_read_config()write_i2c_read_result() 方法,用于构建和发送 I2C 消息。
  • 新增反序列化回调处理上行 I2C 读取结果和错误,并转发至用户级回调。

关键设计决策

  • 从机地址格式:主机提供的从机地址保持 7 位格式,固件在调用 HAL 时自动左移 1 位以适配 8 位寻址模式。
  • 阻塞传输策略:用固定超时的阻塞 HAL 调用替代异步队列驱动方式,改善高并发工作负载 (如 OLED 初始化、全屏更新) 下的可靠性。
  • 可选寄存器寻址:通过 has_register 标志支持寄存器内存访问,使用条件性的 HAL_I2C_Mem_*() 或基础 HAL_I2C_Master_*() 调用。

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

走读

添加了I2C协议支持,涵盖数据结构定义、协议序列化/反序列化、STM32和HPM硬件驱动实现,以及主机端的I2C通信接口。

变更

功能分组 总结
核心数据定义
core/include/librmcs/data/datas.hpp, core/src/protocol/protocol.hpp
新增DataId::kI2c0枚举值,定义I2cDataViewI2cReadConfigView数据结构,以及I2cHeader协议头的位字段布局。
协议反序列化
core/src/protocol/deserializer.hpp, core/src/protocol/deserializer.cpp
添加DeserializeCallback的四个I2C回调接口,实现process_i2c_field()协程处理I2C报文解析、验证、有效负载反序列化。
协议序列化
core/src/protocol/serializer.hpp
新增write_i2c_write()write_i2c_read_config()write_i2c_read_result()write_i2c_error()序列化方法,包含缓冲区大小验证和从属地址校验。
DataCallback接口扩展
core/include/librmcs/data/datas.hpp
DataCallback抽象接口添加i2c_receive_callback()i2c_error_callback()纯虚方法。
STM32 C_Board硬件驱动
firmware/c_board/bsp/cubemx/Core/Inc/i2c.h, firmware/c_board/bsp/cubemx/Core/Src/i2c.c, firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c
I2C2外设初始化、GPIO配置(GPIOF的PF0/PF1脚)、事件/错误中断处理程序、MSP钩子实现。
STM32 C_Board应用层
firmware/c_board/app/src/i2c/i2c.hpp, firmware/c_board/app/src/app.cpp, firmware/c_board/app/src/usb/vendor.hpp
I2C设备包装类处理寄存器写/读操作,HAL调用转发,失败时通过USB序列化错误;USB反序列化器路由I2C消息。
STM32配置与构建
firmware/c_board/bsp/cubemx/...CMakeLists.txt, firmware/c_board/bsp/cubemx/rmcs_slave.ioc, firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h, firmware/c_board/bsp/cubemx/Core/Src/main.c, firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h, firmware/c_board/bsp/cubemx/Core/Src/gpio.c
启用HAL I2C模块、添加I2C源文件到CMake、更新CubeMX项目配置新增I2C外设/中断/引脚。
HPM RMCS_Board硬件驱动
firmware/rmcs_board/app/src/i2c/i2c.hpp, firmware/rmcs_board/app/src/app.cpp, firmware/rmcs_board/app/src/usb/vendor.hpp
I2C设备包装类调用HPM SDK底层接口执行寄存器/原始读写,失败时序列化错误;USB反序列化器路由I2C消息。
HPM SDK升级
firmware/rmcs_board/bsp/hpm_sdk
更新子模块引用至包含I2C支持的新提交。
主机端代理接口
host/include/librmcs/agent/c_board.hpp, host/include/librmcs/agent/rmcs_board.hpp
CBoardRmcsBoardPacketBuilder新增i2c0_write()i2c0_read()方法;实现i2c_receive_callback()i2c_error_callback()虚方法供应用覆写。
主机端协议处理
host/include/librmcs/protocol/handler.hpp, host/src/protocol/handler.cpp
Handler::PacketBuilder新增write_i2c()write_i2c_read_config()write_i2c_read_result()方法;Handler::Impl实现I2C反序列化回调,转发数据或日志错误。

序列图

sequenceDiagram
    participant Host as 主机应用
    participant Serializer as 协议序列化器
    participant USB as USB驱动
    participant Deserializer as 协议反序列化器
    participant Handler as 消息处理器
    participant I2C as I2C驱动
    participant HAL as STM32/HPM HAL

    Host->>Serializer: write_i2c_write(kI2c0, data)
    Serializer->>USB: 发送序列化报文
    USB->>Deserializer: 接收字节流
    Deserializer->>Deserializer: process_i2c_field()
    Deserializer->>Handler: i2c_write_deserialized_callback()
    Handler->>I2C: handle_downlink_write()
    I2C->>HAL: HAL_I2C_Mem_Write/Master_Transmit
    HAL-->>I2C: 成功或失败
    
    alt 写入成功
        I2C-->>Handler: 返回
    else 写入失败
        I2C->>Serializer: write_i2c_error()
        Serializer->>USB: 发送错误报文
    end

    Host->>Serializer: write_i2c_read_config(kI2c0, config)
    Serializer->>USB: 发送读请求
    USB->>Deserializer: 接收字节流
    Deserializer->>Handler: i2c_read_config_deserialized_callback()
    Handler->>I2C: handle_downlink_read_config()
    I2C->>HAL: HAL_I2C_Mem_Read/Master_Receive
    HAL-->>I2C: 数据或失败
    
    alt 读取成功
        I2C->>Serializer: write_i2c_read_result()
        Serializer->>USB: 发送读结果
        USB->>Host: 上行数据
    else 读取失败
        I2C->>Serializer: write_i2c_error()
        Serializer->>USB: 发送错误报文
    end
Loading

估算代码审查工作量

🎯 4 (复杂) | ⏱️ ~50 分钟

可能相关的PR

  • librmcs#15:扩展相同的DataId枚举和DataCallback接口(添加kI2c0和I2C回调),与本PR修改的核心数据结构密切相关。
  • librmcs#23:修改host/include/librmcs/agent/c_board.hpp中的CBoard代理声明,本PR在其基础上扩展I2C包构建方法和回调。

诗歌

🐰 ✨ I2C之路铺展开,
序列化、反序列化来往穿梭,
硬件中断轻轻响,
从主机到芯片,数据如兔毛飘飘然,
寄存器地址被温柔地读写,
通信的舞蹈,在协议的音乐中绽放光彩!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清晰准确地概括了主要变更:添加I2C协议支持和稳定c_board传输。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
firmware/c_board/app/src/app.cpp (1)

86-86: 建议明确 Line 86 的 no-op 调用意图。

Line 86 当前调用 i2c::i2c0->update(),但 firmware/c_board/app/src/i2c/i2c.hppupdate() 为空实现。建议加注释说明“保留扩展点”,避免后续维护误判。

可选改进示例
-        i2c::i2c0->update();
+        // Keep this call as an extension point for future non-blocking I2C work.
+        i2c::i2c0->update();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/c_board/app/src/app.cpp` at line 86, 在调用 i2c::i2c0->update() 的位置(当前在
app.cpp 第 86 行)明确说明这是一处空实现的保留扩展点:在调用旁边添加注释,注明 i2c::I2C::update() 在
firmware/c_board/app/src/i2c/i2c.hpp
中目前为空实现、用于未来扩展或平台特定实现,并指明不要删除或误以为是忘写逻辑;同时报错/断言等不可行时保持调用以便兼容未来实现。
host/include/librmcs/agent/rmcs_board.hpp (1)

75-85: 考虑添加 [[unlikely]] 属性以保持一致性。

c_board.hpp 中的 i2c0_writei2c0_read 方法在错误条件上使用了 [[unlikely]] 属性,但此文件缺少该属性。建议保持两个 board 实现的一致性。

♻️ 建议的修改
     PacketBuilder& i2c0_write(const librmcs::data::I2cDataView& data) {
-        if (data.payload.empty() || !builder_.write_i2c(data::DataId::kI2c0, data))
+        if (data.payload.empty() || !builder_.write_i2c(data::DataId::kI2c0, data)) [[unlikely]]
             throw std::invalid_argument{"I2C0 write failed: Invalid I2C data"};
         return *this;
     }

     PacketBuilder& i2c0_read(const librmcs::data::I2cReadConfigView& data) {
-        if (data.read_length == 0 || !builder_.write_i2c_read_config(data::DataId::kI2c0, data))
+        if (data.read_length == 0 || !builder_.write_i2c_read_config(data::DataId::kI2c0, data))
+            [[unlikely]]
             throw std::invalid_argument{"I2C0 read failed: Invalid I2C read config"};
         return *this;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@host/include/librmcs/agent/rmcs_board.hpp` around lines 75 - 85, The error
branches in PacketBuilder::i2c0_write and PacketBuilder::i2c0_read lack the
[[unlikely]] attribute used in the c_board.hpp equivalent; update the
conditional checks so the throw paths are annotated with [[unlikely]] (i.e.,
mark the failing condition as unlikely when checking data.payload.empty() or
data.read_length == 0 and the builder_.write_* calls) to match the other board
implementation and maintain consistency between i2c0_write and i2c0_read error
branches.
firmware/c_board/app/src/i2c/i2c.hpp (1)

28-40: 空 payload 静默返回 vs 发送错误通知 - 建议对齐行为。

payload.empty() 时,此方法静默返回(line 29-30),而当 payload.size() > kMaxDataLength 时发送错误通知(line 32-35)。

对比 rmcs_board 版本的 handle_downlink_write(同样静默返回),两者行为一致。但从协议角度,主机端可能期望收到反馈。如果这是预期行为(空写入不是错误),可以添加注释说明设计意图。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/c_board/app/src/i2c/i2c.hpp` around lines 28 - 40, The function
handle_downlink_write currently returns silently when data.payload.empty() but
sends an error when payload.size() > kMaxDataLength, causing inconsistent host
feedback; update handle_downlink_write to either call
write_error(data.slave_address) for empty payloads to align behavior with
oversized payloads, or add a clear code comment above the empty-payload check
explaining that an empty write is intentionally treated as a no-op and not an
error (and reference write_error, kMaxDataLength, and write_blocking in the
comment to clarify the contract).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@firmware/c_board/bsp/cubemx/Core/Src/i2c.c`:
- Around line 85-88: 当前在 i2c.c 中对 I2C2 事件/错误中断使用 HAL_NVIC_SetPriority(..., 0, 0)
并启用 IRQ (HAL_NVIC_EnableIRQ(I2C2_EV_IRQn)/HAL_NVIC_EnableIRQ(I2C2_ER_IRQn)),会与
USB (OTG_FS_IRQn) 冲突且你的传输调用 HAL_I2C_Master_Transmit()/HAL_I2C_Master_Receive()
是阻塞式,不需要中断;请在配置中将 I2C2_EV_IRQn 和 I2C2_ER_IRQn 的优先级改为 HAL_NVIC_SetPriority(...,
1, 0) 或直接移除/注释掉对应的 HAL_NVIC_EnableIRQ 调用(如果不需要错误中断处理),并确保修改发生在配置 I2C2
中断的初始化函数(查找 HAL_NVIC_SetPriority / HAL_NVIC_EnableIRQ 对 I2C2 的调用处)。

In `@firmware/rmcs_board/app/src/i2c/i2c.hpp`:
- Around line 58-60: handle_downlink_read_config currently silently returns when
data.read_length is 0 or > kMaxDataLength; change this to send the same I2C
error notification the c_board implementation uses instead of silent return. In
the handle_downlink_read_config function (and when validating
data::I2cReadConfigView.read_length against kMaxDataLength) emit the I2C error
notification/response (use the project’s existing notify/send I2C error API used
by the c_board codebase) with a descriptive error reason before returning so the
host receives the error feedback.
- Around line 32-56: handle_downlink_write currently omits a payload size limit
check: before using data.payload in i2c_master_write/i2c_master_address_write
validate that data.payload.size() <= kMaxDataLength (same limit used in
c_board), and if it exceeds, call
usb::get_serializer().write_i2c_error(data_id_, data.slave_address) (assert on
non-kInvalidArgument like existing error paths) and return; reference symbols:
handle_downlink_write, data::I2cDataView, kMaxDataLength, write_i2c_error,
data_id_.

In `@firmware/rmcs_board/bsp/hpm_sdk`:
- Line 1: 回退移除了 GPIO 初始化(board_init_gpio_pins)和 Flash/XPI 配置,可能破坏依赖于 GPIO 状态的
HAL I2C 传输;请在 PR 中补充回退原因与兼容性评估、并在代码里恢复或有条件调用
board_init_gpio_pins()(或提供替代初始化路径)以保证 I2C 初始化/传输和中断处理行为一致;在本地或 CI 运行覆盖性验证:1) 验证
HAL I2C init/transfer 在无 board_init_gpio_pins 情况下是否失败;2) 验证中断和 I/O 线路的电平/复用设置;3)
恢复或迁移 Flash/XPI NOR board 配置并记录任何行为差异;在 PR 描述中列出对比 a82a5354 与 132349c9
的差异、测试结果和最终决定(恢复、条件初始化或明确不兼容)。

---

Nitpick comments:
In `@firmware/c_board/app/src/app.cpp`:
- Line 86: 在调用 i2c::i2c0->update() 的位置(当前在 app.cpp 第 86
行)明确说明这是一处空实现的保留扩展点:在调用旁边添加注释,注明 i2c::I2C::update() 在
firmware/c_board/app/src/i2c/i2c.hpp
中目前为空实现、用于未来扩展或平台特定实现,并指明不要删除或误以为是忘写逻辑;同时报错/断言等不可行时保持调用以便兼容未来实现。

In `@firmware/c_board/app/src/i2c/i2c.hpp`:
- Around line 28-40: The function handle_downlink_write currently returns
silently when data.payload.empty() but sends an error when payload.size() >
kMaxDataLength, causing inconsistent host feedback; update handle_downlink_write
to either call write_error(data.slave_address) for empty payloads to align
behavior with oversized payloads, or add a clear code comment above the
empty-payload check explaining that an empty write is intentionally treated as a
no-op and not an error (and reference write_error, kMaxDataLength, and
write_blocking in the comment to clarify the contract).

In `@host/include/librmcs/agent/rmcs_board.hpp`:
- Around line 75-85: The error branches in PacketBuilder::i2c0_write and
PacketBuilder::i2c0_read lack the [[unlikely]] attribute used in the c_board.hpp
equivalent; update the conditional checks so the throw paths are annotated with
[[unlikely]] (i.e., mark the failing condition as unlikely when checking
data.payload.empty() or data.read_length == 0 and the builder_.write_* calls) to
match the other board implementation and maintain consistency between i2c0_write
and i2c0_read error branches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 99e630ac-7991-4c1f-89de-584c2a600765

📥 Commits

Reviewing files that changed from the base of the PR and between e9675db and 12bce2b.

📒 Files selected for processing (26)
  • .codex
  • core/include/librmcs/data/datas.hpp
  • core/src/protocol/deserializer.cpp
  • core/src/protocol/deserializer.hpp
  • core/src/protocol/protocol.hpp
  • core/src/protocol/serializer.hpp
  • firmware/c_board/app/src/app.cpp
  • firmware/c_board/app/src/i2c/i2c.hpp
  • firmware/c_board/app/src/usb/vendor.hpp
  • firmware/c_board/bsp/cubemx/Core/Inc/i2c.h
  • firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h
  • firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h
  • firmware/c_board/bsp/cubemx/Core/Src/gpio.c
  • firmware/c_board/bsp/cubemx/Core/Src/i2c.c
  • firmware/c_board/bsp/cubemx/Core/Src/main.c
  • firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c
  • firmware/c_board/bsp/cubemx/cmake/stm32cubemx/CMakeLists.txt
  • firmware/c_board/bsp/cubemx/rmcs_slave.ioc
  • firmware/rmcs_board/app/src/app.cpp
  • firmware/rmcs_board/app/src/i2c/i2c.hpp
  • firmware/rmcs_board/app/src/usb/vendor.hpp
  • firmware/rmcs_board/bsp/hpm_sdk
  • host/include/librmcs/agent/c_board.hpp
  • host/include/librmcs/agent/rmcs_board.hpp
  • host/include/librmcs/protocol/handler.hpp
  • host/src/protocol/handler.cpp

Comment on lines +85 to +88
HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 检查其他外设的中断优先级配置
echo "=== 检查 c_board BSP 中其他外设的中断优先级 ==="
rg "HAL_NVIC_SetPriority" firmware/c_board/bsp/cubemx/ --type c -n

echo ""
echo "=== 检查 I2C 模块是否使用阻塞式或中断式传输 ==="
rg "HAL_I2C_(Master_Transmit|Master_Receive)" firmware/c_board/app/src/i2c/ --type cpp -n -A 2

Repository: Alliance-Algorithm/librmcs

Length of output: 2522


I2C2 中断优先级与 USB 冲突,且阻塞式传输不需要中断。

I2C2 事件和错误中断配置优先级 (0, 0) 与 USB OTG (OTG_FS_IRQn) 共享最高优先级,可能导致中断竞争。同时,代码在 firmware/c_board/app/src/i2c/i2c.hpp 中使用 HAL_I2C_Master_Transmit()HAL_I2C_Master_Receive() 等阻塞式传输函数(polling 模式),不需要启用中断来完成传输控制。建议将 I2C2 中断优先级降低至 (1, 0) 以避免与 USB 冲突,或如果中断仅用于错误处理且该功能可通过其他机制实现,考虑禁用这些中断。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/c_board/bsp/cubemx/Core/Src/i2c.c` around lines 85 - 88, 当前在 i2c.c
中对 I2C2 事件/错误中断使用 HAL_NVIC_SetPriority(..., 0, 0) 并启用 IRQ
(HAL_NVIC_EnableIRQ(I2C2_EV_IRQn)/HAL_NVIC_EnableIRQ(I2C2_ER_IRQn)),会与 USB
(OTG_FS_IRQn) 冲突且你的传输调用 HAL_I2C_Master_Transmit()/HAL_I2C_Master_Receive()
是阻塞式,不需要中断;请在配置中将 I2C2_EV_IRQn 和 I2C2_ER_IRQn 的优先级改为 HAL_NVIC_SetPriority(...,
1, 0) 或直接移除/注释掉对应的 HAL_NVIC_EnableIRQ 调用(如果不需要错误中断处理),并确保修改发生在配置 I2C2
中断的初始化函数(查找 HAL_NVIC_SetPriority / HAL_NVIC_EnableIRQ 对 I2C2 的调用处)。

Comment on lines +32 to +56
void handle_downlink_write(const data::I2cDataView& data) {
if (data.payload.empty())
return;

const auto* payload = reinterpret_cast<const uint8_t*>(data.payload.data());
hpm_stat_t status = status_fail;
if (data.has_register) {
uint8_t reg_address = data.reg_address;
status = i2c_master_address_write(
i2c_base_, data.slave_address, &reg_address, sizeof(reg_address),
const_cast<uint8_t*>(payload), static_cast<uint32_t>(data.payload.size()));
} else {
status = i2c_master_write(
i2c_base_, data.slave_address, const_cast<uint8_t*>(payload),
static_cast<uint32_t>(data.payload.size()));
}

if (status != status_success) {
auto& serializer = usb::get_serializer();
core::utility::assert_always(
serializer.write_i2c_error(data_id_, data.slave_address)
!= core::protocol::Serializer::SerializeResult::kInvalidArgument);
return;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

缺少 payload 大小上限验证。

c_board 版本在 handle_downlink_write 中验证 payload.size() > kMaxDataLength 并发送错误通知(firmware/c_board/app/src/i2c/i2c.hpp lines 32-35),但此实现缺少该检查。

如果 payload 超过 511 字节,传输可能会失败或产生未定义行为。建议添加与 c_board 一致的验证逻辑。

🛡️ 建议添加大小验证
 void handle_downlink_write(const data::I2cDataView& data) {
     if (data.payload.empty())
         return;

+    if (data.payload.size() > kMaxDataLength) {
+        auto& serializer = usb::get_serializer();
+        core::utility::assert_always(
+            serializer.write_i2c_error(data_id_, data.slave_address)
+            != core::protocol::Serializer::SerializeResult::kInvalidArgument);
+        return;
+    }
+
     const auto* payload = reinterpret_cast<const uint8_t*>(data.payload.data());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/rmcs_board/app/src/i2c/i2c.hpp` around lines 32 - 56,
handle_downlink_write currently omits a payload size limit check: before using
data.payload in i2c_master_write/i2c_master_address_write validate that
data.payload.size() <= kMaxDataLength (same limit used in c_board), and if it
exceeds, call usb::get_serializer().write_i2c_error(data_id_,
data.slave_address) (assert on non-kInvalidArgument like existing error paths)
and return; reference symbols: handle_downlink_write, data::I2cDataView,
kMaxDataLength, write_i2c_error, data_id_.

Comment on lines +58 to +60
void handle_downlink_read_config(const data::I2cReadConfigView& data) {
if (data.read_length == 0 || data.read_length > kMaxDataLength)
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

无效 read_length 时应发送错误通知而非静默返回。

read_length == 0> kMaxDataLength 时,此实现静默返回(line 59-60),但 c_board 版本会发送 I2C 错误通知给主机(firmware/c_board/app/src/i2c/i2c.hpp lines 43-46)。

这种不一致可能导致主机端在不同板子上收到不同的错误反馈行为。

🛡️ 建议添加错误通知
 void handle_downlink_read_config(const data::I2cReadConfigView& data) {
-    if (data.read_length == 0 || data.read_length > kMaxDataLength)
+    if (data.read_length == 0 || data.read_length > kMaxDataLength) {
+        auto& serializer = usb::get_serializer();
+        core::utility::assert_always(
+            serializer.write_i2c_error(data_id_, data.slave_address)
+            != core::protocol::Serializer::SerializeResult::kInvalidArgument);
         return;
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/rmcs_board/app/src/i2c/i2c.hpp` around lines 58 - 60,
handle_downlink_read_config currently silently returns when data.read_length is
0 or > kMaxDataLength; change this to send the same I2C error notification the
c_board implementation uses instead of silent return. In the
handle_downlink_read_config function (and when validating
data::I2cReadConfigView.read_length against kMaxDataLength) emit the I2C error
notification/response (use the project’s existing notify/send I2C error API used
by the c_board codebase) with a descriptive error reason before returning so the
host receives the error feedback.

@@ -1 +1 @@
Subproject commit a82a53544d5679a43b70f390c8bbbb8e91f6b8c1
Subproject commit 132349c9ddad3cbeca7211345d5d6086355f20b9
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Submodule pointer change =="
git diff --submodule=log origin/main...HEAD -- firmware/rmcs_board/bsp/hpm_sdk || true

echo
echo "== .gitmodules entry =="
sed -n '/firmware\/rmcs_board\/bsp\/hpm_sdk/,+5p' .gitmodules || true

echo
echo "== Old/New gitlinks =="
echo "[origin/main]"
git ls-tree origin/main -- firmware/rmcs_board/bsp/hpm_sdk || true
echo
echo "[HEAD]"
git ls-tree HEAD -- firmware/rmcs_board/bsp/hpm_sdk || true

Repository: Alliance-Algorithm/librmcs

Length of output: 676


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check if hpm_sdk submodule is initialized =="
if [ -d "firmware/rmcs_board/bsp/hpm_sdk/.git" ]; then
  echo "✓ Submodule is initialized"
  
  cd firmware/rmcs_board/bsp/hpm_sdk
  echo
  echo "== Commit log between old and new commit =="
  git log --oneline a82a53544d5679a43b70f390c8bbbb8e91f6b8c1..132349c9ddad3cbeca7211345d5d6086355f20b9 || true
  echo
  
  echo "== Detailed commit info for new commit =="
  git show --stat 132349c9ddad3cbeca7211345d5d6086355f20b9 | head -100 || true
  
else
  echo "✗ Submodule not initialized locally"
  echo "Submodule path: firmware/rmcs_board/bsp/hpm_sdk"
fi

Repository: Alliance-Algorithm/librmcs

Length of output: 201


🌐 Web query:

site:github.com/Alliance-Algorithm/hpm_sdk compare a82a53544d5679a43b70f390c8bbbb8e91f6b8c1...132349c9ddad3cbeca7211345d5d6086355f20b9

💡 Result:

GitHub shows no changes to compare between these commits: a82a5354... already contains all commits from 132349c9... (i.e., 132349c9... is behind / an ancestor of a82a5354...). (github.com)

If you want to see the reverse difference, switch the base/head (compare 132349c9... as base against a82a5354... as head). (github.com)

Citations:


🌐 Web query:

site:github.com/Alliance-Algorithm/hpm_sdk compare 132349c9ddad3cbeca7211345d5d6086355f20b9...a82a53544d5679a43b70f390c8bbbb8e91f6b8c1

💡 Result:

Comparison 132349c9ddad3cbeca7211345d5d6086355f20b9...a82a53544d5679a43b70f390c8bbbb8e91f6b8c1 in Alliance-Algorithm/hpm_sdk contains 1 commit (“iter1”, committed Mar 31, 2026 by qzhhhi), touching 2 files with +13 / -3 lines. GitHub couldn’t render the full compare view (“taking too long to generate”), but the commit diff is visible. [1][2]

Changes:

  • boards/hpm5300evk/board.c: adds a new function board_init_gpio_pins() that sets the app GPIO pin as input via gpio_set_pin_input(...). [2]
  • boards/hpm5300evk/board.h:
    • adds board flash/XPI NOR related defines: BOARD_FLASH_BASE_ADDRESS, BOARD_FLASH_SIZE, BOARD_APP_XPI_NOR_XPI_BASE, and BOARD_APP_XPI_NOR_CFG_OPT_*. [2]
    • changes the board_init_gpio_pins declaration from commented-out to enabled (void board_init_gpio_pins(void);). [2]

Sources: [1] compare view, [2] commit a82a535 diff.


这是版本回退,移除了 GPIO 初始化代码——需要明确说明回退原因和兼容性影响。

这次变更并非升级,而是从 a82a5354 回退到其祖先 132349c9。被回退的 commit(2026-03-31)移除了:

  • board_init_gpio_pins() 函数及其 GPIO 初始化逻辑
  • Flash/XPI NOR 相关的 board 配置定义

当前 PR 直接依赖 HAL I2C 传输,如果 I2C 初始化或数据线依赖于 board_init_gpio_pins() 的 GPIO 状态配置,这个回退可能导致 I2C 传输失败。PR 缺少:

  • 说明为什么需要此次回退
  • GPIO 初始化被移除后的兼容性验证
  • I2C/中断处理与 GPIO 初始化间的依赖关系说明

请补充这些信息或在本地完整验证后再提交。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/rmcs_board/bsp/hpm_sdk` at line 1, 回退移除了 GPIO
初始化(board_init_gpio_pins)和 Flash/XPI 配置,可能破坏依赖于 GPIO 状态的 HAL I2C 传输;请在 PR
中补充回退原因与兼容性评估、并在代码里恢复或有条件调用 board_init_gpio_pins()(或提供替代初始化路径)以保证 I2C
初始化/传输和中断处理行为一致;在本地或 CI 运行覆盖性验证:1) 验证 HAL I2C init/transfer 在无
board_init_gpio_pins 情况下是否失败;2) 验证中断和 I/O 线路的电平/复用设置;3) 恢复或迁移 Flash/XPI NOR
board 配置并记录任何行为差异;在 PR 描述中列出对比 a82a5354 与 132349c9
的差异、测试结果和最终决定(恢复、条件初始化或明确不兼容)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant