异构快启 Camera 使用指南
概述
编写目的
描述camera异构快启的整体架构、数据流程、异构快启sensor更新指南、rtos-isp工作模式阐述、flash分区数据管理、sensor_list使用说明、如何连接TigerIsp工具以及如何获取rtos的图像数据。
适应范围
Allwinner软件平台Tina,快启场景。
- V861
- V881
- V838
相关人员
开发和维护camera的相关人员。
专有名词
- CSI(Camera Serial Interface):图像串行接口,一般指串行数字接口
- ISP(Image Signal Processor):图像处理器
- VIPP(Video Input Post Processor):视频输入后置处理器,一般做scale处理
- MIPI(Mobile Industry Processor Interface):高速接收接口
- TDM(Time Divison Multiplexing):分时复用控制器,其中rx表示接受sensor数据,tx表示发送数据给isp处理
- VINC(Video Input Control):视频输出dma接收
- WDR(Wide Dynamic Range Imaging):宽动态范围成像,行业也称为HDR(High Dynamic Range Imaging)高动态范围成像
- MPP(Media Process Platform):媒体处理平台
快启异构架构说明
快启异构Camera运行流程
基本流程
快启异构方案出图基本流程如下图所示,可以大概分为以下三个流程:
-
Boot0引导rtos系统(rtos系统)启动,rtos系统启动后初始化sensor、CSI和ISP硬件以及初始化ISP算法库,图像开始采集并且ISP库对图像开始处理。
-
Boot0引导Linux系统启动,然后等待rtos的通知,rtos系统对图像处理后关闭CSI和ISP硬件并发消息告知Linux系统。
-
Linux系统打开CSI和ISP硬件开始接收图像,并把图像信息发送给rtos系统的ISP算法库对图像进行处理,处理结果再发送回给Linux系统的ISP硬件,双系统协同完成图像的接收和处理。
详细流程

