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);

功能:

  1. 初始化内部 thread_waiter。
  2. 申请并使能 IRQ_SCALER。
  3. 调用 hal_mscaler_init() 打开时钟和门控并初始化寄存器状态。
  4. 注册 MID 内部的 frame-done 回调。
  5. 保存超时值并进入 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 唯一的逐帧处理入口,执行过程是同步的:

  1. 检查 frame != NULL。
  2. 检查会话状态必须为 INITIALIZED 或 CONFIGURED。
  3. 首次调用或静态参数变化时,调用 HAL 重新配置几何、格式、算法和联动参数。
  4. 把会话状态切到 RUNNING。
  5. 调用 hal_mscaler_start(),由 HAL 写地址、stride、维护 cache 并启动 RDMA。
  6. 在 thread_waiter 上等待 frame-end 中断。
  7. 调用 hal_mscaler_get_result() invalidate 输出 cache。
  8. 成功后回到 CONFIGURED,允许直接提交下一帧。

配置复用条件:只有以下字段变化时才重新配置:

  • out_fmt
  • src_width / src_height
  • dst_width / dst_height
  • mstj.out_buff_num
  • mstj.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_STAT idle,随后复位寄存器, 状态进入 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 后切换时钟不需要重新配置几何。