API GUIDE / AON / API OVERVIEW

AON API 概述

1. 文档范围

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

  • HAL CPM:面向应用、BSP 和驱动上层的时钟、分频、父时钟和 gate 控制接口
  • LL CPM/AON:面向 CPM/AON 寄存器与位域操作的低层接口

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

  • code/include/drivers/g32s10/cpm/hal_cpm.h
  • code/include/drivers/g32s10/cpm/cpm_regs.h
  • code/include/drivers/g32s10/cpm/ll_cpm.h
  • code/include/drivers/g32s10/cpm/ll_cdr.h
  • code/include/drivers/g32s10/cpm/ll_aon.h
  • code/include/drivers/g32s10/cpm/ll_pm.h
  • code/drivers/g32s10/cpm/hal_cpm_core.c
  • code/drivers/g32s10/cpm/hal_cpm_clk.c
  • code/drivers/g32s10/cpm/hal_cpm_pll.c
  • code/drivers/g32s10/cpm/hal_cpm_cgu.c
  • code/drivers/g32s10/cpm/hal_cpm_i2s_cgu.c
  • code/drivers/g32s10/cpm/hal_cpm_gate.c
  • code/drivers/g32s10/cpm/hal_cpm_summary.c

2. 分层关系

Application / BSP / Driver / Test
           |
           v
        HAL CPM
           |
           v
 LL CPM / LL CDR / LL AON / LL PM
           |
           v
     CPM and AON Registers

分层职责如下:

  • HAL CPM
    • 使用统一 hal_cpm_id_t 描述 clock 和 gate 资源
    • 封装 clock enable、disable、rate、parent 和 gate open/close 语义
    • 维护 clock 软件缓存,包括 parent、rate 和 clock enable 引用计数
    • 对参数进行 SDK 统一检查并返回 error_code_t
  • LL CPM/AON
    • 提供 static inline 寄存器和位域访问入口
    • 不维护软件状态,不做 clock tree 或引用计数语义
    • 不返回 SDK 错误码;读取接口返回寄存器值或 bool
  • cpm_regs.h
    • 定义 cpm_regs_t、aon_regs_t、寄存器实例宏、bit/field mask 和硬件枚举值

3. 构建配置

配置项 默认值 说明
CONFIG_DRIVER_CPM y 编译 G32S10 CPM 驱动。
CONFIG_CPM_ENABLE_STUB n 编译 CPM HAL 空实现。开启后 public HAL 符号保留,但不访问 CPM/AON 硬件。

CONFIG_CPM_ENABLE_STUB=y 时,code/drivers/g32s10/cpm/CMakeLists.txt 只编译 hal_cpm_stub.c。stub 行为如下:

接口 stub 行为
hal_cpm_init() 返回 IM_OK。
hal_cpm_clk_enable() / hal_cpm_clk_disable() / hal_cpm_clk_set_rate_hz() / hal_cpm_clk_set_parent() 参数占位后返回 IM_OK。
hal_cpm_clk_is_enabled() 输出 false,返回 IM_OK。
hal_cpm_clk_get_rate_hz() 输出 0,返回 IM_OK。
hal_cpm_clk_get_parent() 输出 HAL_CPM_ID_INVALID,返回 IM_OK。
hal_cpm_rosc2_trim() 空操作,返回 IM_OK。

4. 资源模型与公开类型

4.1 基地址与寄存器实例

CPM HAL/LL 访问两个硬件寄存器块,基地址由 base.h 提供:

#define CPM_IOBASE    0x10000000
#define AON_IOBASE    0x100CD000

cpm_regs.h 基于这两个基地址定义寄存器实例宏:

#define CPM    ((cpm_regs_t *)(uintptr_t)CPM_IOBASE)
#define AON    ((aon_regs_t *)(uintptr_t)AON_IOBASE)

其中 CPM 覆盖主 CPM 寄存器、PLL、CPCCR/CPCCR1 和各类 CDR;AON 覆盖 ROSC、LP/RT clock、AON gate 和 AON I2S CDR 等低功耗域寄存器。

4.2 统一资源 ID

CPM HAL 使用一个公开枚举类型描述 clock 和 gate:

typedef enum {
    HAL_CPM_ID_CLK_EXTAL = 0,
    ...
    HAL_CPM_ID_GATE_BASE = 0x1000U,
    ...
    HAL_CPM_ID_CLK_NONE = 0xFFFEU,
    HAL_CPM_ID_INVALID = 0xFFFFU,
} hal_cpm_id_t;

ID 空间按范围组织:

范围 说明
HAL_CPM_ID_CLK_BASE_BEGIN ~ HAL_CPM_ID_CLK_BASE_END - 1 根时钟、主时钟、LPCLK 和 RTCLK。
HAL_CPM_ID_CLK_PLL_BEGIN ~ HAL_CPM_ID_CLK_PLL_END - 1 PLL 相关 clock。
HAL_CPM_ID_CLK_CGU_BEGIN ~ HAL_CPM_ID_CLK_CGU_END - 1 普通 CGU CDR clock。
HAL_CPM_ID_CLK_I2S_CGU_BEGIN ~ HAL_CPM_ID_CLK_I2S_CGU_END - 1 I2S TX/RX CGU clock。
HAL_CPM_ID_GATE_BASE ~ HAL_CPM_ID_GATE_END - 1 AON LP/HP0/HP1 gate。
HAL_CPM_ID_CLK_NONE 伪 parent id,表示支持无时钟输出的 mux 选择 none。

说明:

  • clock id 可用于 enable、disable、is_enabled、get_rate、set_rate、get_parent、set_parent。
  • HAL_CPM_ID_CLK_NONE 不属于普通 clock range,只能作为 parent 值或 get_parent 的返回值使用。
  • gate id 只支持 enable、disable、is_enabled。
  • 对 gate id 调用 rate 或 parent 接口返回 IM_ERR_UNSUPPORTED。
  • gate id 通过 HAL_CPM_ID_GATE_BASE 加硬件 stop bit offset 表示,中间保留位不是有效 gate。

