API GUIDE / CPM / HAL

G32S10 CPM HAL 接口

HAL 层接口:Base clock enable 是软件引用计数入口。

1. 资源模型与公开类型

1.1 Base Clock ID

ID说明可设置 rate可设置 parent
HAL_CPM_ID_CLK_EXTAL外部晶振时钟。仅接受当前频率值否
HAL_CPM_ID_CLK_ROSC2ROSC2 时钟。是,支持 16/24/32/48 MHz否
HAL_CPM_ID_CLK_SCLK_ASCLK_A。否;仅接受当前 parent 频率是,可选 EXTAL / APLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_CCLKCPU clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_L2CLKL2 clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE,与 CCLK 共用 source mux
HAL_CPM_ID_CLK_H1CLKH1 clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_H2CLKH2 clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE
HAL_CPM_ID_CLK_PCLKPCLK。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE,与 H2CLK 共用 source mux
HAL_CPM_ID_CLK_HMCLKHM clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE / LPCLK
HAL_CPM_ID_CLK_PMCLKPM clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE / LPCLK,与 HMCLK 共用 source mux
HAL_CPM_ID_CLK_CPU_V0LP V0 CPU clock。是SCLK_A / MPLL / HAL_CPM_ID_CLK_NONE / LPCLK
HAL_CPM_ID_CLK_LPCLKAON LPCLK。仅接受当前有效频率是,CPU_V0 或 ROSC2
HAL_CPM_ID_CLK_RTCLKAON 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() 只接受当前频率值。

1.2 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 字段;通过任一 ID 修改 parent 或 rate 都会改变另一个 ID 看到的 CDR 配置。 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 不参与计算;此时 enable/disable 不操作 CDR,is_enabled 返回 true,set_rate_hz() 只接受当前 LPCLK 频率。任一 LP clock 调用 set_parent(LPCLK) 都会把三者一起切到 LPCLK 路径;任一 LP clock 切回 SCLK_A / MPLL(LP_UART 还可选 EXTAL)时,会先配置该 clock 的 CDR,再把 LPCLKSEL 切回 CPM。

IDCDR 寄存器Divider 位宽系数可选 parent
HAL_CPM_ID_CLK_CGU_PSRAMpsramcdr41SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_RSArsacdr41SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_UARTuartcdr81SCLK_A / MPLL / EXTAL,用于 UART2~7
HAL_CPM_ID_CLK_CGU_LP_UARTuartcdr81SCLK_A / MPLL / EXTAL / LPCLK,用于 UART0/1
HAL_CPM_ID_CLK_CGU_MACmaccdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_MAC_PTPmac_ptpcdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_SFCsfccdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_PWMpwmcdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_PWMApwmacdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_SSI0ssi0cdr81SCLK_A / MPLL / LPCLK
HAL_CPM_ID_CLK_CGU_SSI1ssi1cdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_SSI_SLV0ssi_slv0cdr81SCLK_A / MPLL / LPCLK
HAL_CPM_ID_CLK_CGU_SSI_SLV1ssi_slv1cdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_LCDlpcdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_MSC0msc0cdr84SCLK_A / MPLL / APLL_DIV8 / EXTAL
HAL_CPM_ID_CLK_CGU_MSC1msc1cdr84SCLK_A / MPLL / APLL_DIV8 / EXTAL
HAL_CPM_ID_CLK_CGU_TPCtpccdr41SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_CIM0cim0cdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_CIM1cim1cdr81SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_CAN0can0cdr81SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_CAN1can1cdr81SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_SADC0sadc0cdr81SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_SADC1sadc1cdr81SCLK_A / MPLL / EXTAL
HAL_CPM_ID_CLK_CGU_JPEGjpegcdr41SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_MSCALERmscalercdr41SCLK_A / MPLL
HAL_CPM_ID_CLK_CGU_ISPMispmcdr41SCLK_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。

1.3 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:

IDAON bit
HAL_CPM_ID_GATE_CPU_V0AON_LPCLKGR_CPU_V0_BIT
HAL_CPM_ID_GATE_AHB_MCUAON_LPCLKGR_AHB_MCU_BIT
HAL_CPM_ID_GATE_APB_MCUAON_LPCLKGR_APB_MCU_BIT
HAL_CPM_ID_GATE_DMAAON_LPCLKGR_DMA_BIT
HAL_CPM_ID_GATE_WDTAON_LPCLKGR_WDT_BIT
HAL_CPM_ID_GATE_UART0AON_LPCLKGR_UART0_BIT
HAL_CPM_ID_GATE_UART1AON_LPCLKGR_UART1_BIT
HAL_CPM_ID_GATE_SMB0AON_LPCLKGR_SMB0_BIT
HAL_CPM_ID_GATE_SSI0AON_LPCLKGR_SSI0_BIT
HAL_CPM_ID_GATE_SSI_SLV0AON_LPCLKGR_SSI_SLV0_BIT
HAL_CPM_ID_GATE_AICAON_LPCLKGR_AIC_BIT
HAL_CPM_ID_GATE_ROSC_HPAON_LPCLKGR_ROSC_HP_BIT

HP0 gate:

IDAON bit
HAL_CPM_ID_GATE_NEMCAON_HPCLKGR0_NEMC_BIT
HAL_CPM_ID_GATE_EFUSEAON_HPCLKGR0_EFUSE_BIT
HAL_CPM_ID_GATE_OTGAON_HPCLKGR0_OTG_BIT
HAL_CPM_ID_GATE_MSC0AON_HPCLKGR0_MSC0_BIT
HAL_CPM_ID_GATE_MSC1AON_HPCLKGR0_MSC1_BIT
HAL_CPM_ID_GATE_LP_EXCLKAON_HPCLKGR0_LP_EXCLK_BIT
HAL_CPM_ID_GATE_SMB1AON_HPCLKGR0_SMB1_BIT
HAL_CPM_ID_GATE_SMB2AON_HPCLKGR0_SMB2_BIT
HAL_CPM_ID_GATE_SADC0AON_HPCLKGR0_SADC0_BIT
HAL_CPM_ID_GATE_TCUAON_HPCLKGR0_TCU_BIT
HAL_CPM_ID_GATE_UART2AON_HPCLKGR0_UART2_BIT
HAL_CPM_ID_GATE_UART3AON_HPCLKGR0_UART3_BIT
HAL_CPM_ID_GATE_SC_HASHAON_HPCLKGR0_SC_HASH_BIT
HAL_CPM_ID_GATE_UART4AON_HPCLKGR0_UART4_BIT
HAL_CPM_ID_GATE_UART5AON_HPCLKGR0_UART5_BIT
HAL_CPM_ID_GATE_PDMAAON_HPCLKGR0_PDMA_BIT
HAL_CPM_ID_GATE_UART6AON_HPCLKGR0_UART6_BIT
HAL_CPM_ID_GATE_LCDAON_HPCLKGR0_LCD_BIT
HAL_CPM_ID_GATE_MIPI_CSIAON_HPCLKGR0_MIPI_CSI_BIT
HAL_CPM_ID_GATE_UART7AON_HPCLKGR0_UART7_BIT
HAL_CPM_ID_GATE_RSAAON_HPCLKGR0_RSA_BIT
HAL_CPM_ID_GATE_SSI1AON_HPCLKGR0_SSI1_BIT
HAL_CPM_ID_GATE_TNPUAON_HPCLKGR0_TNPU_BIT
HAL_CPM_ID_GATE_MIPI_DSIAON_HPCLKGR0_MIPI_DSI_BIT
HAL_CPM_ID_GATE_CAN0AON_HPCLKGR0_CAN0_BIT
HAL_CPM_ID_GATE_DTRNGAON_HPCLKGR0_DTRNG_BIT
HAL_CPM_ID_GATE_CAN1AON_HPCLKGR0_CAN1_BIT
HAL_CPM_ID_GATE_CIMAON_HPCLKGR0_CIM_BIT

HP1 gate:

IDAON bit
HAL_CPM_ID_GATE_MACAON_HPCLKGR1_MAC_BIT
HAL_CPM_ID_GATE_AESAON_HPCLKGR1_AES_BIT
HAL_CPM_ID_GATE_JPEG_DECAON_HPCLKGR1_JPEG_DEC_BIT
HAL_CPM_ID_GATE_TPCAON_HPCLKGR1_TPC_BIT
HAL_CPM_ID_GATE_SADC1AON_HPCLKGR1_SADC1_BIT
HAL_CPM_ID_GATE_AHB1AON_HPCLKGR1_AHB1_BIT
HAL_CPM_ID_GATE_SSI_SLV1AON_HPCLKGR1_SSI_SLV1_BIT
HAL_CPM_ID_GATE_I2DAON_HPCLKGR1_I2D_BIT
HAL_CPM_ID_GATE_PWMAON_HPCLKGR1_PWM_BIT
HAL_CPM_ID_GATE_APB0AON_HPCLKGR1_APB0_BIT
HAL_CPM_ID_GATE_PWMAAON_HPCLKGR1_PWMA_BIT
HAL_CPM_ID_GATE_IPUAON_HPCLKGR1_IPU_BIT
HAL_CPM_ID_GATE_SFCAON_HPCLKGR1_SFC_BIT
HAL_CPM_ID_GATE_PSRAMAON_HPCLKGR1_PSRAM_BIT
HAL_CPM_ID_GATE_OSTAON_HPCLKGR1_OST_BIT
HAL_CPM_ID_GATE_JPEGAON_HPCLKGR1_JPEG_BIT
HAL_CPM_ID_GATE_MSCALERAON_HPCLKGR1_MSCALER_BIT

2. HAL 接口

2.1 初始化

error_code_t hal_cpm_init(void);

功能:

  • 清零 HAL clock enable 引用计数

  • 从当前硬件寄存器刷新 clock parent 和 rate 缓存

返回值:

返回值说明
IM_OK初始化成功。
IM_ERR_INVALID_PARAM内部 clock 表或硬件读取结果异常。
其它错误码刷新某个 clock parent/rate 时返回的底层错误。

2.2 Enable / Disable / Is Enabled

error_code_t hal_cpm_clk_enable(hal_cpm_id_t id);
error_code_t hal_cpm_clk_disable(hal_cpm_id_t id);
error_code_t hal_cpm_clk_is_enabled(hal_cpm_id_t id, bool *is_enabled_out);

clock id 语义:

  • hal_cpm_clk_enable() 会维护 clock enable 引用计数。

  • 引用计数从 0 变成 1 时,才调用对应 clock 类型的硬件 enable。

  • 多次 enable 需要对应多次 disable;引用计数大于 1 时 disable 只递减计数,不关闭硬件。

  • 对当前无硬件 disable 控制的 base/PLL clock,最后一次 disable 只清软件引用计数。

gate id 语义:

  • 不维护引用计数。

  • enable 直接打开 gate,disable 直接关闭 gate。

返回值:

返回值说明
IM_OK操作成功。
IM_ERR_INVALID_PARAMid 非法或输出指针为空。
IM_ERR_BUSYclock enable 引用计数达到上限。
IM_ERR_TIMEOUT等待 PLL on 状态或 CDR busy 清除超时。
IM_ERR_UNSUPPORTED指定 clock 类型不支持该操作。

2.3 Rate

error_code_t hal_cpm_clk_get_rate_hz(hal_cpm_id_t id, uint32_t *rate_hz_out);
error_code_t hal_cpm_clk_set_rate_hz(hal_cpm_id_t id, uint32_t rate_hz);

说明:

  • rate 单位固定为 Hz。

  • get_rate_hz 读取 HAL 缓存值;hal_cpm_clk_get_info() 每次调用会先全量刷新 parent/rate 缓存。

  • set_rate_hz、set_parent 成功后只刷新被操作 clock 自身的 parent/rate 缓存, 不递归刷新依赖它的子节点。

  • gate id 不支持 rate 接口。

返回值:

返回值说明
IM_OK操作成功。
IM_ERR_INVALID_PARAMid 非法、输出指针为空或 rate 参数非法。
IM_ERR_NOT_READY当前 parent 频率为 0,无法计算目标分频。
IM_ERR_UNSUPPORTED资源不支持设置频率,或目标模式与该 clock 的当前配置冲突。
IM_ERR_TIMEOUT等待 CDR busy 清除或 PLL on 状态超时。

2.4 Parent

error_code_t hal_cpm_clk_get_parent(hal_cpm_id_t id,
                                    hal_cpm_id_t *parent_id_out);
error_code_t hal_cpm_clk_set_parent(hal_cpm_id_t id,
                                    hal_cpm_id_t parent_id);

说明:

  • parent 参数必须是可用作 parent 的 clock id 或 HAL_CPM_ID_CLK_NONE;具体目标 clock 还须支持该 parent,否则返回 IM_ERR_UNSUPPORTED。

  • gate id 不支持 parent 接口。

  • root clock 没有 parent,调用 get_parent 返回 IM_ERR_UNSUPPORTED。

  • get_parent 读到硬件无时钟输出时返回 HAL_CPM_ID_CLK_NONE;此时对应 clock rate 为 0。

  • set_parent 成功后只刷新当前节点自身的 parent/rate 缓存,子节点缓存不会自动重算;依赖该节点的子 clock 需通过 hal_cpm_clk_get_info() 或 hal_cpm_init() 重新同步。

2.5 ROSC2 校准

error_code_t hal_cpm_rosc2_trim(void);

功能:

  • 把 ROSC2 切到 24 MHz 档位(AON_ROSC2_FSEL_24M),然后固定延时 100 us;该流程没有可读取的档位稳定状态位

  • 清计数,保持 TRIM_COUNT_EN 为低电平 200 us,再拉高 TRIM_COUNT_EN;固定延时 100 us 后轮询 TRIMS.TRIM_FINISH,置位后读取一次TRIMS.TRIM_COUNT_NUM

  • 在 64 项升序 trim 表中取第一个不小于计数值的表项索引,作为ROSCC.ROSC2_TRIM 字段值并写入

  • 测量只执行一次;写入 trim 后不会再次测量,也不会反复测量直到表值与应用值一致

