API GUIDE / MSCALER / OVERVIEW

G32S10 MSCALER API 概述

模块概述:本文覆盖 MSCALER 的三层接口:

1. 文档范围

本文覆盖 MSCALER 的三层接口:

  1. mscaler_regs.h:MSCALER 寄存器结构体、基地址和位域宏

  2. ll_mscaler.h:寄存器级 static inline 读写接口

  3. hal_mscaler.h / hal_mscaler.c:面向上层的静态配置、逐帧启动与 JPEG 联动接口

本文描述当前代码实际实现的配置、校验、cache 维护和中断完成路径。图像 buffer 的分配和生命周期由调用方负责。

2. 分层关系

APPLICATION  Application  缩放业务或显示/图像处理上层
→
HAL  HAL MSCALER  struct_init / init / set_configure
callback_register / start / get_result
→
LL  LL MSCALER  static inline 寄存器访问
→
REGISTERS  mscaler_regs.h  寄存器结构、实地址与位域 mask
  • mscaler_regs.h 定义寄存器布局、位域 mask 和寄存器访问实例。

  • LL 仅进行寄存器读写,不保存任务状态,也不做完整参数校验。

  • HAL 计算 stride、缩放步进和算法参数,校验地址,维护 cache,并读取、清除和分发 frame-end 中断。

  • 应用负责注册 SoC IRQ、提供回调和等待机制,并提供满足格式、容量和 8-byte 对齐要求的输入/输出 buffer;HAL 不分配或搬运 buffer。

3. 典型用法

以下示例均只展示 HAL 层调用。应用负责 register_scaler_irq()、wait_for_frame_done() 和帧缓冲区的获取;这些函数内部应分别连接 SoC IRQ、等待已注册 callback 发出的完成通知,以及提供满足格式、容量和 8-byte 对齐要求的 buffer。

3.1 单帧

单帧流程只处理一个源 buffer:初始化 HAL,配置静态参数,启动一次,等待 frame-end,取回结果后反初始化。

#include "hal_mscaler.h"

#define SRC_WIDTH   640U
#define SRC_HEIGHT  480U
#define DST_WIDTH   320U
#define DST_HEIGHT  240U
#define SRC_Y_SIZE  (SRC_WIDTH * SRC_HEIGHT)
#define DST_Y_SIZE  (DST_WIDTH * DST_HEIGHT)

error_code_t run_mscaler_nv12_frame(uint8_t *src, uint8_t *dst)
{
    hal_mscaler_input_param_t param;
    hal_mscaler_config_t config;
    error_code_t ret;

    hal_mscaler_struct_init(&param, &config);
    param.out_fmt = HAL_MSCALER_FORMAT_NV12;
    param.src_width = SRC_WIDTH;
    param.src_height = SRC_HEIGHT;
    param.dst_width = DST_WIDTH;
    param.dst_height = DST_HEIGHT;
    param.src_y_addr = src;
    param.src_uv_addr = &src[SRC_Y_SIZE];
    param.dst_y_addr = dst;
    param.dst_uv_addr = &dst[DST_Y_SIZE];
    config.mstj.is_enabled = false;

    ret = hal_mscaler_init();
    if (ret == IM_OK) {
        ret = hal_mscaler_callback_register(frame_done_callback);
    }
    if (ret == IM_OK) {
        ret = register_scaler_irq();
    }
    if (ret == IM_OK) {
        ret = hal_mscaler_set_configure(&param, &config);
    }
    if (ret == IM_OK) {
        ret = hal_mscaler_start(&param);
    }
    if (ret == IM_OK) {
        ret = wait_for_frame_done(config.timeout_ms);
    }
    if (ret == IM_OK) {
        ret = hal_mscaler_get_result(&param);
    }

    unregister_scaler_irq();
    (void)hal_mscaler_callback_register(NULL);
    hal_mscaler_deinit();
    return ret;
}

3.2 连续帧

连续帧流程只配置一次尺寸、格式、缩放算法和 JPEG 联动参数;每次循环更换当前帧的源/目标地址,再调用一次 hal_mscaler_start()。

#include "hal_mscaler.h"

#define SRC_WIDTH   640U
#define SRC_HEIGHT  480U
#define DST_WIDTH   320U
#define DST_HEIGHT  240U
#define SRC_Y_SIZE  (SRC_WIDTH * SRC_HEIGHT)
#define DST_Y_SIZE  (DST_WIDTH * DST_HEIGHT)