4.3 Base Clock ID

ID 说明 可设置 rate 可设置 parent
HAL_CPM_ID_CLK_EXTAL 外部晶振时钟。 仅接受当前频率值 否
HAL_CPM_ID_CLK_ROSC2 ROSC2 时钟。 是,支持 16/24/32/48 MHz 否
HAL_CPM_ID_CLK_SCLK_A SCLK_A。 否;仅接受当前 parent 频率 是,可选 EXTAL / APLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_CCLK CPU clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_L2CLK L2 clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE,与 CCLK 共用 source mux
HAL_CPM_ID_CLK_H1CLK H1 clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_H2CLK H2 clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_PCLK PCLK。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE,与 H2CLK 共用 source mux
HAL_CPM_ID_CLK_HMCLK HM clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE / LPCLK
HAL_CPM_ID_CLK_PMCLK PM clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE / LPCLK,与 HMCLK 共用 source mux
HAL_CPM_ID_CLK_CPU_V0 LP V0 CPU clock。 是 SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE / LPCLK
HAL_CPM_ID_CLK_LPCLK AON LPCLK。 仅接受当前有效频率 是,CPU_V0 或 ROSC2
HAL_CPM_ID_CLK_RTCLK AON RTCLK。 否 是,ROSC2 或 EXTAL,输出为 parent/512

Base clock enable 是软件引用计数入口。硬件层当前不对 base clock 执行额外开启动作,disable 对不可硬关闭节点不会关硬件。 CCLK / L2CLK 共用 CPU source mux,但两者 divider 独立;H2CLK / PCLK 共用 H2/P source mux,但两者 divider 独立;HMCLK / PMCLK 共用 HM/PM source mux,并共用 PMCLK divider;H1CLK 和 CPU_V0 使用独立 source mux 和 divider。修改同一 source 组内任一时钟的 parent 会改变另一时钟的有效 parent;修改 HMCLK / PMCLK 中任一时钟的 rate 会同时改变另一时钟的频率。对 HMCLK / PMCLK / CPU_V0 设置 LPCLK 会把 AON LPCLKSEL 切到 ROSC2,而设置其他 parent 会切回 CPM。 HAL_CPM_ID_CLK_ROSC2 的 rate 由 ROSCC.ROSC2_FSEL 档位推导为标称频率(16/24/32/48 MHz),不是 trim 后的实测频率。 当 AON LPCLKSEL 选择 ROSC2 时,HMCLK、PMCLK 和 CPU_V0 的有效 parent 会显示为 LPCLK,rate 跟随 ROSC2;此时对这三个 clock 调用 set_rate_hz() 只接受当前频率值。

4.4 PLL ID

ID 说明 Parent 备注
HAL_CPM_ID_CLK_APLL APLL 输出。 HAL_CPM_ID_CLK_EXTAL 支持 set_rate。
HAL_CPM_ID_CLK_MPLL MPLL 输出。 HAL_CPM_ID_CLK_EXTAL 支持 set_rate。
HAL_CPM_ID_CLK_APLL_DIV8 APLL/8 派生输出。 HAL_CPM_ID_CLK_APLL 只读 rate,不支持直接 set_rate。

PLL rate 计算公式:

rate = parent_rate * M / N / OD1 / OD2

当前 HAL 对 APLL/MPLL set_rate 使用动态计算出的 M/N/OD1/OD2 配置,并轮询 PLL on 状态直至置位(最多 100000 次),超时返回 IM_ERR_TIMEOUT。HAL_CPM_ID_CLK_APLL_DIV8 的 rate 来自 APLL rate 除以 8。

4.5 CGU ID

普通 CGU clock 由 CPM CDR 寄存器控制。HAL 统一使用 Hz 作为 rate 参数;底层会转换成 CDR divider 字段。 HAL_CPM_ID_CLK_CGU_UART 与 HAL_CPM_ID_CLK_CGU_LP_UART 映射到同一个 uartcdr,共享 source、divider 和 STOP 使能位,不存在独立的 LP_UART 使能位。为避免一个逻辑域关闭仍被另一域使用的物理时钟,enable、disable、is_enabled 以及 hal_cpm_clk_get_info().enable_count 都对 LP_UART 使用同一个物理 UART clock 状态及软件引用计数。get_parent 和 get_rate_hz 仍按传入逻辑 ID 返回有效状态,因为 LP_UART 还可能经 AON LPCLKSEL 直连 LPCLK;set_parent 和 set_rate_hz 也保留逻辑域参数,以支持 LPCLK 路径切换。LP_UART 未走 LPCLK 时两者共同使用 uartcdr,成功的 parent/rate 更新会同步刷新两个逻辑 clock 的缓存,避免一个 ID 修改后另一个 ID 返回旧值。 LP 域 CGU(LP UART、SSI0、SSI_SLV0)共用 AON LPCLKSEL,但 parent 集合不完全相同:LP_UART 支持 SCLK_A / MPLL / EXTAL / LPCLK,SSI0 和 SSI_SLV0 支持 SCLK_A / MPLL / LPCLK。当 LPCLKSEL=ROSC2 时,这三个 clock 的有效 parent 都显示为 LPCLK,rate 等于当前 LPCLK,CPM CDR divider 不参与计算;此时 SSI0/SSI_SLV0 的 enable/disable 不操作 CDR,is_enabled 返回 true,而 LP_UART 的 enable/disable/is_enabled 仍作用于共享 uartcdr STOP 状态;这三个 clock 的 set_rate_hz() 都只接受当前 LPCLK 频率。任一 LP clock 调用 set_parent(LPCLK) 都会把三者一起切到 LPCLK 路径;任一 LP clock 切回 SCLK_A / MPLL(LP_UART 还可选 EXTAL)时,会先配置该 clock 的 CDR,再把 LPCLKSEL 切回 CPM。

