API GUIDE / MSCALER / Middleware
G32S10 MSCALER Middleware 接口
Middleware 层接口:状态字段是 volatile,因为 frame-end 回调会在中断上下文读取它。
1. 公开数据类型
1.1 im_mscaler_state_t
| 状态 | 含义 |
|---|---|
IM_MSCALER_STATE_RESET | 没有活动会话;需要先调用 im_mscaler_init() |
IM_MSCALER_STATE_INITIALIZED | 会话已建立,尚未成功完成静态配置 |
IM_MSCALER_STATE_CONFIGURED | 静态配置已生效,硬件空闲,可以启动下一帧 |
IM_MSCALER_STATE_RUNNING | 已启动一帧,正在等待 frame-end |
状态字段是 volatile,因为 frame-end 回调会在中断上下文读取它。
2. 会话状态机
im_mscaler_init()
IM_MSCALER_STATE_RESET -------------------> IM_MSCALER_STATE_INITIALIZED
^ |
| im_mscaler_convert()
| |
| v
| configure success
| |
| v
| IM_MSCALER_STATE_CONFIGURED
| |
| im_mscaler_convert()
| |
| v
| IM_MSCALER_STATE_RUNNING
| |
| frame-end + get_result
| |
| v
| IM_MSCALER_STATE_CONFIGURED
|
+-------------------------------- frame-end timeout
|
v
IM_MSCALER_STATE_ERROR
|
next convert recovery
|
v
IM_MSCALER_STATE_INITIALIZED
状态转换规则:
| 当前状态 | 操作 | 结果 |
|---|---|---|
RESET |
im_mscaler_init() 成功 |
INITIALIZED |
INITIALIZED |
首次 im_mscaler_convert() 配置成功 |
CONFIGURED,随后进入 RUNNING |
INITIALIZED |
配置失败 | 保持 INITIALIZED |
CONFIGURED |
im_mscaler_convert() |
RUNNING,成功后回到 CONFIGURED |
CONFIGURED |
参数变化后 im_mscaler_convert() |
重新配置后进入 RUNNING |
RUNNING |
frame-end 超时 | 停止并复位硬件,进入 ERROR |
ERROR |
im_mscaler_convert() 恢复成功 |
INITIALIZED,随后重新配置 |
CONFIGURED / INITIALIZED |
im_mscaler_deinit() |
释放会话,回到 RESET |
RESET |
im_mscaler_deinit() |
返回 IM_OK,不做任何操作 |
3. API 详细说明
3.1 im_mscaler_init()
error_code_t im_mscaler_init(uint32_t timeout_ms);
功能:
- 初始化内部
thread_waiter。 - 申请并使能
IRQ_SCALER。 - 调用
hal_mscaler_init()打开时钟和门控并初始化寄存器状态。 - 注册 MID 内部的 frame-done 回调。
- 保存超时值并进入
IM_MSCALER_STATE_INITIALIZED。
timeout_ms 只影响后续 frame-end 等待。传入 0 时使用 MID 内部默认值
800 ms。
返回值:
| 返回值 | 原因 |
|---|---|
IM_OK |
会话建立成功 |
IM_ERR_BUSY |
已经存在活动会话 |
| 其他错误 | IRQ 申请/使能或 HAL 初始化失败 |
初始化失败时,MID 会回滚已经申请的资源,状态保持 RESET。
3.2 im_mscaler_convert()
error_code_t im_mscaler_convert(im_mscaler_frame_t *frame);
这是当前 MID 唯一的逐帧处理入口,执行过程是同步的:
- 检查
frame != NULL。 - 检查会话状态必须为
INITIALIZED或CONFIGURED。 - 首次调用或静态参数变化时,调用 HAL 重新配置几何、格式、算法和联动参数。
- 把会话状态切到
RUNNING。 - 调用
hal_mscaler_start(),由 HAL 写地址、stride、维护 cache 并启动 RDMA。 - 在
thread_waiter上等待 frame-end 中断。 - 调用
hal_mscaler_get_result()invalidate 输出 cache。 - 成功后回到
CONFIGURED,允许直接提交下一帧。
配置复用条件:只有以下字段变化时才重新配置:
out_fmtsrc_width/src_heightdst_width/dst_heightmstj.out_buff_nummstj.is_enabled
当前帧的 src_y_addr、src_uv_addr、dst_y_addr、dst_uv_addr 不参与
静态配置比较,每帧可以使用不同地址。
返回值:
| 返回值 | 原因 |
|---|---|
IM_OK |
帧处理完成,输出 cache 已同步 |
IM_ERR_INVALID_PARAM |
frame == NULL,或 HAL 参数、尺寸、格式、地址、out_buff_num 非法 |
IM_ERR_NOT_READY |
会话未初始化 |
IM_ERR_TIMEOUT |
frame-end 等待超时,或超时后硬件停止/复位失败 |
| 其他 HAL 错误 | 配置、启动或结果同步阶段失败 |
如果每帧传入的静态参数都不相同,MID 会在每帧重新配置。需要保持配置复用时, 应保证上述参与比较的字段在连续帧之间完全一致。
失败时的状态:
- 静态配置失败:状态保持
INITIALIZED。 hal_mscaler_start()失败:静态配置保留,状态回到CONFIGURED;修正当前帧 地址后可以再次调用im_mscaler_convert()。- frame-end 超时:MID 立即写 stop 并等待
WORK_STATidle,随后复位寄存器, 状态进入ERROR。只有停止/复位成功后才允许释放当前帧 buffer;下一次im_mscaler_convert()会完成恢复并重新配置。 - 超时后的 stop/reset 失败:保留
ERROR状态并返回停止/复位错误。调用方不得 释放当前帧 buffer;可以重试im_mscaler_reset()或再次调用im_mscaler_convert()触发恢复。
3.3 im_mscaler_set_clk_rate()
error_code_t im_mscaler_set_clk_rate(uint32_t rate_hz);
用于切换 MSCALER 模块时钟。父时钟固定为 MPLL,HAL 只调整分频比,分频结果
向上取整,因此实际频率不会高于请求值。当前控制器上限为 170 MHz。
| 参数 | 说明 |
|---|---|
rate_hz == 0 | 选择不超过控制器上限的最高频率 |
rate_hz > 0 | 请求的模块时钟频率 |
需要恢复初始化后的默认时钟时,显式调用 im_mscaler_set_clk_rate(0U)。
调用约束:
| 状态 | 行为 |
|---|---|
RESET | 返回 IM_ERR_NOT_READY |
INITIALIZED | 允许设置 |
CONFIGURED | 允许设置,不需要重新做静态配置 |
RUNNING | 返回 IM_ERR_BUSY |
频率超过控制器上限时 HAL 返回 IM_ERR_INVALID_PARAM,CPM 错误会原样
向上返回。
3.4 im_mscaler_get_clk_rate()
uint32_t im_mscaler_get_clk_rate(void);
读取 CPM 当前实际生效的 MSCALER 模块频率。该接口不检查会话状态;无法测量
时返回 0。因为内部也使用同一把 MID 互斥锁,一次正在执行的im_mscaler_convert() 可能使该调用等待到转换结束。
3.5 im_mscaler_get_state()
im_mscaler_state_t im_mscaler_get_state(void);
返回当前状态快照。该函数不加锁,适合诊断或超时后确认会话是否仍然存在; 返回值只代表读取瞬间的状态。
3.6 im_mscaler_deinit()
error_code_t im_mscaler_deinit(void);
释放 HAL、frame-end 回调、IRQ 和等待器资源,并把状态置为IM_MSCALER_STATE_RESET。
| 情况 | 结果 |
|---|---|
| 没有活动会话 | IM_OK,空操作 |
| 有活动会话且空闲 | 释放资源并返回 IM_OK |
RUNNING | 返回 IM_ERR_BUSY |
frame-end 超时后 MID 保留会话为 ERROR;下一次 im_mscaler_convert() 会自动恢复,只有 im_mscaler_deinit() 才回到 RESET。
4. 典型用法
4.1 连续帧
ret = im_mscaler_init(0U);
if (ret != IM_OK) {
return ret;
}
for (frame_index = 0U; frame_index < frame_count; frame_index++) {
msca.frame.src_y_addr = get_source(frame_index);
msca.frame.src_uv_addr = NULL; /* NV12:由 HAL 按 stride * height 推导 */
msca.frame.dst_y_addr = get_destination(frame_index);
msca.frame.dst_uv_addr = NULL;
ret = im_mscaler_convert(&msca);
if (ret != IM_OK) {
break;
}
}
if (im_mscaler_get_state() != IM_MSCALER_STATE_RESET) {
(void)im_mscaler_deinit();
}只要 param 不变,MID 就不会在循环内重复配置几何和算法。
4.2 设置并确认模块时钟
uint32_t actual_hz;
error_code_t ret;
ret = im_mscaler_init(0U);
if (ret != IM_OK) {
return ret;
}
ret = im_mscaler_set_clk_rate(150000000U);
if (ret == IM_OK) {
actual_hz = im_mscaler_get_clk_rate();
if (actual_hz == 0U) {
/* CPM 读数不可用,或 stub 构建。 */
}
}时钟设置应在帧启动前完成。达到 CONFIGURED 后切换时钟不需要重新配置几何。