API GUIDE / JPEGD / HAL
G32S10 JPEGD HAL 接口
HAL 层接口:详见 code/include/drivers/g32s10/jpegd/hal_jpegd.h 和 code/drivers/g32s10/jpegd/hal_jpegd.c。
1. HAL JPEGD 接口
详见 code/include/drivers/g32s10/jpegd/hal_jpegd.h 和 code/drivers/g32s10/jpegd/hal_jpegd.c。
1.1 公开类型
1.1.1 hal_jpegd_pixel_format_t
| 值 | 说明 |
|---|---|
HAL_JPEGD_PIX_FMT_NV12 | Semi-planar NV12/YUV420 输出 |
HAL_JPEGD_PIX_FMT_YUYV | Packed YUYV/YUV422 输出 |
HAL_JPEGD_PIX_FMT_Y | 单 Y 平面输出 |
1.1.2 hal_jpegd_irq_event_t 和 hal_jpegd_callback_t
| 事件 | 说明 |
|---|---|
HAL_JPEGD_IRQ_EVENT_NONE | 无事件;HAL 不会向已注册回调分发该值 |
HAL_JPEGD_IRQ_EVENT_FRAME_DONE | 当前帧完成 |
HAL_JPEGD_IRQ_EVENT_TIMEOUT | 当前帧发生硬件 timeout |
hal_jpegd_callback_t 的原型为 void (*)(hal_jpegd_irq_event_t event)。回调由hal_jpegd_irq_handler() 在平台 IRQ 上下文调用,不能阻塞。
1.1.3 hal_jpegd_tables_t
| 字段 | 类型 | 说明 |
|---|---|---|
qt_y | const uint32_t * | Y 分量量化表,16 word,不能为 NULL |
qt_u | const uint32_t * | U 分量量化表,16 word,不能为 NULL |
qt_v | const uint32_t * | V 分量量化表,16 word,不能为 NULL |
huffmin | const uint32_t * | Huffman minimum 表,16 word,不能为 NULL |
huffbase | const uint32_t * | Huffman base 表,64 word,不能为 NULL |
huffsymb | const uint32_t * | Huffman symbol 表,336 word,不能为 NULL |
这些指针表示调用方准备好的硬件表 payload。hal_jpegd_sequence_configure() 会把表内容写入 JPEGD 寄存器数组;该函数返回后,HAL 后续单帧启动不再访问这些表指针。
1.1.4 hal_jpegd_param_t
| 字段 | 类型 | 说明 |
|---|---|---|
width | uint32_t | 输出图像宽度,当前 HAL 校验范围 8-1920 |
height | uint32_t | 输出图像高度,当前 HAL 校验范围 8-1440 |
out_format | hal_jpegd_pixel_format_t | 输出像素格式 |
tables | hal_jpegd_tables_t | 调用方准备好的 QT/Huffman 硬件表 |
1.1.5 hal_jpegd_restart_config_t
| 字段 | 类型 | 说明 |
|---|---|---|
restart_markers_en | bool | 是否使能 restart marker 解码 |
restart_mcu_num | uint32_t | restart interval,启用时必须在 1..mcu_number |
1.1.6 hal_jpegd_config_t
| 字段 | 类型 | 说明 |
|---|---|---|
re | hal_jpegd_restart_config_t | Restart marker 解码配置 |
timeout_en | bool | true 时打开硬件 timeout 检测和 timeout interrupt |
timeout_threshold | uint32_t | 硬件 timeout 阈值;建议由 hal_jpegd_struct_init() 填默认值 |
timeout_ms | uint32_t | 供上层等待策略使用的超时提示;HAL 不读取该字段,0 由上层解释 |
reset_cycle | uint32_t | 软件 reset pulse field,范围 0-15;0 时 reset 流程使用默认值 |
1.1.7 hal_jpegd_frame_t
| 字段 | 类型 | 说明 |
|---|---|---|
bitstream_addr | const void * | 输入 entropy bitstream 地址,不能为 NULL |
bitstream_size | uint32_t | 输入 bitstream 字节数,必须非 0,用于 cache clean |
dst_y_addr | void * | 输出 Y 平面或 packed RAW 起始地址,必须 16 字节对齐 |
dst_uv_addr | void * | NV12 输出 UV 起始地址;为 NULL 时 HAL 使用紧凑布局推导 |
dst_buf_size | uint32_t | 输出 buffer 总容量,必须覆盖 HAL 计算出的输出容量 |
output_size | uint32_t | hal_jpegd_get_result() 回填的实际 RAW 输出字节数 |
1.2 公开函数
void hal_jpegd_struct_init(hal_jpegd_param_t *param, hal_jpegd_config_t *config, hal_jpegd_frame_t *frame); error_code_t hal_jpegd_reset(const hal_jpegd_config_t *config); error_code_t hal_jpegd_init(const hal_jpegd_config_t *config); error_code_t hal_jpegd_callback_register(hal_jpegd_callback_t callback); void hal_jpegd_irq_handler(void); error_code_t hal_jpegd_sequence_configure(const hal_jpegd_param_t *param, const hal_jpegd_config_t *config); error_code_t hal_jpegd_start_frame(const hal_jpegd_frame_t *frame); error_code_t hal_jpegd_get_result(hal_jpegd_frame_t *frame); error_code_t hal_jpegd_deinit(void); error_code_t hal_jpegd_regs_dump(void);
推荐调用顺序:
1.3 默认值
hal_jpegd_struct_init() 会清零 param/config/frame,然后设置以下默认值:
| 字段 | 默认值 |
|---|---|
param.out_format | HAL_JPEGD_PIX_FMT_NV12 |
config.timeout_threshold | 0x00ffffff |
config.timeout_ms | 1000 |
config.reset_cycle | 10 |
width、height、tables、bitstream_addr、bitstream_size、dst_y_addr、dst_buf_size 等字段仍需由调用方填写。
1.4 初始化、复位和反初始化
error_code_t hal_jpegd_reset(const hal_jpegd_config_t *config); error_code_t hal_jpegd_init(const hal_jpegd_config_t *config); error_code_t hal_jpegd_deinit(void);
hal_jpegd_reset() 内部流程:
校验
config != NULL和reset_cycle <= 15若
reset_cycle == 0,使用 HAL 默认 reset cycle写
SW_RESET_CYCLE使能 sequence reset 覆盖 sequence-level registers
触发
SW_SEQ_RESET按 SPEC 轮询
JPEG_DEC_TRIG[31] RESET_END,为 1 后才继续;超时返回IM_ERR_TIMEOUT
hal_jpegd_init() 内部流程:
校验 runtime config
清 HAL 内部 context 并保存 config
检查 systick 是否初始化
执行
hal_jpegd_reset()关闭所有 JPEGD 中断并清 pending
设置内部 initialized 状态
hal_jpegd_deinit() 会关闭所有中断、清 pending、执行 reset,并清除 HAL 内部 context 和 initialized 状态。反初始化后回调恢复为 HAL 内部 no-op 回调。每次 hal_jpegd_init() 也会先恢复该 no-op 回调,因此需要在 init 成功后重新注册业务回调。
1.5 序列配置
error_code_t hal_jpegd_sequence_configure(const hal_jpegd_param_t *param, const hal_jpegd_config_t *config);
该函数用于配置一组解码序列的固定参数,包括图像尺寸、输出格式、stride、MCU 数、QT/Huffman 表、restart marker 和 timeout。
参数校验:
| 参数 | 条件 |
|---|---|
param/config | 不能为 NULL |
width | 8-1920 |
height | 8-1440 |
out_format | 必须为 NV12/YUV420、YUYV/YUV422 或单 Y |
tables.qt_y/qt_u/qt_v | 不能为 NULL |
tables.huffmin/huffbase/huffsymb | 不能为 NULL |
reset_cycle | 0-15 |
restart_mcu_num | restart_markers_en=true 时必须在 1..mcu_number |
| HAL 状态 | 必须已经 hal_jpegd_init() |
寄存器配置:
根据输出格式计算对齐宽高、stride、MCU 数和输出容量
固定写 table selector:Y 使用 table 0,U/V 使用 table 1
写
qt_tab_y[16]、qt_tab_u[16]、qt_tab_v[16]写
huffmin[16]、huffbase[64]、huffsymb[336]根据
config.re配置 restart marker根据
config.timeout_en配置硬件 timeout 和 timeout interrupt使能 frame-end interrupt status
写对齐宽高、stride、输出 RAW 字节总数、MCU 数和输出格式
1.6 单帧启动、中断和取结果
error_code_t hal_jpegd_callback_register(hal_jpegd_callback_t callback); void hal_jpegd_irq_handler(void); error_code_t hal_jpegd_start_frame(const hal_jpegd_frame_t *frame); error_code_t hal_jpegd_get_result(hal_jpegd_frame_t *frame);
hal_jpegd_start_frame():
校验 HAL 已初始化、sequence config 已配置
保存 frame 到 HAL 内部 context
清除历史中断状态
校验
bitstream_addr != NULL、bitstream_size != 0校验
dst_buf_size >= HAL 计算出的输出容量校验
dst_y_addr16 字节对齐写
BS_ADDR和RAWY_ADDR对 input bitstream 执行 cache clean
对输出 Y/RAWY 范围执行 clean+invalidate
NV12/YUV420 输出下配置 UV 地址;若
dst_uv_addr == NULL,按紧凑布局推导触发
START
hal_jpegd_callback_register():
只能在
hal_jpegd_init()成功后调用传入非空回调后,JPEGD 中断事件由该回调接收
传入
NULL后恢复 HAL 内部 no-op 回调回调在平台 IRQ 上下文执行,不能阻塞;事件为
HAL_JPEGD_IRQ_EVENT_FRAME_DONE或HAL_JPEGD_IRQ_EVENT_TIMEOUT
hal_jpegd_irq_handler():
HAL 不注册 CPU IRQ handler;平台 IRQ 入口必须在收到 JPEGD IRQ 后调用本函数
函数读取
INTR_STAT,清除当前 pending 状态,再向已注册回调分发事件未初始化、无 pending 状态或未处于已启动帧状态时直接返回
同时出现 timeout 和 frame-end 时优先分发 timeout 事件
hal_jpegd_get_result():
校验
frame != NULL和frame->dst_y_addr != NULL校验 HAL 已初始化、sequence 已配置,且已启动帧已由
hal_jpegd_irq_handler()收尾读取
GLB_STAT.RAW_LEN若输出大小超过
dst_buf_size,返回IM_ERR_NO_SPACE对输出 buffer 执行 cache invalidate
回填
frame->output_size触发
SW_FRM_RESET
调用方必须在收到 HAL_JPEGD_IRQ_EVENT_FRAME_DONE 后再调用本函数,并传入与hal_jpegd_start_frame() 相同的输出 buffer 字段。帧仍在运行时该函数返回IM_ERR_NOT_READY。
1.7 Cache 管理
HAL 当前在以下位置进行 cache 维护:
| 阶段 | 地址 | 操作 | 目的 |
|---|---|---|---|
start_frame | bitstream_addr,长度 bitstream_size | clean | 确保硬件读到 CPU 已准备好的 entropy bitstream |
start_frame | dst_y_addr,长度 rawy_size | clean+invalidate | 避免 CPU 脏 cache line 在硬件写结果后覆盖 Y/RAW 输出 |
start_frame | dst_uv_addr 或推导 UV 地址,长度 rawc_size | clean+invalidate | NV12/YUV420 下避免 CPU 脏 cache line 覆盖 UV 输出 |
get_result | dst_y_addr,长度 HAL 计算出的输出容量 | invalidate | 让 CPU 读取硬件写入后的 RAW 输出 |
调用方在 hal_jpegd_start_frame() 到 hal_jpegd_get_result() 之间不应修改 input bitstream 或 output buffer。
1.8 线程安全与中断策略
JPEGD HAL 当前通过平台 IRQ 入口调用 hal_jpegd_irq_handler(),再由注册回调接收帧结束或硬件 timeout 事件。HAL 不等待、不轮询 INTR_STAT,也不负责注册或释放 SoC IRQ。
当前 HAL 使用模块级静态 context,不支持多实例并发或无锁多线程访问。回调运行于 IRQ 上下文,不能执行阻塞操作;若上层需要在多任务环境使用 JPEGD,应在 HAL 调用外侧加锁,并使用 ISR 安全的通知机制。
1.9 Debug Register Dump
error_code_t hal_jpegd_regs_dump(void);
hal_jpegd_regs_dump() 用 INFO log 输出 JPEGD 可读寄存器,便于和 spec 或异常现场对照。该接口由两个 Kconfig 开关控制:
| 开关 | 说明 |
|---|---|
CONFIG_SDK_ENABLE_DEBUG_HELPERS | SDK 全局 debug helper 开关 |
CONFIG_JPEGD_ENABLE_DEBUG_HELPERS | JPEGD driver debug helper 开关 |
未同时打开这两个开关时,接口仍保留,但直接返回 IM_ERR_UNSUPPORTED。
默认 dump 内容包括普通控制寄存器、状态寄存器和 0x108-0x16C 的 JPEGD debug 寄存器。INTR_CLR 是 write-only 寄存器,dump 时只打印 <skip>,不会读取。
QT/Huffman 表寄存器默认跳过,避免一次 dump 打出过长日志。需要确认表内容时,可在编译参数中打开:
#define HAL_JPEGD_DUMP_READ_TABLES 1U
打开后会额外打印:
| 表 | 数量 |
|---|---|
QT_TAB_Y | 16 word |
QT_TAB_U | 16 word |
QT_TAB_V | 16 word |
HUFFMIN | 16 word |
HUFFBASE | 64 word |
HUFFSYMB | 336 word |
2. HAL 调用代码骨架
下面代码只展示 HAL 层入参和调用顺序。qt_*、huff*、entropy_bs 和输出 buffer 均由调用方提前准备。
#include "hal_jpegd.h"
#define JPEGD_DST_ALIGN 16U
extern const uint32_t qt_y[16];
extern const uint32_t qt_u[16];
extern const uint32_t qt_v[16];
extern const uint32_t huffmin[16];
extern const uint32_t huffbase[64];
extern const uint32_t huffsymb[336];
extern const void *entropy_bs;
extern uint32_t entropy_bs_size;
static volatile hal_jpegd_irq_event_t jpegd_event;
static void jpegd_irq_callback(hal_jpegd_irq_event_t event)
{
jpegd_event = event;
}
void board_jpegd_irq_handler(void)
{
hal_jpegd_irq_handler();
}
/* Platform-specific task/ISR synchronization, implemented by the caller. */
extern error_code_t wait_for_jpegd_event(volatile hal_jpegd_irq_event_t *event);
static uint8_t raw_dst[1024U * 1024U] __attribute__((aligned(JPEGD_DST_ALIGN)));
error_code_t run_jpegd_hal_decode(void)
{
hal_jpegd_param_t param;
hal_jpegd_config_t config;
hal_jpegd_frame_t frame;
error_code_t ret;
error_code_t deinit_ret;
hal_jpegd_struct_init(¶m, &config, &frame);
param.width = 640U;
param.height = 480U;
param.out_format = HAL_JPEGD_PIX_FMT_NV12;
param.tables.qt_y = qt_y;
param.tables.qt_u = qt_u;
param.tables.qt_v = qt_v;
param.tables.huffmin = huffmin;
param.tables.huffbase = huffbase;
param.tables.huffsymb = huffsymb;
config.re.restart_markers_en = true;
config.re.restart_mcu_num = 21U;
frame.bitstream_addr = entropy_bs;
frame.bitstream_size = entropy_bs_size;
frame.dst_y_addr = raw_dst;
frame.dst_uv_addr = NULL;
frame.dst_buf_size = sizeof(raw_dst);
ret = hal_jpegd_init(&config);
if (ret != IM_OK) {
return ret;
}
ret = hal_jpegd_callback_register(jpegd_irq_callback);
if (ret != IM_OK) {
goto cleanup;
}
ret = hal_jpegd_sequence_configure(¶m, &config);
if (ret != IM_OK) {
goto cleanup;
}
jpegd_event = HAL_JPEGD_IRQ_EVENT_NONE;
ret = hal_jpegd_start_frame(&frame);
if (ret != IM_OK) {
goto cleanup;
}
/* The platform JPEGD IRQ entry must call hal_jpegd_irq_handler().
* The registered callback should notify the task that the frame ended. */
ret = wait_for_jpegd_event(&jpegd_event);
if ((ret != IM_OK) || (jpegd_event != HAL_JPEGD_IRQ_EVENT_FRAME_DONE)) {
ret = (ret == IM_OK) ? IM_ERR_TIMEOUT : ret;
goto cleanup;
}
ret = hal_jpegd_get_result(&frame);
cleanup:
deinit_ret = hal_jpegd_deinit();
if ((ret == IM_OK) && (deinit_ret != IM_OK)) {
return deinit_ret;
}
return ret;
}