ID CDR 寄存器 Divider 位宽 系数 可选 parent
HAL_CPM_ID_CLK_CGU_PSRAM psramcdr 4 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_RSA rsacdr 4 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_UART uartcdr 8 1 SCLK_A / MPLL / EXTAL,用于 UART2~7
HAL_CPM_ID_CLK_CGU_LP_UART uartcdr 8 1 SCLK_A / MPLL / EXTAL / LPCLK,用于 UART0/1
HAL_CPM_ID_CLK_CGU_MAC maccdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_MAC_PTP mac_ptpcdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_SFC sfccdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_PWM pwmcdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_PWMA pwmacdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_SSI0 ssi0cdr 8 1 SCLK_A / MPLL / LPCLK
HAL_CPM_ID_CLK_CGU_SSI1 ssi1cdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_SSI_SLV0 ssi_slv0cdr 8 1 SCLK_A / MPLL / LPCLK
HAL_CPM_ID_CLK_CGU_SSI_SLV1 ssi_slv1cdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_LCD lpcdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_MSC0 msc0cdr 8 4 SCLK_A / MPLL / APLL_DIV8 / EXTAL
HAL_CPM_ID_CLK_CGU_MSC1 msc1cdr 8 4 SCLK_A / MPLL / APLL_DIV8 / EXTAL
HAL_CPM_ID_CLK_CGU_TPC tpccdr 4 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_CIM0 cim0cdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_CIM1 cim1cdr 8 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_CAN0 can0cdr 8 1 SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_CAN1 can1cdr 8 1 SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_SADC0 sadc0cdr 8 1 SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_SADC1 sadc1cdr 8 1 SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_JPEG jpegcdr 4 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_MSCALER mscalercdr 4 1 SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_ISPM ispmcdr 4 1 SCLK_A / MPLL

CGU 分频关系:

rate = parent_rate / ((divider_field + 1) * coefficient)

HAL set_rate 向上取整计算分频值,使输出频率不大于目标频率;受分频字段上限限制时,实际输出可能低于目标。set_parent 会根据目标 parent 写入对应 CDR source 字段,并在需要时控制 UART/MSC/CAN/SADC 的 EXCLK enable 位;其中 MSC EXCLK 只在该路径切到 EXTAL 时置位,HAL 不会在这里清除 MSC EXCLK。

4.6 I2S CGU ID

ID 说明 可选 parent
HAL_CPM_ID_CLK_CGU_I2S_TX I2S TX clock。 SCLK_A / MPLL / ROSC2
HAL_CPM_ID_CLK_CGU_I2S_RX I2S RX clock。 SCLK_A / MPLL / ROSC2

选择 SCLK_A 或 MPLL 时走 CPM I2S CDR 路径;选择 ROSC2 时走 AON I2S CDR 路径。TX/RX 共用 source mux,切换 source 会影响两个方向。

I2S CGU 使用 M/N 分频:

rate = parent_rate * M / N

当前实现对未使能的 I2S clock 支持保存待写入的 M/N 配置;后续 enable 时再写入硬件。切换 parent 时,如果旧 rate 非 0,HAL 会尝试按新 parent 重新计算 M/N 以保持原频率。

由于 source mux 由 TX/RX 共用,set_parent() 在切换前会检查 peer:如果 peer 已使能且其当前 source 与目标 source 不同,或 peer 未使能但保存的 M/N 是针对旧 source 计算的,则拒绝本次切换并返回 IM_ERR_UNSUPPORTED,避免把 peer 切到错误频率。

4.7 Gate ID

Gate 资源映射到 AON LPCLKGR、HPCLKGR0 和 HPCLKGR1 stop bit。HAL 语义如下:

HAL 操作 硬件动作
hal_cpm_clk_enable(gate_id) 清 stop bit,打开 gate。
hal_cpm_clk_disable(gate_id) 置 stop bit,关闭 gate。
hal_cpm_clk_is_enabled(gate_id, &open) 读取 stop bit;stop bit 为 0 时输出 true。

LP gate:

ID AON bit
HAL_CPM_ID_GATE_CPU_V0 AON_LPCLKGR_CPU_V0_BIT
HAL_CPM_ID_GATE_AHB_MCU AON_LPCLKGR_AHB_MCU_BIT
HAL_CPM_ID_GATE_APB_MCU AON_LPCLKGR_APB_MCU_BIT
HAL_CPM_ID_GATE_DMA AON_LPCLKGR_DMA_BIT
HAL_CPM_ID_GATE_WDT AON_LPCLKGR_WDT_BIT
HAL_CPM_ID_GATE_UART0 AON_LPCLKGR_UART0_BIT
HAL_CPM_ID_GATE_UART1 AON_LPCLKGR_UART1_BIT
HAL_CPM_ID_GATE_SMB0 AON_LPCLKGR_SMB0_BIT
HAL_CPM_ID_GATE_SSI0 AON_LPCLKGR_SSI0_BIT
HAL_CPM_ID_GATE_SSI_SLV0 AON_LPCLKGR_SSI_SLV0_BIT
HAL_CPM_ID_GATE_AIC AON_LPCLKGR_AIC_BIT
HAL_CPM_ID_GATE_ROSC_HP AON_LPCLKGR_ROSC_HP_BIT

HP0 gate:

