API GUIDE / PWM / OVERVIEW

G32S10 PWM API 概述

模块概述:本文档定义 G32S10 SDK 当前 PWM 模块的正式接口,覆盖以下两层:

1. 文档范围

本文档定义 G32S10 SDK 当前 PWM 模块的正式接口,覆盖以下两层:

  • HAL PWM:面向应用、BSP和驱动上层的功能级接口

  • LL PWM:面向寄存器与位操作的低层接口

本文档基于以下实现与头文件编写:

  • code/include/drivers/g32s10/pwm/hal_pwm.h

  • code/include/drivers/g32s10/pwm/ll_pwm.h

  • code/include/drivers/g32s10/pwm/pwm_regs.h

  • code/drivers/g32s10/pwm/hal_pwm.c

补充说明:

  • LL层不返回状态码;读取寄存器值或状态时返回 uint32_t 或 bool

  • HAL层负责参数校验、状态管理、组合配置和中断回调分发

  • PWM输出引脚复用和输入时钟配置由BSP或调用方负责

  • 平台IRQ由上层调用者注册

2. 分层关系

APPLICATION  Application / BSP / Driver  业务代码、板级支持与示例入口
↓
HAL  HAL PWM  模块级配置、状态管理与硬件访问
↓
LL  LL PWM  寄存器访问与字段级控制
↓
HARDWARE REGISTERS  PWM Registers  实例地址、寄存器布局与位域定义

分层职责如下:

  • HAL PWM

    • 维护 hal_pwm_handle_t、生命周期状态和callback

    • 检查实例、group、枚举、配置结构和输出指针

    • 提供波形、ADC trigger、Global、Fail和中断管理接口

  • LL PWM

    • 提供寄存器位和字段访问入口

    • 使用group index或group mask直接操作硬件

    • 不维护软件状态,不检查业务参数

  • pwm_regs.h

    • 定义PWM实例、寄存器结构体、访问属性和位域宏

3. 资源模型与公开类型

3.1 PWM硬件资源

项目说明
PWM group共8个group,编号为0至7
PWM输出每个group包含一对P/N输出,共16路物理输出
group共享资源P/N共享时钟分频、波形模式、周期计数器和参数更新域
P/N独立资源阈值、死区、初始电平、空闲电平、OSCR和Fail默认输出可分别配置
ADC trigger每个group提供两个事件阈值;四个ADC trigger endpoint可独立选择group
Global暂停指定group的内部计数,解除后从原位置继续
Fail支持IO Fail和ADC Fail,状态与中断按每个group 2 bit组织
中断主IRQ处理ADC event、Global和Fail;update使用独立IRQ

3.2 HAL返回值

HAL层普通可失败接口统一返回SDK公共错误码类型:

error_code_t

常用返回值如下:

返回值说明
IM_OK操作成功
IM_ERR_INVALID_PARAMhandle、instance、输出指针、group、mask、枚举或字段值非法
IM_ERR_NOT_READY常规硬件接口调用时handle未处于 HAL_PWM_STATE_READY
IM_ERR_BUSYgroup正在工作,不能修改时钟分频、波形模式或执行完整group初始化
IM_ERR_UNSUPPORTED当前构建未使能PWM dump辅助能力

HAL不等待 CLK_BUSY 或 PARAM_BUSY 清零,因此update接口不返回timeout。

4. 当前实现约束与行为说明

4.1 PWM组与输出资源

资源数量/范围HAL配置粒度说明
PWM组8组,0至7group / groupsgroup选择单个组;groups按bit0至bit7选择多个组。
P/N输出每组2路,共16路组内P/N参数P/N共享时钟分频、波形模式、周期和参数更新域;阈值、死区、电平、OSCR和FAIL默认输出可分别配置。

4.2 波形参数与更新

