Skip to content

feat(gpio): Add GPIO PWM write support and implement for c_board#34

Merged
qzhhhi merged 2 commits intomainfrom
dev/gpio-pwm
Mar 9, 2026
Merged

feat(gpio): Add GPIO PWM write support and implement for c_board#34
qzhhhi merged 2 commits intomainfrom
dev/gpio-pwm

Conversation

@qzhhhi
Copy link
Member

@qzhhhi qzhhhi commented Mar 9, 2026

  • Define GPIO digital/analog write protocol (header, serializer, deserializer) with read variants reserved for future work.
  • Expose gpio_digital_transmit / gpio_analog_transmit in host CBoard agent.
  • Map c_board channels 1–7 to TIM1 CH1–4 and TIM8 CH1–3 PWM outputs at 50 Hz.

GPIO PWM 写入支持与 c_board 实现(更新)

功能概述

本 PR 为库增加了端到端的 GPIO 写入支持(数字与模拟/PWM),包含协议定义、序列化/反序列化接口、主机侧传输封装以及 c_board 固件上的 PWM 驱动实现(通道映射 TIM1 CH1–4 与 TIM8 CH1–3,共 7 通道,工作于 50 Hz)。

核心变更

协议层(core)

  • 新增数据视图类型:
    • data::GpioDigitalDataView { uint8_t channel; bool high; }
    • data::GpioAnalogDataView { uint8_t channel; uint16_t value; }
  • 新增协议位域:
    • GpioHeader:4 位 payload 枚举 + 8 位 channel(包含 kDigitalWriteLow/High、kAnalogWrite 等,读/读结果类型已预留)
    • GpioAnalogPayload:承载 16 位 PWM 值
  • 序列化:
    • Serializer 增加 write_gpio_digital / write_gpio_analog,并新增 required_gpio_size 辅助函数用于长度计算与校验
  • 反序列化:
    • Deserializer 处理 FieldId::kGpio,新增 process_gpio_field,按 payload 类型解析并通过回调分发
    • DeserializeCallback 接口新增 gpio_digital_deserialized_callback 与 gpio_analog_deserialized_callback

主机 API(host)

  • CBoard::PacketBuilder 新增:
    • gpio_digital_transmit(const data::GpioDigitalDataView&):对通道(1–7)做范围校验(违规抛 std::invalid_argument),并构建 GPIO 数据信封发送
    • gpio_analog_transmit(const data::GpioAnalogDataView&):同上,含通道校验
  • 协议处理器(PacketBuilder / PacketBuilderImpl)暴露 write_gpio_digital / write_gpio_analog 接口,反向路径新增相应的反序列化回调(在非 c_board 主机实现中默认记录/忽略)

c_board 固件实现(firmware/c_board)

  • 新增 Gpio 类(firmware/c_board/app/src/gpio/gpio.hpp):
    • 管理 7 个 PWM 通道,维护 7 个 CCR 指针(TIM1 CH1–4、TIM8 CH1–3)
    • kCounterPeriod = 60000(配合 TIM 配置以实现 50 Hz)
    • duty_to_compare 函数将 16 位值映射到 CCR;set_compare 做边界检查
    • handle_digital_write:根据 high 标志设置为满占空比或 0
    • handle_analog_write:直接按值设置占空比
    • 全局延迟初始化实例 inline constinit Gpio::Lazy gpio
  • 在 app 初始化中调用 MX_TIM1_Init(), MX_TIM8_Init() 并执行 gpio::gpio.init()
  • USB Vendor 回调(firmware/c_board/app/src/usb/vendor.hpp)将反序列化的 GPIO 数据转发给 gpio 驱动

HAL / 硬件配置

  • 将 c_board 上的 7 路 PWM 引脚宏添加到 main.h(PWM1–PWM7)
  • tim.h 声明并暴露 TIM_HandleTypeDef htim1, htim8 以及 MX_TIM1_Init / MX_TIM8_Init
  • tim.c 实现 TIM1/TIM8 的初始化、MSP 与后置 GPIO 配置,新增对 TIM1/TIM8 的 MSP Init/DeInit 支持(大量新增代码)
  • gpio.c 在 MX_GPIO_Init 中启用 GPIOI 和 GPIOE 时钟
  • CubeMX 项目文件(rmcs_slave.ioc)更新:引脚/外设映射扩展以支持 TIM1/TIM8 与新增 PWM 引脚(管脚数量与映射改动明显)