ID AON bit
HAL_CPM_ID_GATE_NEMC AON_HPCLKGR0_NEMC_BIT
HAL_CPM_ID_GATE_EFUSE AON_HPCLKGR0_EFUSE_BIT
HAL_CPM_ID_GATE_OTG AON_HPCLKGR0_OTG_BIT
HAL_CPM_ID_GATE_MSC0 AON_HPCLKGR0_MSC0_BIT
HAL_CPM_ID_GATE_MSC1 AON_HPCLKGR0_MSC1_BIT
HAL_CPM_ID_GATE_LP_EXCLK AON_HPCLKGR0_LP_EXCLK_BIT
HAL_CPM_ID_GATE_SMB1 AON_HPCLKGR0_SMB1_BIT
HAL_CPM_ID_GATE_SMB2 AON_HPCLKGR0_SMB2_BIT
HAL_CPM_ID_GATE_SADC0 AON_HPCLKGR0_SADC0_BIT
HAL_CPM_ID_GATE_TCU AON_HPCLKGR0_TCU_BIT
HAL_CPM_ID_GATE_UART2 AON_HPCLKGR0_UART2_BIT
HAL_CPM_ID_GATE_UART3 AON_HPCLKGR0_UART3_BIT
HAL_CPM_ID_GATE_SC_HASH AON_HPCLKGR0_SC_HASH_BIT
HAL_CPM_ID_GATE_UART4 AON_HPCLKGR0_UART4_BIT
HAL_CPM_ID_GATE_UART5 AON_HPCLKGR0_UART5_BIT
HAL_CPM_ID_GATE_PDMA AON_HPCLKGR0_PDMA_BIT
HAL_CPM_ID_GATE_UART6 AON_HPCLKGR0_UART6_BIT
HAL_CPM_ID_GATE_LCD AON_HPCLKGR0_LCD_BIT
HAL_CPM_ID_GATE_MIPI_CSI AON_HPCLKGR0_MIPI_CSI_BIT
HAL_CPM_ID_GATE_UART7 AON_HPCLKGR0_UART7_BIT
HAL_CPM_ID_GATE_RSA AON_HPCLKGR0_RSA_BIT
HAL_CPM_ID_GATE_SSI1 AON_HPCLKGR0_SSI1_BIT
HAL_CPM_ID_GATE_TNPU AON_HPCLKGR0_TNPU_BIT
HAL_CPM_ID_GATE_MIPI_DSI AON_HPCLKGR0_MIPI_DSI_BIT
HAL_CPM_ID_GATE_CAN0 AON_HPCLKGR0_CAN0_BIT
HAL_CPM_ID_GATE_DTRNG AON_HPCLKGR0_DTRNG_BIT
HAL_CPM_ID_GATE_CAN1 AON_HPCLKGR0_CAN1_BIT
HAL_CPM_ID_GATE_CIM AON_HPCLKGR0_CIM_BIT

HP1 gate:

ID AON bit
HAL_CPM_ID_GATE_MAC AON_HPCLKGR1_MAC_BIT
HAL_CPM_ID_GATE_AES AON_HPCLKGR1_AES_BIT
HAL_CPM_ID_GATE_JPEG_DEC AON_HPCLKGR1_JPEG_DEC_BIT
HAL_CPM_ID_GATE_TPC AON_HPCLKGR1_TPC_BIT
HAL_CPM_ID_GATE_SADC1 AON_HPCLKGR1_SADC1_BIT
HAL_CPM_ID_GATE_AHB1 AON_HPCLKGR1_AHB1_BIT
HAL_CPM_ID_GATE_SSI_SLV1 AON_HPCLKGR1_SSI_SLV1_BIT
HAL_CPM_ID_GATE_I2D AON_HPCLKGR1_I2D_BIT
HAL_CPM_ID_GATE_PWM AON_HPCLKGR1_PWM_BIT
HAL_CPM_ID_GATE_APB0 AON_HPCLKGR1_APB0_BIT
HAL_CPM_ID_GATE_PWMA AON_HPCLKGR1_PWMA_BIT
HAL_CPM_ID_GATE_IPU AON_HPCLKGR1_IPU_BIT
HAL_CPM_ID_GATE_SFC AON_HPCLKGR1_SFC_BIT
HAL_CPM_ID_GATE_PSRAM AON_HPCLKGR1_PSRAM_BIT
HAL_CPM_ID_GATE_OST AON_HPCLKGR1_OST_BIT
HAL_CPM_ID_GATE_JPEG AON_HPCLKGR1_JPEG_BIT
HAL_CPM_ID_GATE_MSCALER AON_HPCLKGR1_MSCALER_BIT

5. 文档范围

本文档定义 G32S10 SDK CPM/AON 低功耗(PM)middleware(MID)层的正式接口,面向在应用、BSP 或示例代码中发起低功耗请求、注册设备 PM 客户端、读取 PM 状态以及完成唤醒恢复的调用方。

本文档以当前 SDK 源码为准,主要核对文件如下:

类型 路径
MID 公开接口 code/middleware/pm/include/im_pm.h
MID 实现 code/middleware/pm/src/im_pm.c
V1 上下文辅助接口 code/middleware/pm/include/pm_context.h
V1 上下文汇编实现 code/middleware/pm/src/pm_context.S
HAL 公开接口 code/include/drivers/g32s10/pm/hal_pm.h
HAL 实现 code/drivers/g32s10/pm/hal_pm.c
AON HAL code/include/drivers/g32s10/aon/hal_aon.h、code/drivers/g32s10/aon/hal_aon.c
构建配置 code/middleware/pm/Kconfig、code/middleware/pm/CMakeLists.txt
MID 示例 code/middleware/pm/example/
硬件规格参考 G32S10_CPM&AON_spec_CN.docx(3.3 CPM 功耗管理、3.4 AON 功耗管理)

本文覆盖 MID 层公开 API,并对以下模式给出状态、流程和能力说明:

模式 MID 枚举 当前覆盖
Active IM_PM_MODE_ACTIVE 正常运行态,不是请求目标
Idle IM_PM_MODE_IDLE V1 支持
Light-nor IM_PM_MODE_LIGHT_NOR V1 与 SRAM-only V0 支持
Light-pd IM_PM_MODE_LIGHT_PD V1 与 SRAM-only V0 支持,含双核上下文保存/恢复
Retention IM_PM_MODE_RETENTION SRAM-only V0 支持
Deep-sleep IM_PM_MODE_DEEP_SLEEP SRAM-only V0 支持
Hibernate IM_PM_MODE_HIBERNATE SRAM-only V0 支持
Power-down IM_PM_MODE_POWER_OFF 板级/PMIC 整机掉电目标;接口定义存在,当前 HAL 不支持