参数位宽/范围HAL行为
周期计数值16位,0至0xFFFF由 hal_pwm_set_period_count() 或参数结构体写入。
P/N阈值每项16位,0至0xFFFF单项setter只写寄存器,修改后需显式触发波形参数更新。
P/N死区每项16位,0至0xFFFF单项setter不允许写0;初始化和参数配置在中心对齐模式下会为0值补默认死区。
当前计数值17位,只读通过 hal_pwm_get_counter() 读取,不由HAL写入。
  • hal_pwm_init() 只初始化软件handle;组配置、参数更新和输出启动由后续接口显式完成。

  • 运行中修改周期、阈值、死区或OSCR后,调用 hal_pwm_compare_param_update();修改ADC触发阈值后,调用 hal_pwm_event_param_update()。

  • HAL不检查 CLK_BUSY 或 PARAM_BUSY,也不等待更新完成;需要观察完成状态时使用LL busy查询或参数更新中断。

  • hal_pwm_group_init()、hal_pwm_set_clk_div() 和 hal_pwm_set_wave_mode() 在目标PWM组工作时返回 IM_ERR_BUSY。

4.3 ADC触发、Global与FAIL

功能配置范围行为约束
ADC触发时序每组两个阈值ADC事件计数器需单独使能;运行中修改阈值后需触发ADC事件参数更新。
ADC触发路径4个ADC触发端点每个端点对应一个PWM组;路径配置不等同于调试输出配置。
ADC调试输出每个触发端点一个调试IO和共享hold countHAL只配置PWM路由,不配置GPIO复用;IO0至IO3的引脚复用由BSP负责。
Global按PWM组暂停内部计数;解除后从暂停位置继续,不等同于FAIL急停。
FAIL每组IO FAIL和ADC FAILFAIL可与ADC触发同时生效;valid_level和filter_div只对IO FAIL起效。

Global暂停时FAIL仍可生效。FAIL触发后的软复位、波形重配和 CNTEN 恢复由上层流程负责,HAL不自动完成恢复流程。

4.4 文件组织

code/include/drivers/g32s10/pwm/
  pwm_regs.h
  ll_pwm.h
  hal_pwm.h
code/drivers/g32s10/pwm/
  hal_pwm.c

文件职责:

文件说明
pwm_regs.hPWM实例、寄存器结构、访问属性和位域宏。
ll_pwm.hLL层 static inline API定义、寄存器访问。
hal_pwm.hHAL 类型、结构体和公开声明。
hal_pwm.cHAL层参数校验、handle 状态、组合配置、IRQ 分发和 dump。

4.5 实现约束

  • LL层只封装寄存器访问,公开接口均为 static inline;不维护软件状态,不依赖RTOS,不申请内存,不记录日志,也不串行化寄存器读改写。

  • HAL层使用调用方提供的 hal_pwm_handle_t,依赖公共错误码和参数检查组件,不动态分配内存且不依赖RTOS;当前 IS_PWM_ALL_INSTANCE() 只接受单个硬件实例 PWM。

  • HAL层不提供内部锁。共享寄存器、分步配置与更新、callback表被多个执行上下文并发访问时,调用方必须完成同步。

  • PWM输出引脚复用和输入时钟由BSP或调用方配置。

  • 平台IRQ由上层调用者注册,两个PWM IRQ分别使用主中断和参数更新中断handler。

  • callback注册接口和两个IRQ handler只要求handle及instance合法,不要求 HAL_PWM_STATE_READY;常规硬件配置接口按各自说明检查READY状态。

  • HAL层不轮询时钟或参数更新busy状态,不重试被硬件忽略的更新触发;需要确认完成时,由调用方读取LL busy状态或使用参数更新中断。

  • 寄存器dump依赖日志组件,并受 CONFIG_SDK_ENABLE_DEBUG_HELPERS 和 CONFIG_PWM_ENABLE_DEBUG_HELPERS 共同控制;关闭任一开关时返回 IM_ERR_UNSUPPORTED。

5. 典型用法

5.1 单 group 普通输出

#include "hal_pwm.h"

hal_pwm_handle_t s_pwm;
hal_pwm_init_config_t config = {
    .clk_div = HAL_PWM_CLK_DIV_8,
    .mode = HAL_PWM_MODE_EDGE_ALIGNED,
    .param = {
        .period_count = 1000U,
        .p_threshold = 250U,
        .n_threshold = 750U,
        .p_dead_time = 0U,
        .n_dead_time = 0U,
    },
};