rmcs_board

  • 在 firmware/rmcs_board 中添加了空实现的 gpio_digital_deserialized_callback 与 gpio_analog_deserialized_callback,以保持接口兼容(不执行操作,仅避免未使用参数警告)

设计要点与兼容性

  • 协议中预留读操作与读结果载荷,便于后续扩展读取功能
  • 从主机到固件形成完整链路:主机序列化 → 传输 → 固件反序列化 → PWM 驱动
  • 通道映射明确为 1..7,主机侧与固件侧都做了范围/边界检查
  • 固件选用 50 Hz 基准(ARR/计数周期 = 60000),适用于舵机/低频 PWM 场景

- Define GPIO digital/analog write protocol (header, serializer, deserializer) with read variants reserved for future work.
- Expose gpio_digital_transmit / gpio_analog_transmit in host CBoard agent.
- Map c_board channels 1–7 to TIM1 CH1–4 and TIM8 CH1–3 PWM outputs at 50 Hz.
@qzhhhi
Copy link
Member Author

qzhhhi commented Mar 9, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b70f8bdb-9cee-4686-844d-c07aabd717d9

📥 Commits

Reviewing files that changed from the base of the PR and between f3557a6 and 1b3b6a0.

📒 Files selected for processing (1)
  • firmware/c_board/app/src/gpio/gpio.cpp

Walkthrough

在仓库中引入对 GPIO 的端到端支持:新增数据视图、协议位域、序列化/反序列化处理、固件端 PWM/GPIO 管理及定时器(TIM1/TIM8)配置,并在主机与固件之间添加相应的传输/回调接口与集成点。

Changes

Cohort / File(s) Summary
数据视图 & 协议
core/include/librmcs/data/datas.hpp, core/src/protocol/protocol.hpp
新增 GpioDigitalDataViewGpioAnalogDataView;新增 GpioHeaderGpioAnalogPayload 协议位域以描述 GPIO 有效载荷与通道。
序列化器
core/src/protocol/serializer.hpp
新增 write_gpio_digitalwrite_gpio_analog 接口及内部 required_gpio_size 计算逻辑,用于构造 GPIO 字段的序列化输出。
反序列化器
core/src/protocol/deserializer.hpp, core/src/protocol/deserializer.cpp
新增 process_gpio_field 实现并在流程中路由 FieldId::kGpio;在回调接口中加入 gpio_digital_deserialized_callbackgpio_analog_deserialized_callback
主机端 API / Handler
host/include/librmcs/agent/c_board.hpp, host/include/librmcs/protocol/handler.hpp, host/src/protocol/handler.cpp
为 PacketBuilder/Handler 添加 gpio_digital_transmit/gpio_analog_transmit 与 write_gpio_digital/write_gpio_analog 的写入路径,并新增反序列化回调的主机端实现(日志/错误处理)。
固件 GPIO 管理器
firmware/c_board/app/src/gpio/gpio.hpp, firmware/c_board/app/src/gpio/gpio.cpp
新增 Gpio 管理类,初始化 TIM1/TIM8 的 PWM 通道映射(7 通道),提供 handle_digital_write 与 handle_analog_write,包含占空比到 CCR 的映射与边界检查。
固件集成与 USB 回调
firmware/c_board/app/src/app.cpp, firmware/c_board/app/src/usb/vendor.hpp, firmware/rmcs_board/src/usb/vendor.hpp
在固件启动中初始化 TIM1/TIM8 并调用 gpio.init();在 c_board 的 USB Vendor 中将 GPIO 反序列化回调路由到 gpio 管理器;在 rmcs_board 中添加空实现以静默未使用参数。
定时器与板级设置
firmware/c_board/bsp/cubemx/Core/Inc/tim.h, .../Core/Src/tim.c, .../Core/Inc/main.h, .../Core/Src/gpio.c, firmware/c_board/bsp/cubemx/rmcs_slave.ioc
引入 TIM1 和 TIM8 的 extern handle 与 MX_TIM1_Init/MX_TIM8_Init,添加对应 HAL MSP 配置、PWM 管脚宏(PWM1..PWM7)及 GPIO 时钟使能;更新 CubeMX 工程以包含新 PWM 通道与引脚映射。