补充说明:

  • 本文的 MID PM 指 code/middleware/pm/ 中的电源管理中间件;公开 API 均以 im_pm_ 开头。
  • MID 只通过 hal_pm_*() 访问低功耗硬件序列,不直接调用 CPM/AON LL 寄存器接口。CPM 时钟树和 gate 的 HAL/LL 接口见 G32S10 CPM HAL/LL 正式接口文档。
  • 文档中的芯片模式(Active、Idle、Light-nor 等)描述硬件低功耗形态;im_pm_state_t 描述 MID 一次事务的软件状态,两者不是同一状态机。
  • 本文列出的模式能力、状态迁移、回滚行为和返回值均以当前源码为准。文中寄存器级流程仅用于解释硬件语义,不构成 MID 公开 API。

目录

6. AON 状态说明

AON 是芯片常供电模块,负责 LP 域的总线/时钟控制,以及全芯片 HP 域的断电和上电控制。CPM 负责 IDLE、SLEEP 等时钟控制流程,AON 在此基础上扩展 RETENTION、DEEP_SLEEP 和 HIBERNATE 等断电流程。

本节先给出产品级运行模式总览,再说明 AON 状态转移及各模式的关键动作。图中“Active”等节点是芯片工作模式,不是 MID 事务状态。

6.1 状态转移图

G32S10 CPM/AON 状态转移图

状态图建议按以下四条主线阅读:

  • 运行主线:Active 在空闲且无中断时执行 WFI 进入 Idle;Idle 只关闭 V1 CPU 时钟,中断到来后自动回到 Active。
  • HP 时钟/供电主线:Light-nor 停止 HP 时钟但保留供电;Light-pd 进一步关闭 CPU_V1/TNPU 电源并允许模块 SRAM power down;Retention 保持 PSRAM 的 VDDMEM 和 V1 恢复上下文;Deep-sleep 断开 HP 域且不保留 V1 执行上下文。
  • 最深睡眠主线:Deep-sleep 下 V0 进入 sleep 后形成 Hibernate,V0 SRAM 进入 retention、模块 SRAM 进入 power down;GPIO 中断唤醒 V0 后回到 Deep-sleep 路径。
  • 外部掉电主线:Active 或 Deep-sleep 可由应用控制外部电源进入 Power-down;Power-down 重新上电后走冷启动回到 Active。该过程不属于 G32S10 PM HAL 的软件请求范围。

状态图中的关键迁移和相关动作如下:

状态迁移 关键动作
Active -> Idle 空闲且无中断时执行 WFI;仅关闭 V1 CPU 时钟,中断唤醒后恢复。
Idle -> Active 中断到来,自动退出 IDLE。
Active -> Light-nor 停止 HP 时钟;V1 进入 WFI/休眠,LP 域保持工作;唤醒后恢复 HP 时钟和 V1 指令状态。
Light-nor -> Active 中断唤醒,恢复 HP 时钟和 V1 指令状态。
Active -> Light-pd 停止 HP 时钟,断开 CPU_V1/TNPU 电源,模块 SRAM power down,保存 V1 上下文并执行 WFI/休眠。
Light-pd -> Active 中断唤醒后恢复 SRAM 供电、CPU_V1/TNPU 和 V1 上下文。
Active -> Retention 保存 V1 上下文,PSRAM 进入 half-sleep,由 V0 请求 HP 域掉电。
Retention -> Active V0 控制 HP 域上电,恢复 PSRAM、时钟和 GPIO,并恢复 V1 上下文。
Active -> Deep-sleep V1 不保存执行上下文,V0 请求 HP 域掉电。
Deep-sleep -> Active V0 控制 HP 域上电,V1 冷启动。
Deep-sleep -> Hibernate V0 SRAM 进入 retention、模块 SRAM 进入 power down;Hibernate 使用 Deep-sleep 作为内部基础状态。
Hibernate -> Deep-sleep V0 GPIO 中断触发,V0/LP 域恢复,系统回到 Deep-sleep 基础状态。
Active -> Power-down 应用控制外部电源掉电。
Deep-sleep -> Power-down 在深睡状态下由应用控制外部电源掉电;该迁移属于板级/PMIC 外部电源路径。
Power-down -> Active 应用控制外部电源重新上电,执行冷启动。

从 MID 角度看,Active 对应正常业务运行;im_pm_request() 成功后进入 SLEEPING,但此时硬件可能已处于 Idle、Light-pd、Retention、Deep-sleep 或 Hibernate。唤醒后必须先完成对应 hal_pm_exit_*() 序列,再调用 im_pm_resume() 完成软件事务恢复。

6.2 各模式资源表现

G32S10 CPM/AON 各模式资源表现

该图按 V1、HP 外设、PSRAM、V0 和 LP 外设五个维度描述各工作模式。整体上,状态越往后,V1、HP 外设和 PSRAM 的资源关闭得越彻底,V0 和 LP 外设的可用能力也越有限。

active

V1 运行在 800 MHz,V0 运行在 400 MHz,HP/LP 外设和 PSRAM 均正常工作。该状态处理全部业务和中断,是其他睡眠状态的返回点。

idle

仅关闭 V1 CPU 时钟,V0 仍以 400 MHz 运行,HP/LP 外设和 PSRAM 保持工作,中断可以唤醒 V1。该状态适合短时间无任务但仍需保持外设和内存可用的场景。

light-nor

V1 时钟关闭,HP 外设停止工作,PSRAM 进入自刷新;V0 运行在 16~48 MHz,LP 外设可继续工作。唤醒后恢复 HP 时钟和 V1 指令状态。

light-pd

V1 和 TNPU 断电,HP 外设不工作且模块 SRAM 可 power down;PSRAM 保持自刷新,IO 可进入 idle;V0 运行在 16~48 MHz,LP 外设可工作。该状态需要保存 V1 上下文,唤醒后恢复 SRAM 供电、CPU_V1/TNPU 和 V1 上下文。