error_code_t pwm_group0_start(void)
{
    error_code_t ret;

    ret = hal_pwm_init(&s_pwm, PWM);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_group_init(&s_pwm, HAL_PWM_GROUP_0, &config);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_compare_param_update(&s_pwm, HAL_PWM_GROUP_0);
    if (ret != IM_OK) {
        return ret;
    }

    return hal_pwm_enable(&s_pwm, HAL_PWM_GROUP_0);
}

示例不包含 PWM 输入时钟和输出 GPIO pinmux 配置,BSP 必须在启动前完成。

5.2 运行期同步修改多个波形参数

const hal_pwm_param_config_t param = {
    .period_count = 2000U,
    .p_threshold = 800U,
    .n_threshold = 1200U,
    .p_dead_time = 10U,
    .n_dead_time = 10U,
};

error_code_t pwm_group0_update(void)
{
    error_code_t ret;

    ret = hal_pwm_param_config(&s_pwm, HAL_PWM_GROUP_0, &param);
    if (ret != IM_OK) {
        return ret;
    }

    return hal_pwm_compare_param_update(&s_pwm, HAL_PWM_GROUP_0);
}

若多个执行上下文可能同时操作 PWM,调用方应在 hal_pwm_param_config() 到 hal_pwm_compare_param_update() 的完整区间外加锁。

5.3 ADC trigger 与 callback

void pwm_event_callback(hal_pwm_handle_t *hpwm, uint32_t pending_groups)
{
    void *context = hpwm->user_data;

    (void)context;
    (void)pending_groups;
}

error_code_t pwm_adc_trigger_setup(void *context)
{
    error_code_t ret;

    s_pwm.user_data = context;

    ret = im_irq_request(IRQ_PWM,
                         hal_pwm_irq_handler,
                         "pwm adc trigger",
                         &s_pwm);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_register_irq_callback(&s_pwm,
                                        HAL_PWM_IRQ_TYPE_EVENT,
                                        pwm_event_callback);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_adc_trigger_path_config(&s_pwm,
                                          HAL_PWM_ADC0_TRIGGER0,
                                          HAL_PWM_GROUP_0);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_adc_trigger_timing_config(&s_pwm,
                                            HAL_PWM_GROUP_0,
                                            250U,
                                            750U);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_event_param_update(&s_pwm, HAL_PWM_GROUP_0);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_clear_adc_trigger_interrupt_status(&s_pwm,
                                                      HAL_PWM_GROUP_0);
    if (ret != IM_OK) {
        return ret;
    }

    ret = hal_pwm_adc_trigger_interrupt_unmask(&s_pwm, HAL_PWM_GROUP_0);
    if (ret != IM_OK) {
        return ret;
    }

    ret = im_irq_enable(IRQ_PWM);
    if (ret != IM_OK) {
        return ret;
    }

    return hal_pwm_event_enable(&s_pwm, HAL_PWM_GROUP_0);
}

im_irq_request()由上层调用者完成平台IRQ注册,并将 &s_pwm 作为 user_ctx 传给 hal_pwm_irq_handler()。应在解除PWM中断mask并清除历史状态后使能平台IRQ,再启动ADC事件计数器。

6. 推荐关注的错误码

场景建议处理
IM_ERR_INVALID_PARAM检查 group 是否只有一个 bit、groups 是否只含 bit0至7、输出指针和枚举是否有效。
IM_ERR_NOT_READY检查是否已调用 hal_pwm_init(),或 handle 是否因 hal_pwm_soft_reset() 进入 RESET。
IM_ERR_BUSY先停止目标 group,再修改 divider、wave mode 或重新执行 group init。
IM_ERR_UNSUPPORTED开启 SDK 与 PWM 两级 debug helper 配置,或不要调用 dump。

对于硬件 update 被 busy 状态忽略的情况,HAL trigger 仍返回 IM_OK。调用方应结合 LL busy 查询、update interrupt、寄存器 dump 或示波器波形确认实际生效情况。