Sequence Diagram(s)

sequenceDiagram
    participant Host as Host (应用)
    participant Serializer as Serializer
    participant USB as USB/Vendor
    participant Deser as Deserializer
    participant Vendor as Vendor 回调
    participant GPIO as 固件 GPIO 管理器
    participant PWM as PWM 硬件

    Host->>Serializer: 构造并发送 GPIO 字段 (Digital/Analog)
    Serializer->>USB: 发送字节流
    USB->>Deser: 接收并调用 process_stream (FieldId::kGpio)
    Deser->>Deser: 解析 GpioHeader (PayloadType, Channel)
    alt DigitalWrite
        Deser->>Vendor: gpio_digital_deserialized_callback(GpioDigitalDataView)
    else AnalogWrite
        Deser->>Vendor: gpio_analog_deserialized_callback(GpioAnalogDataView)
    end
    Vendor->>GPIO: handle_digital_write / handle_analog_write
    GPIO->>GPIO: 验证通道,计算 CCR 值
    GPIO->>PWM: 更新 CCR 寄存器(输出 PWM)
    PWM-->>GPIO: PWM 输出生效
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 分钟

Possibly related PRs

诗歌

🐰 在电路间跳跃我轻轻颤动,
七条通道奏起 PWM 的歌,
协议与回调手牵着硬件的梦,
兔子用占空比绘出光的节奏,
数字与模拟在板上互相问候。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.54% 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 标题清晰准确地概括了主要变更:为c_board添加GPIO PWM写入支持功能。

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev/gpio-pwm

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.

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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.

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

1-9: Include 顺序可优化

根据项目的 Google C++ Include Style 规范,建议调整顺序:对应头文件 → C 系统头文件 → C++ 标准库头文件 → 其他库头文件 → 项目头文件。

建议的 include 顺序
 `#include` "firmware/c_board/app/src/gpio/gpio.hpp"

-#include <cstdint>
-
 `#include` <main.h>
 `#include` <stm32f4xx_hal_gpio.h>

+#include <cstdint>
+
 `#include` "firmware/c_board/app/src/spi/bmi088/accel.hpp"
 `#include` "firmware/c_board/app/src/spi/bmi088/gyro.hpp"

根据 learnings: "In the librmcs project, enforce Google C++ Include Style in all C++ source files."

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