retention

V1 断电,HP 外设断电并保留 PSRAM 的 VDDMEM,PSRAM 进入 half-sleep;V0 运行在 16~48 MHz,LP 外设可工作。该状态保存 PSRAM 数据和 V1 恢复上下文,唤醒后恢复 PSRAM、时钟、GPIO 和 V1 上下文。

deep-sleep

V1、HP 外设和 PSRAM 均断电,V0 运行在 16~48 MHz,LP 外设可工作。该状态不保存 V1 执行上下文,唤醒后 HP 域重新上电、V1 冷启动。

hibernate

V1、HP 外设和 PSRAM 断电,LP 域剩余模块关闭时钟,仅保留 AON 内部休眠状态机;V0 进入 sleep,仅计时和 GPIOD 中断唤醒可用,V0 SRAM 保持 retention、模块 SRAM 进入 power down。GPIO 唤醒后 LP 域时钟恢复并回到 deep-sleep 基础状态。

powerdown

V1、HP 外设、PSRAM、V0 和 LP 外设全部断电,由应用控制外部电源完成整机掉电。重新上电后执行冷启动。该状态不同于 CPM 内部的 POWER DOWN 模式,也不是普通软件可请求的低功耗模式。

7. 分层关系与依赖

Application / BSP / Example
           |
           v
        MID PM
           |
           v
        HAL PM
           |
           v
 LL CPM / LL AON / LL PM
           |
           v
   CPM and AON Registers

MID 层职责:

  • 以“一次低功耗事务”为单位编排 PM 生命周期:校验请求、按顺序调用客户端、提交恢复记录、调用 HAL 进入/退出,并在失败时回滚。
  • 维护调用方可见的 im_pm_state_t 状态、当前目标模式、最近一次故障和初始化时保存的能力快照。
  • 要求设备以静态链表注册 prepare / suspend / resume_early / resume / complete 回调,统一处理业务设备的停机和恢复顺序。
  • 在进入低功耗前保存恢复记录,并在唤醒初始化或 im_pm_resume() 时校验 magic、版本、owner、客户端数量、模式、序列号、挂起掩码和 CRC。

MID 当前使用的 HAL 接口:

HAL 接口 MID 用途
hal_pm_init() / hal_pm_deinit() 初始化/反初始化 AON 及 PM HAL 上下文
hal_pm_get_capabilities() 获取当前核和构建配置支持的模式掩码
hal_pm_enter_idle() / hal_pm_exit_idle() IDLE 进入/退出
hal_pm_enter_light_nor() / hal_pm_exit_light_nor() Light-nor 进入/退出
hal_pm_enter_light_pd() / hal_pm_exit_light_pd() Light-pd 进入/退出及 V0/V1 唤醒配合
hal_pm_enter_retention() / hal_pm_exit_retention() RETENTION 进入/退出
hal_pm_enter_deep_sleep() / hal_pm_exit_deep_sleep() DEEP_SLEEP 进入/退出
hal_pm_enter_hibernate() / hal_pm_exit_hibernate() HIBERNATE 进入/退出

MID 依赖的 SDK 组件:

  • hal_pm.h:模式、唤醒源、能力结构和每模式 enter/exit 接口。
  • hal_aon.h / hal_aon.c:AON 模式、复位/隔离/断电、PSRAM retention、握手区及 retained resume entry。
  • im_error.h:统一 error_code_t 错误码。
  • OS mutex:im_pm.c 使用递归互斥锁保护事务状态和客户端回调。
  • V1 上下文支持:pm_context.S 提供 pm_v1_ctx_save() / pm_v1_ctx_restore(),用于 LIGHT-PD/RETENTION 后从 retained resume entry 返回原执行点。

MID 不负责:

  • 具体 AON/CPM 寄存器写入顺序、PSRAM 控制器初始化或 TNPU/模块 SRAM 上电时序;这些由 HAL PM 和 AON HAL 完成。
  • 板级唤醒源配置、pending 位清理、GPIO 路由和 PMIC 控制;这些由应用/板级路径负责。
  • 执行 WFI、保存 V1 CPU 上下文或驱动 V0/V1 握手;MID 只提供模式请求和恢复事务管理。
  • 实现 IM_PM_MODE_POWER_OFF;该模式在当前 G32S10 HAL 中始终不支持。

8. 构建配置与文件组织

8.1 Kconfig

MID PM 配置项定义在 code/middleware/pm/Kconfig:

config MIDDLEWARE_PM
    bool "Power-management middleware"
    default n
    depends on SOC_SERIES_G32S10
    select DRIVER_PM

CONFIG_MIDDLEWARE_PM=y 会同时选择 CONFIG_DRIVER_PM=y。V0-only 断电模式还要求 CONFIG_G32S10_V0_RUN_IN_SRAM_ONLY=y;未满足时 V0 的能力快照为 0。

8.2 文件职责

code/middleware/pm/
  include/
    im_pm.h
    pm_context.h
  src/
    im_pm.c
    pm_context.S
code/include/drivers/g32s10/pm/
  hal_pm.h
code/drivers/g32s10/pm/
  hal_pm.c
  retention_stub.S
  retention_stub.c
  retention_stub.h
code/middleware/pm/example/
  CMakeLists.txt
  README.md
  build.sh
  pm_example_defconfig
  pm_example_slt_v0_defconfig
  pm_example_slt_v1_defconfig
  firmware/
    g32s10_v0_pm_slt.bin
  main/
    CMakeLists.txt
    main.c
    v0_main.c