error_code_t run_mscaler_nv12_stream(void)
{
    hal_mscaler_input_param_t param;
    hal_mscaler_config_t config;
    uint8_t *src;
    uint8_t *dst;
    uint32_t frame_index;
    error_code_t ret;

    hal_mscaler_struct_init(&param, &config);
    param.out_fmt = HAL_MSCALER_FORMAT_NV12;
    param.src_width = SRC_WIDTH;
    param.src_height = SRC_HEIGHT;
    param.dst_width = DST_WIDTH;
    param.dst_height = DST_HEIGHT;
    config.mstj.is_enabled = false;

    ret = hal_mscaler_init();
    if (ret != IM_OK) {
        return ret;
    }
    ret = hal_mscaler_callback_register(frame_done_callback);
    if (ret == IM_OK) {
        ret = register_scaler_irq();
    }
    if (ret == IM_OK) {
        /* Static geometry and algorithm configuration is done once. */
        ret = hal_mscaler_set_configure(&param, &config);
    }

    for (frame_index = 0U; (ret == IM_OK) && (frame_index < FRAME_COUNT);
         frame_index++) {
        ret = get_next_frame_buffers(frame_index, &src, &dst);
        if (ret != IM_OK) {
            break;
        }

        /* Only the frame addresses change between starts. */
        param.src_y_addr = src;
        param.src_uv_addr = &src[SRC_Y_SIZE];
        param.dst_y_addr = dst;
        param.dst_uv_addr = &dst[DST_Y_SIZE];

        ret = hal_mscaler_start(&param);
        if (ret == IM_OK) {
            ret = wait_for_frame_done(config.timeout_ms);
        }
        if (ret == IM_OK) {
            ret = hal_mscaler_get_result(&param);
        }
    }

    unregister_scaler_irq();
    (void)hal_mscaler_callback_register(NULL);
    hal_mscaler_deinit();
    return ret;
}

启用 JPEG 联动时,将 config.mstj.is_enabled 设为 true,并按图像格式和 JPEG 消费时序填写 out_buff_num 与 out_bline_num。

4. 错误码速查

错误码常见原因
IM_OK初始化、启动、中断驱动的帧完成等待或结果 cache 同步成功。
IM_ERR_INVALID_PARAM尺寸不在 HAL 范围内、格式非法、缩放步进超过 0x7ffff、Y 地址或显式/推导后的 UV 地址无效或未 8-byte 对齐、帧参数与静态配置不匹配,或 out_bline_num > dst_height。
IM_ERR_NOT_READYHAL 未初始化、当前任务未配置或尚未完成就取结果。
IM_ERR_BUSY配置仍被上一帧占用,或者调用方在上一帧结束前再次启动。
IM_ERR_TIMEOUT应用等待 frame-end 超过配置的超时时间。

5. 注意事项

  • hal_mscaler_init() 不会配置图像参数。先调用一次 hal_mscaler_set_configure() 写入尺寸、格式和算法;每帧仅调用 hal_mscaler_start() 更新地址、stride 和启动寄存器。

  • hal_mscaler_start() 会拒绝与静态配置不一致的宽高或格式。需要改变这些参数时,先执行 hal_mscaler_deinit(),再初始化和配置。

  • HAL 不校验调用方提供的 buffer 总容量。调用方必须按 HAL 实际 stride 和图像高度计算足够空间,尤其要考虑 8-byte stride 对齐。

  • NV12/YUV420 的 UV 地址可以显式配置,也可以留空由 HAL 按 Y 平面大小推导;无论哪种方式,最终地址都必须有效且 8-byte 对齐。YUV422/ONLY_Y 只需要配置 Y 地址和 stride。

  • 当前 HAL 的 out_fmt 同时用于输入和输出格式,未提供颜色空间或像素格式转换。

  • 当前 HAL 对 YUYV 的源、目标 stride 都乘以 2。使用 YUYV 时应结合 packed buffer 布局和硬件要求审查该配置。

  • INT_COMMON_0_MASK 的 LL 写接口命名为 mask,但 HAL 默认不写该寄存器;HAL 在 IRQ handler 中读取并清除 frame-end 状态。