结合以上流程图,具体阐述如下:
-
boot0启动,并读取flash分区(每个sensor占4个扇区,4kB的数据量)信息到预留内存里面,flash分区存放应用层控制输出码流分辨率、帧率、码流格式、白天黑夜切换阈值等信息。
-
boot0先引导rtos系统启动,接着引导linux系统启动。
-
rtos系统启动后先初始化twi、时钟、pinctrl等基础系统信息后,读取预留内存的分辨率、帧率、曝光增益等信息,并由此初始化摄像头sensor、CSI和ISP硬件。
-
linux系统启动后,初始化CSI和ISP软件链路信息,等待rtos系统通知再开启CSI和ISP。
-
rtos系统初始化ISP库读取效果头文件和读取预留内存白天黑夜切换阈值,主要对AE和AWB进行收敛并根据阈值切换IR-CUT。
-
AE和AWB稳定后,关闭rtos系统的TWI、CSI和ISP硬件,并通知linux系统,linux系统收到通知后注册TWI、CSI和ISP中断处理函数,并使能CSI和ISP的IOMMU使能位。
-
rtos系统和Linux初始化rpmsg和rpbuf,linux系统开启CSI和ISP,通过rpmsg和rpbuf与rtos系统的ISP库进行交互处理图像效果。
-
rpmsg为name server机制,每次可以发送数据最大为512-16字节(数据块大小为512字节,头部占用16字节),所以rtos系统ISP库和Linux系统CSI&ISP框架之间的小数据交互使用到的是rpmsg机制。
-
rpbuf机制其实就是一种共享内存机制,即在linux系统和rtos系统都申请一块name和大小相同的ddr地址,双系统都可以读写到此块ddr地址,完成大数据交互。linux系统会把统计值数据save buffer发送给rtos系统的ISP库进行处理,ISP库处理完成后,把处理结果load buffer再发送给Linux系统设置到ISP硬件。
-
linux系统抓取到rtos系统的ISP库处理后的效果图像送到编码,编码读取预留内存的分辨率、帧率和编码格式,对数据流进行编码。
异构快启系统sensor更换指导
rtos系统sensor更换说明
-
sensor的初始化配置最好先在Linux测试通过,不然rtos无法判断sensor输出图像是否正常。
-
rtos系统的sensor初始化作为一个加速阶段,切换到linux的时候就作为linux系统首帧的图像效果。
-
rtos系统sensor首帧初始化目前支持预取值模式、 高帧率模式、硬光敏模式和硬光敏高帧率模式(mrtos menuconfig选择配置), rtos-isp模式使用说明 进行详细说明。
-
预取值模式指的是sensor的初始化曝光增益使用的是上一次系统关闭时候保存在flash的曝光和增益,以保证首帧曝光增益正常。最简单模式,sensor几乎没有什么特别改动。
-
高帧率模式就是先使用低分辨高帧率先计算出曝光增益和白平衡,然后再切换到目标帧率,以得到当前环境正确的曝光增益和白平衡,优点就是首帧曝光增益和白平衡比较正常,缺点是比第一种耗时。sensor具体如何修改支持高帧率模式会在 Sensor支持高帧率模式指导 中详细说明。
-
硬光敏模式光敏高帧率模式就是读取光敏电阻数值从而得到当前环境的亮度,所以可以在boot0就判断当前环境的亮度,提前控制ir_cut和红外补光。进入rtos系统的后再通过查询提前标定的光敏gpadc置与曝光增益关系表得出首帧曝光增益,优点是与第一种模式一样出图快,缺点是会增加成本。
-
硬光敏高帧率模式就是读取光敏电阻数值从而得到当前环境的亮度,所以可以在boot0就判断当前环境的亮度,提前控制ir_cut和红外补光。进入rtos系统的时候再使用高帧率模式收敛曝光增益和白平衡,由于提前在boot0就控制了it_cut,所以优点就是出图比第二种高帧率模式快且曝光增益相对准确,缺点是增加成本。sensor支持硬光敏模式需要使用到高帧率进行加速收敛,所以改动同高帧率模式。
-
可以参考gc4663_mipi.c,位于
lichee/rtos-hal/hal/source/vin/modules/sensor/gc4663_mipi.c
-
下面介绍一下sensor驱动的结构体:
struct sensor_fuc_core gc4663_core = {
.g_mbus_config = sensor_g_mbus_config, //配置sensor lane数目、通道数目以及
//mipi settletime函数
.sensor_test_i2c = sensor_test_i2c, //测试sensor twi通讯是否成功函数
.sensor_power = sensor_power, //sensor上电和下电函数
.s_ir_status = sensor_set_ir, //ircut控制函数
.s_stream = sensor_s_stream, //sensor数据流开启开关函数
.s_switch = sensor_s_switch, //高帧率模式低分辨率高帧率切换到目前分辨率目前帧
//率函数
.s_exp_gain = sensor_s_exp_gain, //sensor曝光增益配置函数
.sensor_g_format = sensor_get_format, //sensor信息配 置结构体
.sensor_g_switch_format = sensor_get_switch_format, //高帧率模式下待切换的目
//前分辨率目前帧率sensor信息配置结构体
.probe = sensor_probe, //设置模组的一些基本信息,例如:模组寄存器的地址位宽和数据位宽
};
-
预取值模式和硬光敏模式:sensor_s_stream和sensor_format配置的就是目标分辨率目标帧率的数据流开启函数和配置结构体,sensor_s_switch和switch_sensor_format不需要配置。
-
高帧率模式和硬光敏高帧率模式:sensor_s_stream和sensor_format配置的就是低分辨高帧率的数据流开启函数和配置结构体,sensor_s_switch和switch_sensor_format配置的就是目标分辨率目标帧率的数据流切换函数和配置结构体。其中sensor_s_switch配置的切换寄存器越简单越好,这样初始化时间短。
-
接着在该目录下camera.h添加extern该结构体sensor_fuc_core
extern struct sensor_fuc_core gc4663_core;添加完再该目录下修改Kconfig和Makefile,编译新添加的sensor驱动。
-
注册sensor驱动的func_core结构体
rtos/lichee/rtos-hal/hal/source/vin/modules/sensor/sensor_register.c
struct sensor_cfg_array sensor_array[] = {
#ifdef CONFIG_SENSOR_GC4663_MIPI
{"gc4663_mipi", &gc4663_core},
#endif
#ifdef CONFIG_SENSOR_GC2053_MIPI
{"gc2053_mipi", &gc2053_core},
#endif
#ifdef CONFIG_SENSOR_SC2355_MIPI
{"sc2355_mipi", &sc2355_core},
#endif
}; -
修改vin配置文件
rtos/lichee/rtos-hal/hal/source/vin/platform/vin_config_{IC}.c,如果打开CONFIG_VIN_USE_SYSCONFIG,vin配置参考异构快启系统sys_config文件配置指导
其中,CONFIG_ISP_NUMBER的数值是由用户通过menuconfig配置,表示isp使用个数。
- CONFIG_ISP_NUMBER = 1对应的是单目摄像头配置。
- CONFIG_ISP_NUMBER = 2/3对应的双目摄像头配置(其中CONFIG_ISP_NUMBER = 2表示双目线性,CONFIG_ISP_NUMBER = 3 表示单目wdr+单目线性或者双目wdr)。
这里主要关注global_sensors,mipi0对应第一个结构体[0],mipi1对应第二个结构体[1]:
[0] = {
.used = 1,
.sensor_name = "gc4663_mipi", //sensor名称
.sensor_twi_addr = 0x52, //slave地址
.sensor_twi_id = 1, //twi号
.mclk_id = 0, //mclk号
.use_isp = 1,
.id = 0,
.addr_width = 16, //sensor地址位数
.data_width = 8, //sensor数据位数
.reset_gpio = GPIOA(11), //reset引脚
.pwdn_gpio = GPIOA(9), //pwdn引脚
.ir_cut_gpio[0] = GPIOD(18), /*-cut*/
.ir_cut_gpio[1] = GPIOD(8), /*+cut*/
.ir_led_gpio = 0xffff, //如果不需要设置该功能引脚的话请设置为0xffff
}, -
修改twi配置
修改twi引脚:文件位于rtos/board/v861_e907/{方案}/configs/sys_config.fex,直接修改即可。
修改twi的频率:文件位于rtos/lichee/rtos-hal/hal/source/twi/hal_twi.c,如下:
twi_status_t hal_twi_init(twi_port_t port)
{
......
twi->freq = TWI_FREQUENCY_400K;
......
}
linux系统sensor更换说明
-
这里只是比较非快启环境的差异,并非从头开始讲解如何编写一个新的驱动。
-
除了board.dts需要配置ir-cut引脚外,board.dts配置、编译方式都没有变化,与之前一致。
sensor0:sensor@0 {
......
sensor0_sm_hs = <&pio PD 18 1 0 1 0>; /\*-cut\*/
sensor0_sm_vs = <&pio PD 8 1 0 1 0>; /\*+cut\*/
......
}; -
函数sensor_init()如果有以下语句请把它在该函数删除,preview_first_flag表示第一次出图,如果在sensor_init函数置1的话,那表示每次都是第一次出图,所以需要删除。
info->preview_first_flag = 1; -
函数sensor_reg_init()以下语句进行变更
#if defined CONFIG_VIN_INIT_rtos
if (info->preview_first_flag) {//首次初始化不设置,因为在rtos环境已经初始化了
info->preview_first_flag = 0;
} else {
if (wsize->regs)
sensor_write_array(sd, wsize->regs, wsize->regs_size);
if (info->exp && info->gain) {
exp_gain.exp_val = info->exp;
exp_gain.gain_val = info->gain;
} else {
if (wsize->wdr_mode == ISP_DOL_WDR_MODE) {
exp_gain.exp_val = 30720;
exp_gain.gain_val = 16;
} else {
exp_gain.exp_val = 15408;
exp_gain.gain_val = 32;
}
}
sensor_s_exp_gain(sd, &exp_gain); //设置上一次保存的曝光增益
}
#else
if (wsize->regs) {
sensor_write_array(sd, wsize->regs, wsize->regs_size);
}
#endif -
函数sensor_probe()添加一下两个语句
info->preview_first_flag = 1;
info->first_power_flag = 1; -
修改加载驱动方式
VIN_INIT_DRIVERS(init_sensor);
module_exit(exit_sensor); -
board.dts配置说明
-
预留地址给rtos系统vin使用,使用结束后会在linux释放,但是此地址需要与系统约定好。此处只供参考,实际要按照需求进行内存分配
e907_dram_reserved: e907_dram@41000000 {
reg = <0x0 0x41000000 0x0 0x400000>;
no-map;
};
isp_dram_reserved: isp_dram@414c6000 {
reg = <0x0 0x414c6000 0x0 0xA00000>;
};RTOS e907 和ISP内存需要同步修改 位置:rtos/lichee/rtos/projects/v861_e907/perf2_fastboot/defconfig
CONFIG_ARCH_START_ADDRESS=0x41000000
CONFIG_ARCH_MEM_LENGTH=0x900000
CONFIG_ISP_MEMRESERVE_ADDR=0x414c6000
CONFIG_ISP_MEMRESERVE_LEN=0xa00000或者 mrtos menuconfig 修改


