API GUIDE / CPM / OVERVIEW
G32S10 CPM API 概述
模块概述:本文档定义 G32S10 SDK 当前 CPM 模块的正式接口,覆盖以下两层:
1. 文档范围
本文档定义 G32S10 SDK 当前 CPM 模块的正式接口,覆盖以下两层:
HAL CPM:面向应用、BSP 和驱动上层的时钟、分频、父时钟和 gate 控制接口LL CPM/AON:面向 CPM/AON 寄存器与位域操作的低层接口
本文档基于以下实现与头文件编写:
code/include/drivers/g32s10/cpm/hal_cpm.hcode/include/drivers/g32s10/cpm/cpm_regs.hcode/include/drivers/g32s10/cpm/ll_cpm.hcode/include/drivers/g32s10/cpm/ll_cdr.hcode/include/drivers/g32s10/cpm/ll_aon.hcode/include/drivers/g32s10/cpm/ll_pm.hcode/drivers/g32s10/cpm/hal_cpm_core.ccode/drivers/g32s10/cpm/hal_cpm_clk.ccode/drivers/g32s10/cpm/hal_cpm_pll.ccode/drivers/g32s10/cpm/hal_cpm_cgu.ccode/drivers/g32s10/cpm/hal_cpm_i2s_cgu.ccode/drivers/g32s10/cpm/hal_cpm_gate.ccode/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_tLL CPM/AON提供
static inline寄存器和位域访问入口不维护软件状态,不做 clock tree 或引用计数语义
不返回 SDK 错误码;读取接口返回寄存器值或
boolcpm_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 统一资源 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.2 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.3 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 切到错误频率。
5. HAL 与 LL 使用约束
普通业务和驱动上层应优先使用
hal_cpm_clk_*接口,不直接拼 CDR、CPCCR 或 AON CLKGR 字段。LL 接口适用于 HAL 内部、bring-up、调试和确实需要寄存器级控制的底层模块。
修改 CPCCR/CPCCR1 或 CDR source/divider/STOP 字段后,需要按对应寄存器要求触发 CE/update 并等待 busy 清除;HAL 已封装这些流程。
gate close 会直接关闭目标模块时钟,关闭 bus、memory、CPU、PSRAM 等关键 gate 可能导致系统挂起。
hal_cpm_clk_get_rate_hz()返回 HAL 缓存值,不直接读寄存器即时计算;外部绕过 HAL 修改寄存器后,应调用hal_cpm_clk_get_info()触发全量刷新,或调用hal_cpm_init()(同时会清零 enable 引用计数)重新同步。普通 main clock 和 CGU 的
hal_cpm_clk_set_rate_hz()向上取整分频,使输出频率不大于目标值;受字段上限限制时可能明显低于目标。I2S 使用 M/N 搜索最接近目标的组合,实际频率可能高于或低于目标。调用方应再读取实际 rate 确认结果。hal_cpm_clk_set_rate_hz()/hal_cpm_clk_set_parent()只刷新被操作 clock 自身,修改SCLK_A、MPLL等共享 parent 后,依赖它的子 clock 缓存可能仍是旧值。PLL 动态改频会修改 PLL 控制寄存器并轮询 PLL
on状态,调用方应评估下游 clock 对频率变化的容忍度。
6. 典型使用
6.1 初始化并读取 clock rate
#include "hal_cpm.h"
error_code_t ret;
uint32_t rate_hz;
ret = hal_cpm_init();
if (ret != IM_OK) {
return ret;
}
ret = hal_cpm_clk_get_rate_hz(HAL_CPM_ID_CLK_CGU_UART, &rate_hz);
if (ret != IM_OK) {
return ret;
}6.2 设置 CGU 频率并打开输出
ret = hal_cpm_clk_set_parent(HAL_CPM_ID_CLK_CGU_UART,
HAL_CPM_ID_CLK_EXTAL);
if (ret != IM_OK) {
return ret;
}
ret = hal_cpm_clk_set_rate_hz(HAL_CPM_ID_CLK_CGU_UART, 24000000U);
if (ret != IM_OK) {
return ret;
}
ret = hal_cpm_clk_enable(HAL_CPM_ID_CLK_CGU_UART);
if (ret != IM_OK) {
return ret;
}6.3 打开模块 gate
ret = hal_cpm_clk_enable(HAL_CPM_ID_GATE_UART1);
if (ret != IM_OK) {
return ret;
}6.4 查询 gate 状态
bool open;
ret = hal_cpm_clk_is_enabled(HAL_CPM_ID_GATE_UART1, &open);
if (ret != IM_OK) {
return ret;
}