API GUIDE / EFUSE / HAL
G32S10 EFUSE HAL 接口
HAL 层接口:HAL_EFUSE_SEGMENT_ID_COUNT 仅为数量哨兵,不是合法段 ID。
1. 资源模型与公开类型
1.1 HAL 段 ID
typedef enum hal_efuse_segment_id {
HAL_EFUSE_SEGMENT_CHIP_ID = 0,
/* ... */
HAL_EFUSE_SEGMENT_OSC_TRIM,
HAL_EFUSE_SEGMENT_ID_COUNT,
} hal_efuse_segment_id_t;HAL_EFUSE_SEGMENT_ID_COUNT 仅为数量哨兵,不是合法段 ID。段元数据由 HAL 固化,调用方不能传入裸地址替代段 ID。
核心段如下:
| 段 ID | 段名 | 起始地址 | 大小 | 写入约束 |
|---|---|---|---|---|
CHIP_ID | CHIP_ID | 0x00 | 12 | 受 STATE.CHIP_ID_PRT 保护。 |
PROT | PROT | 0x0C | 2 | 需要特殊段解锁。 |
SPECIAL | SPECIAL | 0x0E | 2 | 需要特殊段解锁。 |
PROT_BK | PROT_BK | 0x10 | 2 | 需要特殊段解锁。 |
RETENT | RETENT | 0x12 | 14 | 受 STATE.RETENT_PRT 保护。 |
SCBOOT | SCBOOT | 0x20 | 32 | 受 STATE.SCBOOT_PRT 保护。 |
OS_KEY | OS_KEY | 0x40 | 16 | 受 STATE.OS_KEY_PRT 保护。 |
USER_KEY | USER_KEY | 0x50 | 16 | 受 STATE.USER_KEY_PRT 保护。 |
SCBOOT_BK | SCBOOT_BK | 0x60 | 32 | 受 STATE.SCBOOT_BAK_PRT 保护。 |
PSRAM_INIT_PROT | PSRAM_INIT_PROT | 0x80 | 4 | 需要特殊段解锁。 |
PSRAM_TYPE 至 PSRAM_RESERVED2 | PSRAM 参数段 | 0x84 至 0xE4 | 各 4 | 分别受 PSRAM_STATE 对应保护位保护。 |
RESERVED | RESERVED | 0xE8 | 21 | 可写;无保护位,写入前读回校验 old | input。 |
SPECIAL_BK | SPECIAL_BK | 0xFD | 2 | 需要特殊段解锁。 |
OSC_TRIM | OSC_TRIM | 0xFF | 1 | 受 STATE.OSC_TRIM_PRT 保护。 |
PSRAM 参数段包含 PSRAM_CFG_REG、PSRAM_TPU、PSRAM_TRST、PSRAM_TCEM、PSRAM_THS_INIT、PSRAM_TDPD_INIT、PSRAM_THS、PSRAM_TXPHS、PSRAM_TXHS、PSRAM_TDPD、PSRAM_TXPDPD、PSRAM_TXDPD、PSRAM_COMMAND_TIMING、PSRAM_RW_LATENCY、PSRAM_MR_INIT、PSRAM_CSN_DUMMY、PSRAM_TCQLZ、PSRAM_MEMORY_SPECIAL、PSRAM_TRP、PSRAM_RWDS_CTRL、PSRAM_TRWR 和 3 个保留参数段。
1.2 VDDQ GPIO 与 HAL 句柄
typedef struct hal_efuse_gpio {
gpio_regs_t *gpiox;
uint32_t pin_mask;
} hal_efuse_gpio_t;
typedef struct hal_efuse_handle {
efuse_regs_t *efusex;
hal_efuse_gpio_t gpio_power;
bool is_initialized;
bool is_timing_ready;
} hal_efuse_handle_t;| 字段 | 说明 |
|---|---|
efusex | 目标 EFUSE 寄存器实例,通常为 EFUSE。 |
gpio_power | 写入期间驱动 VDDQ 的单个有效 GPIO。GPIO 的申请、复用和方向配置由 BSP 负责。 |
is_initialized | hal_efuse_handle_init() 成功后为 true。 |
is_timing_ready | hal_efuse_set_timing() 成功后为 true。所有段读写都要求该标志为 true。 |
HAL 不拥有全局锁。同一 EFUSE 控制器的并发访问必须由 BSP 或调用方串行化。
2. HAL 接口规范
2.1 查询、初始化和时序
| 接口 | 功能 | 关键约束 |
|---|---|---|
hal_efuse_segment_is_valid(seg_id) | 检查段 ID 是否处于合法枚举范围。 | 纯查询,可在中断上下文调用。 |
hal_efuse_get_segment_name(seg_id) | 返回段名;非法 ID 返回 "UNKNOWN"。 | 纯查询,可在中断上下文调用。 |
hal_efuse_segment_is_protected(handle, seg_id, is_protected) | 读取 STATE 或 PSRAM_STATE 对应保护位,报告段是否已写保护。 | 需已初始化且 timing-ready 的 handle;无保护位的段返回 false。 |
hal_efuse_handle_init(handle, efusex, gpio_power) | 绑定 EFUSE 实例与 VDDQ GPIO,清除 timing-ready 状态。 | gpio_power 必须是有效单 pin mask;已初始化的 handle 返回 IM_ERR_BUSY。 |
hal_efuse_handle_deinit(handle) | 强制 VDDQ 低电平并清空软件句柄。 | 不访问 EFUSE 寄存器;返回后 handle 不可继续使用。 |
hal_efuse_set_timing(handle, rate_hz) | 按 EFUSE 输入时钟计算并写入 CFG。 | 需已初始化、rate_hz >= 1000,且控制器空闲。成功前不得进行读写。 |
hal_efuse_regs_dump(handle) | 输出已命名的可读寄存器。 | 仅当 CONFIG_SDK_ENABLE_DEBUG_HELPERS 和 CONFIG_EFUSE_ENABLE_DEBUG_HELPERS 均启用时可用,否则返回 IM_ERR_UNSUPPORTED。 |
hal_efuse_set_timing() 使用当前输入时钟周期计算 RD_ADJ、RD_STROBE、WR_ADJ 和 WR_STROBE。读窗口最小值为 500 ns,写调整最小值为 3.8 us,写 strobe 编程脉冲限制在 10.8 至 13.2 us。时钟变更后必须重新调用该接口。
2.2 段级读接口
error_code_t hal_efuse_read_segment( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, uint8_t *buf_out, uint32_t len_bytes); error_code_t hal_efuse_read_segment_ex( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, uint8_t *buf_out, uint32_t len_bytes, bool use_backup);
从段首读取 1..segment_size byte。非 _ex 接口固定 use_backup = false;_ex 接口将 use_backup 映射至 CTRL.REDN,供备份/REDN 路径访问。
读操作流程:
检查 handle 已初始化且已配置时序。
检查段 ID 和 buffer/长度。
清理完成状态;特殊段自动向
SPEEN写入解锁键。以最多 4 byte 的事务写
CTRL.RDEN,轮询STATE.RD_DONE。从
DATA按 little-endian 字节顺序拆包,最后复位控制器。
2.3 偏移读接口
error_code_t hal_efuse_read( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, uint32_t start_byte, uint32_t size_bytes, uint8_t *buf_out); error_code_t hal_efuse_read_ex( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, uint32_t start_byte, uint32_t size_bytes, uint8_t *buf_out, bool use_backup);
start_byte + size_bytes 不得超过段大小。size_bytes == 0 时允许 buf_out == NULL,直接返回 IM_OK,不访问硬件。当前 HAL 为保持统一段访问语义,会先读取完整段到内部临时 buffer,再复制请求范围。
2.4 段级写接口
error_code_t hal_efuse_write_segment( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, const uint8_t *buf, uint32_t len_bytes); error_code_t hal_efuse_write_segment_ex( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, const uint8_t *buf, uint32_t len_bytes, bool use_backup);
从段首写入 1..segment_size byte。写操作先读当前值,并对每个字节计算:
program_value = input & ~old expected = old | input
因此,已为 1 的 bit 不会重复烧写,输入中的 0 不能清除已有 1。若没有待烧写 bit,HAL 仍执行保护检查和读回验证。
写入一个 1 至 4 byte 分块时,HAL 会:
检查段是否允许写入,以及
STATE或PSRAM_STATE对应保护位是否已置位。特殊段自动解锁;普通段按元数据判断是否需要
SPEEN。拉高 VDDQ GPIO,等待至少 10 us 稳定。
写
DATA和CTRL.WREN,轮询STATE.WR_DONE。无论事务结果如何都拉低 VDDQ,并清除写完成状态。
重新读取目标范围,验证结果等于
expected。
2.5 偏移写接口
error_code_t hal_efuse_write( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, const uint8_t *buf, uint32_t start_byte, uint32_t size_bytes); error_code_t hal_efuse_write_ex( const hal_efuse_handle_t *handle, hal_efuse_segment_id_t seg_id, const uint8_t *buf, uint32_t start_byte, uint32_t size_bytes, bool use_backup);
偏移写会先读取完整段,再只编程请求范围,最后只验证请求范围。范围约束与偏移读相同;size_bytes == 0 直接返回 IM_OK,不触发任何编程。
2.6 HAL 调用约束
除
hal_efuse_segment_is_valid()和hal_efuse_get_segment_name()外,HAL 接口会访问硬件、GPIO 或轮询,不应在中断上下文调用。调用方应在时钟稳定后调用
hal_efuse_set_timing();任何可能改变 EFUSE 输入时钟的操作后均需重新配置。VDDQ GPIO 应由 BSP 正确申请、初始化为输出低电平,并且不得被其他功能复用。
PROT、SPECIAL、PROT_BK、PSRAM_INIT_PROT和SPECIAL_BK的写入可能改变后续段的可访问性,必须单独评审。