文件 说明
im_pm.h MID PM 公开模式、状态、客户端、配置和 API 声明
im_pm.c PM 事务管理、客户端回调编排、状态机、恢复记录和 HAL 调用
pm_context.h PM V1 恢复路径使用的 pm_v1_ctx_save() / pm_v1_ctx_restore() 上下文辅助接口,不是普通业务设备客户端 API
pm_context.S PM V1 恢复路径的上下文保存和恢复汇编实现
hal_pm.h HAL PM 模式、唤醒源、能力和进入/退出 API 声明
hal_pm.c AON/CPM 低功耗模式硬件进入、退出和状态检查
retention_stub.S / retention_stub.c V0 retained resume 和低功耗启动辅助实现
example/ V0/V1 PM 示例、SLT defconfig、预置 V0 SLT 镜像和两段式构建脚本

code/middleware/pm/CMakeLists.txt 在 CONFIG_MIDDLEWARE_PM 生效时编译 src/im_pm.c;V1 构建还编译 src/pm_context.S,V0 构建注册独立的 im_pm 组件。

9. 资源模型与公开类型

9.1 模式与能力

typedef enum {
    IM_PM_MODE_ACTIVE = 0,
    IM_PM_MODE_IDLE,
    IM_PM_MODE_LIGHT_NOR,
    IM_PM_MODE_LIGHT_PD,
    IM_PM_MODE_RETENTION,
    IM_PM_MODE_DEEP_SLEEP,
    IM_PM_MODE_HIBERNATE,
    IM_PM_MODE_POWER_OFF,
    IM_PM_MODE_COUNT,
} im_pm_mode_t;
枚举 含义
IM_PM_MODE_ACTIVE 正常运行状态,不能作为请求目标
IM_PM_MODE_IDLE 停止 V1 CPU 时钟;任意 V1 可路由中断可唤醒
IM_PM_MODE_LIGHT_NOR 停止 HP 时钟,保留供电;LP/AON 继续时钟化
IM_PM_MODE_LIGHT_PD 关闭 CPU_V1/TNPU 并停止 HP 时钟;需保存 V1 上下文
IM_PM_MODE_RETENTION 关闭 HP,保留 PSRAM 数据和 V1 恢复上下文
IM_PM_MODE_DEEP_SLEEP 关闭 HP,不保留 V1 执行上下文
IM_PM_MODE_HIBERNATE DEEP_SLEEP 加 LP 时钟门控,仅保留 AON 休眠状态机
IM_PM_MODE_POWER_OFF 板级/PMIC 掉电目标,G32S10 PM HAL 不支持
IM_PM_MODE_COUNT 模式数量,不是合法请求目标

模式能力由 hal_pm_get_capabilities() 按构建配置决定,im_pm_get_capabilities() 返回初始化时保存的同一份快照:

核 / 构建配置 supported_mode_mask
V1(CONFIG_BUILD_CORE_V1) IDLE、LIGHT_NOR、LIGHT_PD
V0(CONFIG_BUILD_CORE_V0 且 CONFIG_G32S10_V0_RUN_IN_SRAM_ONLY=y) LIGHT_NOR、LIGHT_PD、RETENTION、DEEP_SLEEP、HIBERNATE
V0 未运行在 SRAM-only 模式 0,不支持任何低功耗模式

说明:

  • POWER_OFF 在 G32S10 上始终不支持,power_off_supported 恒为 false。
  • hal_pm_get_capabilities() 只读取编译配置,不要求先调用 hal_pm_init()。
  • im_pm_get_capabilities() 返回初始化时保存的快照;初始化前该快照为全零。
  • 客户端使用 IM_PM_MODE_MASK(mode) 表达自己支持的模式,不能把 ACTIVE 或 COUNT 放入掩码。

9.2 MID 事务状态

typedef enum {
    IM_PM_STATE_RESET = 0,
    IM_PM_STATE_READY,
    IM_PM_STATE_PREPARING,
    IM_PM_STATE_SUSPENDING,
    IM_PM_STATE_ARMED,
    IM_PM_STATE_ENTERING,
    IM_PM_STATE_SLEEPING,
    IM_PM_STATE_WAKING,
    IM_PM_STATE_RESUMING,
    IM_PM_STATE_FAULT,
} im_pm_state_t;
typedef struct {
    im_pm_state_t state;
    im_pm_mode_t mode;
    error_code_t fault;
} im_pm_status_t;

事务状态迁移:

RESET -> READY
READY -> PREPARING -> SUSPENDING -> ARMED -> ENTERING -> SLEEPING
SLEEPING -> WAKING -> RESUMING -> READY
失败路径 -> READY 或 FAULT

状态说明:

  • RESET:im_pm_init() 之前或 im_pm_deinit() 成功之后。
  • READY:可以接受新的 im_pm_request(),也是唯一允许调用 im_pm_deinit() 的状态。
  • PREPARING / SUSPENDING:正在按客户端链表顺序执行回调。
  • ARMED:恢复记录已提交,即将调用 HAL 进入接口。
  • ENTERING:HAL 进入成功后的瞬时状态。代码在同一临界区内立即将其改为 SLEEPING,因此 im_pm_get_status() 观察不到 ENTERING。
  • SLEEPING:事务已提交,等待平台唤醒路径调用 im_pm_resume()。
  • WAKING / RESUMING:正在调用 HAL 退出接口和客户端恢复回调。
  • FAULT:不可恢复的事务错误。当前没有公共 API 将状态从 FAULT 拉回 READY,通常只能复位系统后重新初始化。

fault 保存最近一次事务错误。实现会在 im_pm_init() 开始时清零,并在初始化成功、恢复成功或 deinit 成功时置回 IM_OK;事务失败期间保存对应错误。im_pm_get_status() 在未初始化时返回 state=RESET、mode=ACTIVE、fault=IM_OK。

9.3 PM 客户端与回调

设备客户端通过 im_pm_client_t 和 im_pm_device_ops_t 注册:

typedef struct {
    error_code_t (*prepare)(void *context, im_pm_mode_t mode);
    error_code_t (*suspend)(void *context, im_pm_mode_t mode);
    error_code_t (*resume_early)(void *context, im_pm_mode_t mode);
    error_code_t (*resume)(void *context, im_pm_mode_t mode);
    void (*complete)(void *context, im_pm_mode_t mode, error_code_t status);
} im_pm_device_ops_t;

typedef struct im_pm_client {
    const char *name;
    const im_pm_device_ops_t *ops;
    void *context;
    uint32_t supported_mode_mask;
    const struct im_pm_client *next;
} im_pm_client_t;

客户端约束(im_pm_init() 逐项校验):

  • 最多 16 个客户端。
  • client_count == 0 时 suspend_list 必须为 NULL;非零时链表长度必须与 client_count 完全一致。
  • name、ops、ops->prepare、ops->suspend 必须非空。
  • supported_mode_mask 不得包含 ACTIVE、COUNT 或超出范围的位,允许为 0。
  • suspend_list、客户端节点和回调表必须在 im_pm_deinit() 之前保持有效。
  • prepare 和 suspend 是必需回调;resume_early、resume、complete 可省略。

回调顺序:

  • 应用应按设备依赖关系静态定义 suspend_list;MID 只保证 prepare/suspend 正序和 resume 逆序,不自动推导消费者/提供者关系。
  • prepare 和 suspend 按 suspend_list 正序执行,只处理 supported_mode_mask 包含目标模式的客户端。
  • 恢复时先按相反顺序对所有已 suspend 客户端调用 resume_early,再按相反顺序对 resume_early 成功的客户端调用 resume。
  • resume_early 失败的客户端跳过 resume,但仍以该错误码调用 complete;其余客户端继续恢复。
  • prepare 失败的客户端本身不调用 complete;此前 prepare 成功的客户端按链表正序调用 complete(prepare_error)。
  • suspend 失败时,已 suspend 的客户端按相反顺序恢复;恢复成功的客户端收到 complete(suspend_error)。随后包括失败客户端在内的所有已 prepare 客户端各调用一次 complete。
  • 所有回调都在 MID 的递归互斥锁内执行。回调中不能无限等待另一个线程调用 im_pm_*(),否则会死锁。

9.4 初始化配置

typedef struct {
    const im_pm_client_t *suspend_list;
    uint32_t client_count;
    bool resume_from_retained_record;
} im_pm_config_t;
  • im_pm_config_default() 将 suspend_list 置为 NULL、client_count 置为 0、resume_from_retained_record 置为 false。
  • resume_from_retained_record=true 时,必须存在与当前镜像、当前 owner、当前客户端数量和当前模式能力匹配的 SLEEPING 恢复记录;否则 im_pm_init() 返回 IM_ERR_IO 并进入 FAULT。
  • 客户端链表是静态链表,MID 不复制节点,也不接管节点内存。
  • 同一时刻只允许一个活动 PM 事务;状态不是 READY 时 im_pm_request() 返回 IM_ERR_BUSY。

9.5 唤醒源请求配置

typedef enum {
    HAL_PM_WAKE_NONE = 0,
    HAL_PM_WAKE_V1_TIMER,
    HAL_PM_WAKE_V0_TIMER,
    HAL_PM_WAKE_LP_IRQ,
    HAL_PM_WAKE_GPIO,
    HAL_PM_WAKE_COUNT,
} hal_pm_wake_source_t;

typedef struct {
    hal_pm_wake_source_t wake_source;
} hal_pm_request_config_t;
  • hal_pm_request_config_t 只有 wake_source 一个字段。
  • im_pm_request() 的 request_config 可以为 NULL,等价于 HAL_PM_WAKE_NONE。
  • 唤醒源只是事务元数据,会写入恢复记录并原样传给 HAL;MID 和 HAL 都不配置实际唤醒源,也不清理挂起位,这些由应用/板级路径负责。
  • HAL_PM_WAKE_V1_TIMER 只允许用于 IM_PM_MODE_IDLE,其它模式返回 IM_ERR_INVALID_PARAM。
  • wake_source >= HAL_PM_WAKE_COUNT 返回 IM_ERR_INVALID_PARAM。

当前示例和已验证流程使用的唤醒源约定如下:

MID 模式 典型唤醒源 说明
IM_PM_MODE_IDLE HAL_PM_WAKE_V1_TIMER 或任意 V1 可路由中断 只有 IDLE 允许 V1 timer 元数据
IM_PM_MODE_LIGHT_NOR HAL_PM_WAKE_V0_TIMER / HAL_PM_WAKE_LP_IRQ 进入后 HP 时钟关闭,需 LP/AON 可达事件
IM_PM_MODE_LIGHT_PD HAL_PM_WAKE_NONE 或 LP/AON 事件 V0 控制示例使用主动恢复,不依赖一次性 timer
IM_PM_MODE_RETENTION HAL_PM_WAKE_V0_TIMER / HAL_PM_WAKE_LP_IRQ V0 在 LP 域保持运行
IM_PM_MODE_DEEP_SLEEP HAL_PM_WAKE_V0_TIMER / HAL_PM_WAKE_LP_IRQ V0 负责 HP 上电与 V1 冷启动配合
IM_PM_MODE_HIBERNATE HAL_PM_WAKE_GPIO 当前示例使用 GPIOD 下降沿唤醒

唤醒源字段仍只是元数据;上表不表示 MID 会替应用配置中断、timer 或 GPIO。

9.6 模式对象与生命周期

MID 没有需要调用方逐实例分配的“PM 设备对象”;一个核上的 PM 中间件由静态全局状态维护。调用方生命周期应满足:

  1. 保持客户端链表、节点和回调表有效。
  2. 调用 im_pm_config_default() 和 im_pm_init()。
  3. 发起一次 im_pm_request(),等待硬件进入目标模式。
  4. 平台唤醒路径完成硬件退出或恢复入口后,调用一次 im_pm_resume()。
  5. 需要释放时,仅在 READY 状态调用 im_pm_deinit()。

同一事务只能恢复一次;重复 im_pm_resume() 或未成功请求就恢复都会返回 IM_ERR_BUSY。