In `@firmware/c_board/app/src/gpio/gpio.cpp` around lines 1 - 9, Reorder the
includes in gpio.cpp to follow Google C++ style: keep the corresponding header
"firmware/c_board/app/src/gpio/gpio.hpp" first, then C system headers (e.g.,
<main.h>), then C++ standard headers (e.g., <cstdint>), then other library
headers (e.g., <stm32f4xx_hal_gpio.h>), and finally project headers such as
"firmware/c_board/app/src/spi/bmi088/accel.hpp" and
"firmware/c_board/app/src/spi/bmi088/gyro.hpp"; adjust the include block
accordingly so that gpio.hpp, <main.h>, <cstdint>, <stm32f4xx_hal_gpio.h>, then
accel.hpp and gyro.hpp appear in that order.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@firmware/c_board/app/src/gpio/gpio.cpp`:
- Around line 1-9: Reorder the includes in gpio.cpp to follow Google C++ style:
keep the corresponding header "firmware/c_board/app/src/gpio/gpio.hpp" first,
then C system headers (e.g., <main.h>), then C++ standard headers (e.g.,
<cstdint>), then other library headers (e.g., <stm32f4xx_hal_gpio.h>), and
finally project headers such as "firmware/c_board/app/src/spi/bmi088/accel.hpp"
and "firmware/c_board/app/src/spi/bmi088/gyro.hpp"; adjust the include block
accordingly so that gpio.hpp, <main.h>, <cstdint>, <stm32f4xx_hal_gpio.h>, then
accel.hpp and gyro.hpp appear in that order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 94761686-d16f-4d01-93da-d18dcccb3ac4

📥 Commits

Reviewing files that changed from the base of the PR and between a4c7ed2 and f3557a6.

📒 Files selected for processing (18)
  • 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/gpio/gpio.cpp
  • firmware/c_board/app/src/gpio/gpio.hpp
  • firmware/c_board/app/src/usb/vendor.hpp
  • firmware/c_board/bsp/cubemx/Core/Inc/main.h
  • firmware/c_board/bsp/cubemx/Core/Inc/tim.h
  • firmware/c_board/bsp/cubemx/Core/Src/gpio.c
  • firmware/c_board/bsp/cubemx/Core/Src/tim.c
  • firmware/c_board/bsp/cubemx/rmcs_slave.ioc
  • firmware/rmcs_board/src/usb/vendor.hpp
  • host/include/librmcs/agent/c_board.hpp
  • host/include/librmcs/protocol/handler.hpp
  • host/src/protocol/handler.cpp

Copy link

@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.

🧹 Nitpick comments (1)
firmware/c_board/app/src/gpio/gpio.hpp (1)

52-58: kCounterPeriod 硬编码值与定时器配置耦合,建议添加注释说明依赖关系。

kCounterPeriod = 60000 需要与 .ioc 中 TIM1/TIM8 的 Period 值(59999)保持同步,即 kCounterPeriod = Period + 1。当前值是正确的,但如果定时器配置更改,这里需要手动同步更新。

建议添加注释说明此依赖关系,或考虑从定时器寄存器动态获取 ARR 值:

📝 建议添加注释
 private:
-    static constexpr uint32_t kCounterPeriod = 60000;
+    // Must match TIM1/TIM8 ARR + 1 (configured in rmcs_slave.ioc as Period = 59999)
+    static constexpr uint32_t kCounterPeriod = 60000;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@firmware/c_board/app/src/gpio/gpio.hpp` around lines 52 - 58, kCounterPeriod
is hardcoded to 60000 but is coupled to the TIM1/TIM8 Period (59999) so it must
equal TIMx->ARR + 1; update the code to either: 1) add a clear comment next to
kCounterPeriod stating "must equal TIMx ARR + 1 (e.g. .ioc Period 59999 ->
kCounterPeriod 60000)" so future maintainers know the dependency, or 2) remove
the constexpr and read the ARR value from the timer register at init (store as a
non-constexpr member used by duty_to_compare) so it stays in sync; reference
kCounterPeriod and duty_to_compare to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@firmware/c_board/app/src/gpio/gpio.hpp`:
- Around line 52-58: kCounterPeriod is hardcoded to 60000 but is coupled to the
TIM1/TIM8 Period (59999) so it must equal TIMx->ARR + 1; update the code to
either: 1) add a clear comment next to kCounterPeriod stating "must equal TIMx
ARR + 1 (e.g. .ioc Period 59999 -> kCounterPeriod 60000)" so future maintainers
know the dependency, or 2) remove the constexpr and read the ARR value from the
timer register at init (store as a non-constexpr member used by duty_to_compare)
so it stays in sync; reference kCounterPeriod and duty_to_compare to locate the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d31e2d34-135f-4c79-838b-c4cd1394ff5a

📥 Commits

Reviewing files that changed from the base of the PR and between a4c7ed2 and f3557a6.

📒 Files selected for processing (18)
  • 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/gpio/gpio.cpp
  • firmware/c_board/app/src/gpio/gpio.hpp
  • firmware/c_board/app/src/usb/vendor.hpp
  • firmware/c_board/bsp/cubemx/Core/Inc/main.h
  • firmware/c_board/bsp/cubemx/Core/Inc/tim.h
  • firmware/c_board/bsp/cubemx/Core/Src/gpio.c
  • firmware/c_board/bsp/cubemx/Core/Src/tim.c
  • firmware/c_board/bsp/cubemx/rmcs_slave.ioc
  • firmware/rmcs_board/src/usb/vendor.hpp
  • host/include/librmcs/agent/c_board.hpp
  • host/include/librmcs/protocol/handler.hpp
  • host/src/protocol/handler.cpp

@qzhhhi qzhhhi merged commit eff14b7 into main Mar 9, 2026
5 checks passed
@github-project-automation github-project-automation bot moved this from Todo to Done in RMCS Slave SDK Mar 9, 2026
@qzhhhi qzhhhi deleted the dev/gpio-pwm branch March 9, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant