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_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() 只接受当前频率值。
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。
| 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。
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:
| 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 |
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_PARAM | id 非法或输出指针为空。 |
IM_ERR_BUSY | clock 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_PARAM | id 非法、输出指针为空或 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_TIMEOUT | TRIM_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通用
clkmiddleware 负责遍历 HAL 信息并提供im_clk_summary();shell 的cat_clk只依赖 middlewarehal_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_PARAM | id 越界或 info_out 为空。 |
IM_ERR_NOT_READY | 全量刷新 clock cache 失败,无法保证信息一致。 |
CPM stub 的 clock information 和 gate register 查询接口返回 IM_ERR_UNSUPPORTED。