说明:

  • 阻塞实现:档位切换后固定延时 100 us,计数前保持 TRIM_COUNT_EN 低电平 200 us,拉高后再等待 100 us,然后轮询 TRIM_FINISH(最多 100000 次)。按约 1 ms的计数窗口估算,单次调用为 1.4 ms 量级;忙等期间不让出 CPU。

  • 必须在任务上下文调用,不要在中断上下文、关中断上下文或其它对延迟敏感的路径调用。

  • 调用结束后 ROSC2_FSEL 保持为 24 MHz,不会恢复调用前的档位;调用方需评估LPCLK/RTCLK 等下游时钟对频率变化的容忍度。

  • 计数值高于表项上限时饱和到 ROSC2_TRIM=63,不会返回“未校准”错误。

  • 计数握手失败时关闭 TRIM_COUNT_EN 并返回 IM_ERR_TIMEOUT;成功路径读完计数后同样关闭。TRIMS 中的计数保持到下一次测量开始(TRIM_COUNT_CLR)。

  • 超时返回时 ROSC2_FSEL 仍为 24 MHz,ROSCC.ROSC2_TRIM 保持原值不变。

  • 该接口直接操作 LL 位域,不刷新 HAL clock cache。若调用前 ROSC2_FSEL 不是24 MHz,hal_cpm_clk_get_rate_hz() 在刷新前仍可能返回旧档位的标称频率;调用后可执行 hal_cpm_clk_get_info() 或 hal_cpm_init() 刷新。

  • hal_cpm_clk_get_info() / hal_cpm_init() 只会按 ROSC2_FSEL 刷新 HAL使用的标称频率,不返回 trim 后的实测频率;需要实测值时必须通过 测量。

返回值:

返回值说明
IM_OK测量完成,trim 已写入。
IM_ERR_TIMEOUTTRIM_FINISH 在轮询上限内未置位。

2.6 Clock information

typedef struct {
    uint32_t id;
    const char *name;
    const char *parent;
    bool enabled;
    bool gate_present;
    bool gate_enabled;
    bool busy;
    uint32_t enable_count;
    uint32_t rate_hz;
    uint32_t div_num;
    uint32_t div_den;
} hal_cpm_clk_info_t;

error_code_t hal_cpm_clk_get_count(uint32_t *count_out);
error_code_t hal_cpm_clk_get_info(uint32_t id,
                                  hal_cpm_clk_info_t *info_out);

typedef struct {
    const char *name;
    uintptr_t address;
    uint32_t value;
} hal_cpm_gate_reg_info_t;

error_code_t hal_cpm_clk_get_gate_reg_count(uint32_t *count_out);
error_code_t hal_cpm_clk_get_gate_reg_info(uint32_t index,
                                           hal_cpm_gate_reg_info_t *info_out);

功能:

  • 由具体芯片 HAL 提供当前芯片的 clock 名称、parent 关系、gate、DIV 和 BUSY 语义

  • hal_cpm_clk_get_count() 返回当前芯片 clock 数量

  • hal_cpm_clk_get_info() 查询一个 clock 的完整状态

  • enabled 表示 clock output 状态;gate_present/gate_enabled 表示关联的模块 gate 状态

  • busy 表示当前是否正在进行分频或时钟切换

  • div_num/div_den 表示分频值;普通分频使用 N/1,I2S 使用 M/N,没有分频器时为 0/0

  • 通用 clk middleware 负责遍历 HAL 信息并提供 im_clk_summary();shell 的 cat_clk 只依赖 middleware

  • hal_cpm_clk_get_gate_reg_count()/hal_cpm_clk_get_gate_reg_info() 提供诊断用的 clock gate 寄存器枚举接口

  • gate 寄存器集合是芯片相关的:数量、名称和地址都由具体芯片 HAL 决定,调用方按 [0, count) 遍历,不要假定固定是 LPCLKGR/HPCLKGR0/HPCLKGR1 三个;因此 im_clk_get_gate_reg_count()/im_clk_get_gate_reg_info() 也一样返回描述符而不写死寄存器

  • cat_clk misc 直接打印 HAL 返回的名称和地址;数量为 0 时提示该芯片不暴露 gate 寄存器

返回值:

返回值说明
IM_OK查询成功,info_out 已填写。
IM_ERR_INVALID_PARAMid 越界或 info_out 为空。
IM_ERR_NOT_READY全量刷新 clock cache 失败,无法保证信息一致。

CPM stub 的 clock information 和 gate register 查询接口返回 IM_ERR_UNSUPPORTED。