下面是基于 lk_camera、platform/sprd_shared 与 uis7870_3h10_car 源码的整理。
1. LK Camera 框架(分层与主流程)
1.1 启动与线程模型
| 函数 | 作用 |
|---|---|
pre_task_create()(app/sprdboot/sprd_threads.c) | 快速开机时在 CAMERA_CORE(rules.mk 里为 CPU1)上 thread_create("camera_th", run_camera, ...) |
run_camera()(start_camera.c) | 初始化 s_cam_mgr、置 START_FLAG,调用 run_camera_internel(),结束时 clear_camera_state() 并 sem_post(sem_con) |
run_camera_internel() | 与 Android 侧 camcomm 协同:camcomm_init、register_cam_msg_cb(LKCAM_STATE_STOPPING, stopping_msg_callback),再 check_open_camera → check_config_camera → check_wait_camera_exit → check_flush_camera → check_close_camera |
camera_init() / camera_entry()(APP_START(lk_camera)) | 当前实现为空:真正预览在 run_camera 线程里跑,不在 app 的 .init 里 |
force_close_camera() | notify_camera_exit_block(true)、camera_recycle()、sprd_cam_sys_pw_on()、reset_lk_clk_pd_clk_en(),供切核/关机等路径调用 |
1.2 对外 API(start_camera.h)与状态封装
| 函数 | 作用 |
|---|---|
check_open_camera / check_config_camera / check_flush_camera / check_close_camera | 在 s_cam_mgr 互斥下推进 OPEN/CONFIG/FLUSH/CLOSE 状态位,避免重复或乱序 |
open_camera() | dlopen("libcamoem.so"),dlsym OEM 符号,oem->ops->camera_init(..., camera_callback, ...),初始化 buffer 链表、信号量、互斥锁 |
config_camera() | alloc_buffer(5 块 NV21)→ 可选 pthread_create(display_loop)(async_display==true)→ pthread_create(reverse_line_loop) → start_preview() → 把所有 preview buffer set_img_request 交给驱动 |
flush_camera() | camera_stop_preview,停显示线程 pthread_join(display_th) |
close_camera() | camera_deinit、free_buffer、销毁同步原语 |
notify_camera_exit() / wait_camera_exit() | 与 check_wait_camera_exit 配合,用于线程退出同步 |
1.3 采集与显示数据路径
| 函数 | 作用 |
|---|---|
camera_callback() | 仅处理 CAMERA_EVT_CB_FRAME + CAMERA_FUNC_START_PREVIEW:enqueue_display_buffer → sem_post(display_sem);同步模式会直接 display_one_frame(本工程 async_display=true,走异步) |
start_preview() | camera_fast_ctrl(..., CAMERA_FAST_MODE_FD, 0),设置 preview 尺寸/格式 YUV420、zoom、fps,camera_set_mem_func,camera_start_preview(..., CAMERA_NORMAL_MODE) |
camera_alloc() / camera_free() | 非 preview/video 类型用 cam_mem_alloc/cam_mem_free 向 OEM 提供物理 buffer |
alloc_buffer() / free_buffer() | 预览环形 buffer:NV21 大小 w*h*3/2,链入 prevbuff_list |
enqueue_display_buffer() / dequeue_display_buffer() | 驱动回传的 fd 与 prevbuff_list 匹配后挂到 display_list |
set_img_request() | camera_set_preview_buffer,把空 buffer 还给采集 |
display_loop() | 循环调用 display_one_frame(),直到 stopping |
1.4 设备与 OEM(cameradev)
| 函数 | 作用 |
|---|---|
dev_init() | 注册 gsprd_image、gsprd_sensor、gsprd_camsys_pw_domain 等,按 dev_id 调 probe 或 sensor minit() |
dev_read / dev_write / dev_close | 对注册设备的统一访问(与 Linux 侧 camera 节点抽象类似) |
1.5 与 Android 通信(camcomm)
| 函数/机制 | 作用 |
|---|---|
camcomm_init() / camcomm_deinit() | 共享内存/消息线程,同步 LK 与 Android 的相机状态、电源、GPIO 等 |
set_camera_msg() / get_camera_msg() | 如 LKCAM_STATE_RUNNING、LKCAM_STATE_STOPPING、LKCAM_STATE_STOPPING_SUS、LKCAM_DISPLAY_STATE_* |
register_cam_msg_cb() | 例如注册 LKCAM_STATE_STOPPING → stopping_msg_callback |
1.6 大屏输出(展讯 DPU)
| 函数 | 作用 |
|---|---|
rvc_flip()(platform/sprd_shared/driver/video/sprd/sprd_main.c) | 组两层 sprd_restruct_config,action = ACTION_RVC,在满足宏与 g_env_bootmode/g_last_step/rvc_gpio_check() 时调用 sprd_dispc_flip() |
1.7 板级供电/时钟(uis7870_3h10_car 与 start_camera.c)
| 函数 | 作用 |
|---|---|
wait_mm_wakeup()(target/.../init.c) | 轮询 REG_PMU_APB_PWR_STATUS_DBG_6 中 camera 电源域就绪 |
enable_global_clocks() | BIT_CAMERASYS_GLB_CKG_EN 等打开 MM/相机相关时钟 |
clear_force_shutdown() / sprd_cam_sys_pw_on() / dcam_domain_power_on() / isp_domain_power_on()(start_camera.c) | 通过 PMU 寄存器解除 camera/dcam/isp 强制下电并轮询 power status(调试/回收路径) |
sprd_cam_sys_pw_off() | 强制关 camera 域(配合 force_close_camera 等) |
regulator_init.c / ldo_sleep.c 属于板级 PMIC/LDO 初始化,与 RVC 逻辑无直接函数调用关系,属于整机供电上下文。
2. RVC「快速倒车」相关逻辑(函数列表)
2.1 倒车信号输入
| 函数 | 作用 |
|---|---|
rvc_gpio_check()(rvc/rvc_gpio.c,需 ENABLE_RVC=1 → CONFIG_SPRD_RVC) | 配置 GPIO(代码中为 RVC_GPIO 48),读电平:有效则认为进入倒车场景 |
rvc_gpio.h | 未定义 CONFIG_SPRD_RVC 时内联返回 false,整段 RVC 显示路径被编译裁掉 |
2.2 显示线程里:视频 + 辅助线合成
| 函数 | 作用 |
|---|---|
display_one_frame() | 取一帧 NV21;若 rvc_gpio_check():填 hwlayers[0] 为相机 buffer、hwlayers[1] 为 REVERSELINE_RESERVED_ADDR(LVGL 画的 BGRA 叠加层),调用 rvc_flip(&hwlayers[0],&hwlayers[1]);否则根据 LKCAM_STATE_STOPPING* 走退出或仅更新 display 状态 |
rvc_flip() | DPU 双图层混合(底层 NV21 + 顶层 BGRA 辅助线),ACTION_RVC;在 sprd_main.c 里还有额外条件(如 boot mode、rvc_gpio_check())才执行 sprd_dispc_flip |
2.3 倒车辅助线(LVGL)
| 函数 | 作用 |
|---|---|
reverse_line_loop()(reverseline/reverseline.c) | lv_init(),画缓冲用 REVERSELINE_RESERVED_ADDR,dummy_flush(不落屏,只配合 LVGL),子线程 reverse_line_tick_loop 驱动 lv_tick_inc,主循环 lv_task_handler() 画红/蓝/绿辅助线 |
reverse_line_tick_loop() | 5ms 睡眠 + lv_tick_inc(5) |
2.4 与 Android 切相机的协调(「快速」停 LK 相机)
| 函数 | 作用 |
|---|---|
stopping_msg_callback() | 收到 LKCAM_STATE_STOPPING 时:若 rvc_gpio_check() 仍为真,直接返回 0(打 log「Displaying...」),不 notify_camera_exit_block,避免倒车时 LK 相机被立刻停掉;无倒车信号则 notify_camera_exit_block(false) 让 LK 侧退出 |
3. 逻辑串联(便于你对照代码)
- CPU1 上
run_camera→run_camera_internel:打开 OEM、配置分辨率、起display_loop+reverse_line_loop、开始 preview。 - 帧到达 →
camera_callback→ 显示队列 →display_one_frame。 - GPIO 倒车有效 → 填双层参数 →
rvc_flip→ DPU 显示相机+辅助线;sprd_main.c里对sprd_dispc_flip还有 boot 阶段条件。 - Android 要抢相机时发 STOPPING →
stopping_msg_callback:倒车时先挡住退出,实现倒车场景下 LK 持续显示。
关键点(按函数/文件)
-
RVC 触发与显示主链路
rvc_gpio_check():app/lk_camera/rvc/rvc_gpio.cdisplay_one_frame():app/lk_camera/start_camera.c(判定倒车、组双 layer、调用rvc_flip())rvc_flip():platform/sprd_shared/driver/video/sprd/sprd_main.c(最终sprd_dispc_flip()的条件)
-
倒车辅助线生成(叠加层)
reverse_line_loop()/reverse_line_tick_loop():app/lk_camera/reverseline/reverseline.c- 关键缓冲:
REVERSELINE_RESERVED_ADDR(叠加层地址)
-
快速倒车“不断流”机制
stopping_msg_callback():app/lk_camera/start_camera.c(Android 发 STOPPING 时,若仍倒车则不退出)
-
LK camera 启动框架
pre_task_create():app/sprdboot/sprd_threads.c(把run_camera()pin 到CAMERA_CORE=1)run_camera()/run_camera_internel():app/lk_camera/start_camera.copen_camera()/config_camera()/flush_camera()/close_camera():app/lk_camera/start_camera.ccamera_callback():帧回调入队、唤醒显示线程
RVC(快速倒车)从 GPIO 到上屏的时序(函数链)
-
线程拉起
pre_task_create()→thread_create("camera_th", run_camera, ...)(app/sprdboot/sprd_threads.c)run_camera()→run_camera_internel()(app/lk_camera/start_camera.c)
-
相机初始化与预览启动
check_open_camera()→open_camera()dlopen("libcamoem.so")→oem->ops->camera_init(..., camera_callback, ...)
check_config_camera()→config_camera()alloc_buffer()→pthread_create(display_loop)→pthread_create(reverse_line_loop)→start_preview()→set_img_request()(把 5 个 buffer 全部喂给驱动)
-
帧回调到显示
camera_callback()→enqueue_display_buffer()→sem_post(display_sem)display_loop():循环display_one_frame()
-
倒车触发判定(关键分支)
display_one_frame()rvc_gpio_check()(app/lk_camera/rvc/rvc_gpio.c:读RVC_GPIO电平)- 若 true:
- 组
hwlayers[0]= 相机 NV21 帧(底层) - 组
hwlayers[1]=REVERSELINE_RESERVED_ADDR(BGRA8888 辅助线叠加层) - 调
rvc_flip(&hwlayers[0], &hwlayers[1])
- 组
-
真正上屏(DPU 双层 flip)
rvc_flip()(platform/sprd_shared/driver/video/sprd/sprd_main.c)- 填
sprd_restruct_config两层、action = ACTION_RVC - 满足条件时调用
sprd_dispc_flip(dispc, rvc_config)完成上屏
- 填
倒车辅助线生成链(叠加层)
config_camera()里启动reverse_line_loop(handle)reverse_line_loop()lv_init()→lv_disp_draw_buf_init(..., REVERSELINE_RESERVED_ADDR, ...)pthread_create(reverse_line_tick_loop):周期lv_tick_inc(5)- 循环
lv_task_handler()持续绘制线条到REVERSELINE_RESERVED_ADDR
“快速倒车不断流”的退出抑制点
run_camera_internel()里:register_cam_msg_cb(LKCAM_STATE_STOPPING, stopping_msg_callback, NULL)stopping_msg_callback()- 若
rvc_gpio_check()==true:直接返回(保持显示,不触发退出) - 否则:
notify_camera_exit_block(false)让check_wait_camera_exit()尽快返回并进入flush/close
- 若
rvc_flip() 上屏“门控条件表”(决定是否真的 sprd_dispc_flip())
在 platform/sprd_shared/driver/video/sprd/sprd_main.c 里,rvc_flip() 并不是每次都 flip,上屏被下面条件卡住:
-
编译期开关
#ifndef GSP0_SPLICE_DUAL_DISPLAY && defined(CONFIG_BOOT_ANIMATION)- 含义:只有在 未定义
GSP0_SPLICE_DUAL_DISPLAY且 定义了CONFIG_BOOT_ANIMATION时,rvc_flip()内部才会调用sprd_dispc_flip();否则函数只构造 config 但不实际上屏。
-
运行时条件(全部必须满足)
!strcmp("normal", g_env_bootmode)- 只有 normal boot 才允许 RVC flip
(g_last_step & (1 << PHASE_LINUX_MODE))- 只有进入到“Linux mode 阶段”之后才允许 flip(属于 boot 阶段门控)
rvc_gpio_check() == 1- 倒车信号必须仍然为真
对应源码片段(关键判断)来自 sprd_main.c:
#ifndef GSP0_SPLICE_DUAL_DISPLAY && defined(CONFIG_BOOT_ANIMATION)
if (!strcmp("normal", g_env_bootmode) && (g_last_step & (1<< PHASE_LINUX_MODE)) && rvc_gpio_check() == 1)
sprd_dispc_flip(dispc, rvc_config);
#endif
这些条件的变量/枚举在哪里来的(便于你追)
-
g_env_bootmode- 在多处被
extern使用(如sprd_main.c、dpu_r6p0.c、sec_common.c等) - 定义声明可见:
app/sprdboot/include/boot_mode.h(extern const char* g_env_bootmode;)
- 在多处被
-
g_last_step&PHASE_LINUX_MODEg_last_step:platform/sprd_shared/driver/log_pointing/sprd_log_point.c定义volatile uint32_t g_last_step = 0;PHASE_LINUX_MODE:platform/sprd_shared/driver/log_pointing/sprd_log_point.h枚举里定义
-
CONFIG_BOOT_ANIMATION- 从
app/sprdboot/rules.mk里可以看到被加入GLOBAL_DEFINES(使得编译期defined(CONFIG_BOOT_ANIMATION)生效)
- 从
顺带一提:animation_flip() 与 RVC 是互斥门控
在同一文件里 animation_flip() 也用了同样的门控条件,但最后一项是 rvc_gpio_check()==0,也就是:
- 倒车信号为 1 → 走 RVC 双层
- 倒车信号为 0 → 才允许 boot animation 的 flip