-
twi延后初始化,具体初始化时机等rtos通知(rtos通知:调用接口rpmsg_notify("twi1", NULL, 0),位于rtos/lichee/rtos/projects/v861_e907/{方案}/src/main.c), linux端board.dts中需在节点中增加如下属性:
&twi1 {
..........
/\*twi驱动匹配到该节点即会延后初始化twi硬件和延后注册中断处理函数\*/
rproc-name = "6010000.e907_rproc";
}; -
vind子设备节点改动
tdm0:tdm@0 {
delay_init = <1>;//延迟注册中断处理函数
rpmsg-ser-name = "6010000.e907_rproc";
.........
};
scaler00:scaler@5910000 {
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
.........
};
vinc00:vinc@5830000 {
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
.........
};
Linux需要使用到tdm,需要收到rtos系统使用结束,然后rtos系统会调用rpmsg_notify通知linux系统,例如rpmsg_notify("tdm0", NULL, 0),这样linux会收到事先注册的回调函数进行使能该master的iommu和注册中断处理函数。其他节点scaler和vinc也是如此使用。(tdm为分时复用模式,scaler表示缩放模式,vinc表示数据输出模块)
- isp节点改动
isp00:isp@5900000 {
rpbuf = <&rpbuf_controller0>;
isp-region = <&isp_dram_reserved>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
Linux需要使用到isp,需要rtos系统使用结束,然后rtos系统会调用rpmsg_notify通知linux系统,即rpmsg_notify("isp0", NULL, 0),这样linux会使能 isp注册中断处理函数、释放预留内存。
- 特别说明
由于linux系统启动后sensor首次出图使用的rtos系统初始化的sensor驱动,所以如果需要修改sensor驱动的话,麻烦修改linux的sensor驱动和rtos系统的sensor驱动。