异构快启 WDR 配置指南
前言
文档简介
介绍快启 WDR 的使用方法,方便开发人员使用。
目标读者
Camera 模块的驱动开发/维护人员。
适用范围
| 芯片型号 | 系统版本 | 驱动文件目录 |
|---|---|---|
| V861/V838/V881 Linux | Linux-6.6-xuantie | bsp/drivers/vin |
| V861/V838/V881 RTOS | FreeRTOS | rtos/lichee/rtos-hal/hal/source/vin |
| V85X Linux | Linux-4.9 | drivers/media/platform/sunxi-vin/ |
| V85X RTOS | melis-v3.0 | rtos-hal/hal/source/vin |
专有名词
RTOS系统:FreeRTOS或Melis实时系统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):媒体处理平台
Sensor 驱动修改点
RTOS 系统 Sensor 驱动修改点
下面是基于 gc4663 来讲解。
- 可以参考
RTOS的sensor驱动gc4663_mipi.c
V861/V838/V881 代码位置: rtos/lichee/rtos-hal/hal/source/vin/modules/sensor/gc4663_mipi.c
V85X 代码位置: rtos-hal/hal/source/vin/modules/sensor/gc4663_mipi.c
- 添加
Sensor静态全局变量,以便可以保存sensor的WDR模式来控制曝光增益。
static int sensor_wdr_mode[2];
- 函数
sensor_get_format和sensor_get_switch_format在获取sensor格式后,需要给sensor_wdr_mode赋值,以便可以控制不同的曝光增益。
static struct sensor_format_struct *sensor_get_format(int id, int isp_id)
{
......
sensor_wdr_mode[id] = sensor_format->wdr_mode;
......
}
static struct sensor_format_struct *sensor_get_switch_format(int id, int isp_id)
{
......
sensor_wdr_mode[id] = sensor_format->wdr_mode;
......
}
- 设置曝光增益函数
sensor_s_exp_gain和设置mbus函数sensor_g_mbus_config需要根据sensor_wdr_mode来区分线性和WDR。
static int sensor_s_exp_gain(int id, struct sensor_exp_gain *exp_gain)
{
int isp_wdr_mode;
if (sensor_wdr_mode[id])
isp_wdr_mode = ISP_DOL_WDR_MODE;
else
isp_wdr_mode = ISP_NORMAL_MODE;
......
}
static int sensor_g_mbus_config(int id, struct v4l2_mbus_config *cfg, struct
mbus_framefmt_res *res)
{
int isp_wdr_mode;
if (sensor_wdr_mode[id])
isp_wdr_mode = ISP_DOL_WDR_MODE;
else
isp_wdr_mode = ISP_NORMAL_MODE;
res->res_wdr_mode = isp_wdr_mode;
......
}
- 设置
MIPI的接收WDR模式,一般有三种模式--DOL、VC和普通模式,函数为sensor_g_mbus_config。
static int sensor_g_mbus_config(int id, struct v4l2_mbus_config *cfg, struct
mbus_framefmt_res *res)
{
......
if (isp_wdr_mode == ISP_DOL_WDR_MODE) {
res->res_combo_mode = MIPI_VC_WDR_MODE;
}
......
return 0;
}
Linux系统sensor驱动改动点同常电,没有特殊配置。
配置修改
RTOS 系统配置改动
- 修改
CSI&ISP的频率
注意不是 WDR 模式都需要修改,规格超过设置的频率才需要修改,默认频率是 324M。
CSI & ISP 频率计算公式如下,设置的频率需要取 max(csi_clk, isp_clk)。
csi_clk计算公式:
帧率 x (vts) x (hts) x 1(WDR则为2) / 8 / 1(双pixel则为2) / 1000000,向上取整,单位为MH;
isp_clk计算公式:
帧率 x (vts) x (hts) x 1.2 / 1000000,向上取整,单位为MH;
V861/V838/V881 文件位置:
rtos/lichee/rtos-hal/hal/source/vin/platform/vin_config_sun252iw1.c
参数是 vind_default_clk[VIN_TOP_CLK].frequency,如下所示
struct vin_clk_info vind_default_clk[VIN_TOP_CLK] = {
[VIN_TOP_CLK] = {
.clock_id = CLK_CSI,
.type = HAL_SUNXI_CCU,
.frequency = 324000000,
},
[VIN_TOP_CLK_SRC] = {
.clock_id = CLK_PLL_CSI_4X,
.type = HAL_SUNXI_CCU,
.frequency = 1296000000,
},
[VIN_TOP_CLK_SRC1] = {
.clock_id = CLK_PLL_PERI_300M,
.type = NOT_USE_THIS_CLK,
},
};
V85X 文件位置:
lichee/rtos-hal/hal/source/vin/platform/vin_config_sun8iw21p1.c,
参数是 vind_default_clk[VIN_TOP_CLK].frequency,如下所示:
struct vin_clk_info vind_default_clk[VIN_MAX_CLK] = {
[VIN_TOP_CLK] = {
.clock = HAL_CLK_PERIPH_CSI_TOP,
.frequency = 300000000,
},
......
};
- 配置
TDM模块
由于 WDR 需要使用到 TDM 模块,所以需要把 TDM 连接到 pipeline 中。
V861/V838/V881 文件位置: rtos/lichee/rtos-hal/hal/source/vin/platform/vin_config_sun252iw1.c
V85X 文件位置: lichee/rtos-hal/hal/source/vin/platform/vin_config_sun8iw21p1.c
参数是 tdm_rx_sel,如下所示:
struct vin_core global_video[VIN_MAX_VIDEO] = {
[0] = {
......
.tdm_rx_sel = 0,
......
},
[1] = {
......
.tdm_rx_sel = 1,
......
},
}
注意:
(1) 上面代码所示 tdm_rx_sel 不是固定为0/1,需要根据实际 pipeline 选择。
(2) vin_config_sun252iw1.c 和 vin_config_sun8iw21p1.c 文件中通过 CONFIG_ISP_NUMBER 来区分单双目数据,如下:
#if (CONFIG_ISP_NUMBER == 1)
......//单目配置
#else /* CONFIG_ISP_NUMBER == 2/3 */
......//双目配置
#endif
(3) 单目配置
单目 WDR 或者单目线性--配置 global_video[0]。
(4) 双目配置
双目线性--配置 global_video[0] 和 global_video[1]
单目 WDR +单目线性或者双目 WDR --配置 global_video[0] 和 global_video[2]
RTOS系统menuconfig配置修改
V861/V838/V881 执行 mrtos menuconfig

V85X 执行 mmelis menuconfig,依次进入 VIN Devices 选项,如下图所示:

isp support number(即 CONFIG_ISP_NUMBER)可以配置范围为1-3,不同模式配置不一样:
(1) 单目 WDR 或者单目线性,配置为1。
(2) 双目线性,配置为2。
(3) 单目 WDR +单目线性或者双目 WDR,配置为3。
RTOS系统main.c版型相关主文件修改
V861/V838/V881 此文件为 FreeRTOS 系统启动后运行指令函数集合,文件位置 rtos/lichee/rtos/projects/v861_e907/版型型号/src/main.c,主函数为 cpu0_app_entry,如下所示:
void cpu0_app_entry(void *param)
{
(void)param;
#ifdef CONFIG_COMPONENTS_PM
pm_init(1, NULL);
#endif
#ifdef CONFIG_COMPONENTS_OPENAMP
void *thread;
thread = hal_thread_create(openamp_init_thread, NULL,
"amp_init", 8 * 1024, HAL_THREAD_PRIORITY_SYS);
if (thread != NULL)
hal_thread_start(thread);
#endif
#ifdef CONFIG_COMPONENTS_TCPIP
//tcpip stack init
cmd_tcpip_init();
#endif
#if defined(CONFIG_COMPONENT_CLI) && !defined(CONFIG_UART_MULTI_CONSOLE_AS_MAIN)
vCommandConsoleStart(0x1000, HAL_THREAD_PRIORITY_CLI, NULL);
#endif
#ifdef CONFIG_PRELOAD_COMPENENTS
extern void flash_load_data_async(void);
flash_load_data_async();
#endif
#ifdef CONFIG_DRIVERS_VIN
int ret;
ret = csi_init(0, NULL);
if (ret) {
rpmsg_notify("rt-media", NULL, 0);
printf("csi init fail!\n");
} else {
#if CONFIG_ISP_NUMBER >= 2
rpmsg_notify("tdm0", NULL, 0);
#endif
rpmsg_notify("twi1", NULL, 0);
rpmsg_notify("isp0", NULL, 0);
rpmsg_notify("scaler0", NULL, 0);
rpmsg_notify("scaler4", NULL, 0);
rpmsg_notify("scaler8", NULL, 0);
rpmsg_notify("scaler12", NULL, 0);
rpmsg_notify("vinc0", NULL, 0);
rpmsg_notify("vinc4", NULL, 0);
rpmsg_notify("vinc8", NULL, 0);
rpmsg_notify("vinc12", NULL, 0);
#if CONFIG_ISP_NUMBER >= 2
rpmsg_notify("isp1", NULL, 0);
rpmsg_notify("vinc1", NULL, 0);
rpmsg_notify("vinc5", NULL, 0);
rpmsg_notify("vinc9", NULL, 0);
rpmsg_notify("vinc13", NULL, 0);
#endif
#if CONFIG_ISP_NUMBER >= 3
rpmsg_notify("isp2", NULL, 0);
rpmsg_notify("vinc2", NULL, 0);
rpmsg_notify("vinc6", NULL, 0);
rpmsg_notify("vinc10", NULL, 0);
rpmsg_notify("vinc14", NULL, 0);
#endif
#if CONFIG_ISP_NUMBER >= 4
rpmsg_notify("isp3", NULL, 0);
rpmsg_notify("vinc3", NULL, 0);
rpmsg_notify("vinc7", NULL, 0);
rpmsg_notify("vinc11", NULL, 0);
rpmsg_notify("vinc15", NULL, 0);
#endif
printf("csi init success!\n");
}
#endif
#ifdef CONFIG_COMMAND_AUTO_START_MEMTESTER
void *autotest_thread;
autotest_thread = hal_thread_create(auto_memtester_thread, NULL,
"auto_memtester", 8 * 1024, HAL_THREAD_PRIORITY_SYS);
if (autotest_thread != NULL)
hal_thread_start(autotest_thread);
#endif
vTaskDelete(NULL);
}
V85X 此文件为 Melis 系统启动后运行指令函数集合,文件位置 lichee/melis-v3.0/source/projects/v851_e907/版型选项/src/main.c,主函数为 app_entry,如下所示:
#include <stdio.h>
#include <hal_timer.h>
#include <openamp/sunxi_helper/openamp.h>
extern int csi_init(int argc, const char **argv);
extern int msh_exec(char *cmd, int length);
int app_entry(void *param)
{
#ifdef CONFIG_DRIVERS_VIN
int ret;
ret = csi_init(0, NULL);
if (ret) {
rpmsg_notify("rt-media", NULL, 0);
printf("csi init fail!\n");
}
#if 1
rpmsg_notify("twi0", NULL, 0);
rpmsg_notify("twi1", NULL, 0);
rpmsg_notify("tdm0", NULL, 0);
rpmsg_notify("isp0", NULL, 0);
rpmsg_notify("isp1", NULL, 0);
rpmsg_notify("scaler0", NULL, 0);
rpmsg_notify("scaler4", NULL, 0);
rpmsg_notify("scaler8", NULL, 0);
rpmsg_notify("scaler12", NULL, 0);
rpmsg_notify("vinc0", NULL, 0);
rpmsg_notify("vinc1", NULL, 0);
rpmsg_notify("vinc4", NULL, 0);
rpmsg_notify("vinc5", NULL, 0);
rpmsg_notify("vinc8", NULL, 0);
rpmsg_notify("vinc9", NULL, 0);
rpmsg_notify("vinc12", NULL, 0);
rpmsg_notify("vinc13", NULL, 0);
#endif
#else
hal_msleep(200);
rpmsg_notify("rt-media", NULL, 0);
#endif
msh_exec("dmesg", strlen("dmesg"));
return 0;
}
其中主要配置不同项为 rpmsg_notify,该函数的意思是发生消息给 Linux 系统,告知 Linux 系统该硬件模块 RTOS 系统已经使用完毕,Linux 系统可以注册该硬件模块的中断函数并使用此硬件模块,当然需要 Linux 系统通过函数 rpmsg_notify_add 创建 name 相同的消息回调才会被调用。
即发送方 RTOS 系统,发送函数 rpmsg_notify,接收方 Linux 系统,创建回调函数 rpmsg_notify_add 并接收,通过两个函数的参数 name 一一对应。
有四种调用组合:
(1)单目线性
rpmsg_notify("twi1, NULL, 0);
rpmsg_notify("isp0", NULL, 0);
rpmsg_notify("scaler0", NULL, 0);
rpmsg_notify("scaler4", NULL, 0);
rpmsg_notify("scaler8", NULL, 0);
rpmsg_notify("scaler12", NULL, 0);
rpmsg_notify("vinc0", NULL, 0);
rpmsg_notify("vinc4", NULL, 0);
rpmsg_notify("vinc8", NULL, 0);
rpmsg_notify("vinc12", NULL, 0);
说明:
twi表示sensor使用到的twi号,其他的均属于CSI&ISP硬件模块。- 这里通过
rpmsg_notify调用的函数需要在Linux系统的board.dts同步配置,Linux系统的模块才可以收到该消息。board.dts同步配置的是延时注册,见Linux系统配置改动章节。 vincx表示Linux系统的videox节点,Linux系统收到该消息回调的时候,会注册中断和使能iommu内存,并且调用rt-media回调函数接口告知rt-media可以开始配置videox出图。
(2)单目 WDR
rpmsg_notify("twi1, NULL, 0);
rpmsg_notify("tdm0", NULL, 0);
rpmsg_notify("isp0", NULL, 0);
rpmsg_notify("scaler0", NULL, 0);
rpmsg_notify("scaler4", NULL, 0);
rpmsg_notify("scaler8", NULL, 0);
rpmsg_notify("scaler12", NULL, 0);
rpmsg_notify("vinc0", NULL, 0);
rpmsg_notify("vinc4", NULL, 0);
rpmsg_notify("vinc8", NULL, 0);
rpmsg_notify("vinc12", NULL, 0);
(3)双目线性
rpmsg_notify("twi0", NULL, 0);
rpmsg_notify("twi1", NULL, 0);
rpmsg_notify("tdm0", NULL, 0);
rpmsg_notify("isp0", NULL, 0);
rpmsg_notify("isp1", NULL, 0);
rpmsg_notify("scaler0", NULL, 0);
rpmsg_notify("scaler4", NULL, 0);
rpmsg_notify("scaler8", NULL, 0);
rpmsg_notify("scaler12", NULL, 0);
rpmsg_notify("vinc0", NULL, 0);
rpmsg_notify("vinc1", NULL, 0);
rpmsg_notify("vinc4", NULL, 0);
rpmsg_notify("vinc5", NULL, 0);
rpmsg_notify("vinc8", NULL, 0);
rpmsg_notify("vinc9", NULL, 0);
rpmsg_notify("vinc12", NULL, 0);
rpmsg_notify("vinc13", NULL, 0);
(4)单目 WDR +单目线性或者双目 WDR
rpmsg_notify("twi0", NULL, 0);
rpmsg_notify("twi1", NULL, 0);
rpmsg_notify("tdm0", NULL, 0);
rpmsg_notify("isp0", NULL, 0);
rpmsg_notify("isp2", NULL, 0);
rpmsg_notify("scaler0", NULL, 0);
rpmsg_notify("scaler4", NULL, 0);
rpmsg_notify("scaler8", NULL, 0);
rpmsg_notify("scaler12", NULL, 0);
rpmsg_notify("vinc0", NULL, 0);
rpmsg_notify("vinc2", NULL, 0);
rpmsg_notify("vinc4", NULL, 0);
rpmsg_notify("vinc6", NULL, 0);
rpmsg_notify("vinc8", NULL, 0);
rpmsg_notify("vinc10", NULL, 0);
rpmsg_notify("vinc12", NULL, 0);
rpmsg_notify("vinc14", NULL, 0);
Linux 系统配置改动
- 修改
CSI&ISP的频率
V861/V838/V881 可以根据 FreeRTOS 系统计算出来的时钟频率,设置到 board.dts,如下所示:
&vind0 {
csi_top = <324000000>;
......
}
V85X 可以根据 Melis 系统计算出来的时钟频率,设置到 board.dts,如下所示:
vind0:vind@0 {
vind0_clk = <300000000>;
......
}
注意:
RTOS 系统设置的 CSI & ISP 频率需要与 Linux 系统设置的 CSI & ISP 频率一样,否则可能会导致 Linux 系统无法启动。
- 设置
TWI延时注册
设置 Linux 系统延时注册的原因是 RTOS 系统还在使用该设备,如果这时 Linux 系统注册了该设备的中断函数并操作了该设备的硬件寄存器或者时钟,会导致 RTOS 系统无法使用到该设备,所以需要在 Linux 系统设置设备的延时注册。
根据硬件连接到 sensor 的 twi 号(双目则需要设置两个 twi 延时注册)
V861/V838/V881 在 board.dts 设置它延时注册,设置 rproc-name 为 6010000.e907_rproc,以 twi1 为例,如下所示:
&twi1 {
clock-frequency = <400000>;
......
rproc-name = "6010000.e907_rproc";
status = "okay";
};
V85X 在 board.dts 设置它延时注册,设置 rproc-name 为 e907_rproc@0,以 twi1 为例,如下所示:
&twi1 {
clock-frequency = <400000>;
rproc-name = "e907_rproc@0";
......
status = "okay";
};
Linux 设置 twi 延时注册后,该 twi 将无法使用直到 Melis 系统通过 rpmsg_notify("twi1", NULL, 0) 通知到 Linux 系统为止。
- 设置
TDM/ISP/scaler/vinc延时注册
由于不同的方案配置 TDM / ISP / scaler / vinc 的设备号不一致,如下:
- 单目在线线性:
isp0,scaler0,scaler4,scaler8,scaler12,vinc0,vinc4,vinc8,vinc12 - 单目在线
WDR:tdm0,isp0,scaler0,scaler4,scaler8,scaler12,vinc0,vinc4,vinc8,vinc12 - 双目离线线性:
tdm0,isp0,isp1,scaler0,scaler1,scaler4,scaler5,scaler8,scaler9,scaler12,scaler13,vinc0,vinc1,vinc4,vinc5,vinc8,vinc9,vinc12,vinc13 - 单目离线
WDR+单目离线线性或者双目离线WDR:tdm0,isp0,isp2,scaler0,scaler2,scaler4,scaler6,scaler8,scaler10,scaler12,scaler14,vinc0,vinc2,vinc4,vinc6,vinc8,vinc10,vinc12,vinc14
V861/V838/V881 设置延时注册为 delay_init = <1>,单目在线为例,如下:
tdm0: tdm@5908000 {
work_mode = <0x1>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
isp00:isp@5900000 {
work_mode = <0x1>;
rpbuf = <&rpbuf_controller0>;
isp-region = <&isp_dram_reserved>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
scaler00:scaler@5910000 {
work_mode = <0x1>;
status = "okay";
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
scaler10:scaler@5910400 {
work_mode = <0x1>;
status = "okay";
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
scaler20:scaler@5910800 {
work_mode = <0x1>;
status = "okay";
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
scaler30:scaler@5910c00 {
work_mode = <0x1>;
status = "okay";
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
};
vinc00:vinc@5830000 {
vinc0_csi_sel = <0>;
vinc0_mipi_sel = <0>;
vinc0_isp_sel = <0>;
vinc0_isp_tx_ch = <0>;
vinc0_tdm_rx_sel = <0>;
vinc0_vipp_sel = <0>;
vinc0_rear_sensor_sel = <0>;
vinc0_front_sensor_sel = <0>;
vinc0_sensor_list = <0>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
work_mode = <0x1>;
status = "okay";
};
vinc10:vinc@5831000 {
vinc4_csi_sel = <0>;
vinc4_mipi_sel = <0>;
vinc4_isp_sel = <0>;
vinc4_isp_tx_ch = <0>;
vinc4_tdm_rx_sel = <0>;
vinc4_vipp_sel = <4>;
vinc4_rear_sensor_sel = <0>;
vinc4_front_sensor_sel = <0>;
vinc4_sensor_list = <0>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
work_mode = <0x1>;
status = "okay";
};
vinc20:vinc@5832000 {
vinc8_csi_sel = <0>;
vinc8_mipi_sel = <0>;
vinc8_isp_sel = <0>;
vinc8_isp_tx_ch = <0>;
vinc8_tdm_rx_sel = <0>;
vinc8_vipp_sel = <8>;
vinc8_rear_sensor_sel = <0>;
vinc8_front_sensor_sel = <0>;
vinc8_sensor_list = <0>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
work_mode = <0x1>;
status = "okay";
};
vinc30:vinc@5833000 {
vinc12_csi_sel = <0>;
vinc12_mipi_sel = <0>;
vinc12_isp_sel = <0>;
vinc12_isp_tx_ch = <0>;
vinc12_tdm_rx_sel = <0>;
vinc12_vipp_sel = <12>;
vinc12_rear_sensor_sel = <0>;
vinc12_front_sensor_sel = <0>;
vinc12_sensor_list = <0>;
rpmsg-ser-name = "6010000.e907_rproc";
delay_init = <1>;
work_mode = <0x1>;
status = "okay";
};
V85X 设置延时注册为 delay_init = <1>,单目在线为例,如下:
isp00:isp@0 {
work_mode = <0>;
rpbuf = <&rpbuf_controller0>;
iommus = <&mmu_aw 4 0>;
isp-region = <&isp_reserved>;
delay_init = <1>;
};
scaler00:scaler@0 {
work_mode = <0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
};
scaler20:scaler@8 {
work_mode = <0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
};
scaler10:scaler@4 {
work_mode = <0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
};
scaler30:scaler@12 {
work_mode = <0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
};
vinc00:vinc@0 {
vinc0_csi_sel = <0>;
vinc0_mipi_sel = <0>;
vinc0_isp_sel = <0>;
vinc0_isp_tx_ch = <0>;
vinc0_tdm_rx_sel = <0>;
vinc0_rear_sensor_sel = <0>;
vinc0_front_sensor_sel = <0>;
vinc0_sensor_list = <0>;
work_mode = <0x0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
status = "okay";
};
vinc10:vinc@4 {
vinc4_csi_sel = <0>;
vinc4_mipi_sel = <0>;
vinc4_isp_sel = <0>;
vinc4_isp_tx_ch = <0>;
vinc4_tdm_rx_sel = <0>;
vinc4_rear_sensor_sel = <0>;
vinc4_front_sensor_sel = <0>;
vinc4_sensor_list = <0>;
work_mode = <0x0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
status = "okay";
};
vinc20:vinc@8 {
vinc8_csi_sel = <0>;
vinc8_mipi_sel = <0x0>;
vinc8_isp_sel = <0>;
vinc8_isp_tx_ch = <0>;
vinc8_tdm_rx_sel = <0>;
vinc8_rear_sensor_sel = <0>;
vinc8_front_sensor_sel = <0>;
vinc8_sensor_list = <0>;
work_mode = <0x0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
status = "okay";
};
vinc30:vinc@12 {
vinc12_csi_sel = <0>;
vinc12_mipi_sel = <0x0>;
vinc12_isp_sel = <0>;
vinc12_isp_tx_ch = <0>;
vinc12_tdm_rx_sel = <0>;
vinc12_rear_sensor_sel = <0>;
vinc12_front_sensor_sel = <0>;
vinc12_sensor_list = <0>;
work_mode = <0x0>;
iommus = <&mmu_aw 1 0>;
delay_init = <1>;
status = "okay";
};
- 其中
work_mode为0表示在线模式,为1表示离线模式。 TDM/ISP/scaler/vinc设备号配置了延时注册后,Linux系统将不能使用它们直到RTOS系统通过rpmsg_notify("tdmx", NULL, 0)/rpmsg_notify("ispx", NULL, 0)/rpmsg_notify("scalerx", NULL, 0)/rpmsg_notify("vincx", NULL, 0)通知到Linux系统为止,可以参考Melis系统配置改动章节的第4小点。- 配置了
scaler0-3延时注册只需要Melis系统配置scaler0通知rpmsg_notify("scaler0", NULL, 0)即可,同理配置scaler4-7/scaler8-11/scaler12-15只需要Melis系统配置scaler4/scaler8/scaler4/scaler12通知即可。
Linux系统menuconfig配置修改
执行 m kernel_menuconfig,依次进入 V4L platform devices,如下图所示:
v861

v85x

开启如下配置:
use isp for time sharing multiplextdm reduces buf size by compressionISP WDR module
WDR 开启方式
冷启动 Melis 和 Linux 开启 WDR
通过配置 flash 分区 SENSOR_ISP_CONFIG_S 结构的参数 wdr_mode,配置为1表示打开 WDR,配置为0表示关闭 WDR
V861/V838/V881 可以参考 platform/allwinner/multimedia/rt_media/sun252iw1/api_adapter/AW_VideoInput_API.c
V85X 可以参考 external/fast-user-adapter/rt_media/api_adapter/ 目录文件
AW_VideoInput_API.c 函数 isp_config_to_flash,如下所示:
void isp_config_to_flash(void)
{
SENSOR_ISP_CONFIG_S *sensor_isp_cfg0, *sensor_isp_cfg1;
int fd = 0;
struct write4k_op_t write_4k;
fd = open("/dev/mtd0", O_RDWR);
if (fd < 0) {
aw_loge("open mtd error");
return 0;
}
sensor_isp_cfg0 = malloc(sizeof(SENSOR_ISP_CONFIG_S));
memset(sensor_isp_cfg0, 0, sizeof(SENSOR_ISP_CONFIG_S));
sensor_isp_cfg0->sign = SENSOR_0_SIGN;
sensor_isp_cfg0->crc = 0;
sensor_isp_cfg0->ver = 0;
sensor_isp_cfg0->light_enable = 0;
sensor_isp_cfg0->adc_mode = 0;
sensor_isp_cfg0->light_def = 900;
sensor_isp_cfg0->ircut_state = 0;
sensor_isp_cfg0->ir_mode = 0;
sensor_isp_cfg0->lv_liner_def = 200;
sensor_isp_cfg0->lv_hdr_def = 0;
sensor_isp_cfg0->width = 0;
sensor_isp_cfg0->height = 0;
sensor_isp_cfg0->mirror = 0;
sensor_isp_cfg0->filp = 0;
sensor_isp_cfg0->fps = 15;
sensor_isp_cfg0->wdr_mode = 1;
sensor_isp_cfg0->flicker_mode = 0;
sensor_isp_cfg0->venc_format = 0;
sensor_isp_cfg0->sensor_deinit = 0;
sensor_isp_cfg0->get_yuv_en = 0;
sensor_isp_cfg0->lightadc_debug_en = 0;
sensor_isp_cfg0->light_sensor_en = 1;
write_4k.start = ISP0_PARAM_OFFSET*512;
write_4k.buf = malloc(sizeof(SENSOR_ISP_CONFIG_S));
memset(write_4k.buf, 0, sizeof(SENSOR_ISP_CONFIG_S));
memcpy((void *)write_4k.buf, (void *)sensor_isp_cfg0, sizeof(SENSOR_ISP_CONFIG_S));
write_4k.len = sizeof(SENSOR_ISP_CONFIG_S);
ioctl(fd, MEMWRITE_4K, &write_4k);
free(sensor_isp_cfg0);
......
}
该配置控制的是冷启动后出图的 WDR 模式;
通过 rt-media 用户层接口调用
设置通路配置接口 AWVideoInput_Configure(channelId_0, &config_0) 时,通过设置 config_0.enable_wdr,配置为1表示打开 WDR,配置为0表示关闭 WDR,
V861/V838/V881 可以参考 platform/allwinner/multimedia/rt_media/sun252iw1/demo/demo_video_in.c
V85X 可以参考 external/fast-user-adapter/rt_media/demo/demo_video_in.c
创建通路0的实现,如下所示:
......
config_0.enable_wdr = 1;
if (AWVideoInput_Configure(channelId_0, &config_0) {
aw_loge("config err, exit!");
goto _exit;
}
该配置控制的不是冷启动出图,而且冷启动出图后,关闭出图,再次启动出图时通过该接口配置开启 WDR。
通过 MPP 组件调用
如果 Tina 异构快启 SDK 选择的 MPP 组件的话,那么在 MPP 组件启动后,可以通过 MPP 组件配置 WDR 出图模式,接口为 configViAttr
V861/V838/V881 可以参考 platform/allwinner/eyesee-mpp/middleware/sun252iw1/sample/sample_virvi 目录的 sample_virvi.c 和 sample_virvi.conf。
V85X 可以参考 external/eyesee-mpp/middleware/sun8iw21/sample/sample_virvi/ 目录的 sample_virvi.c 和 sample_virvi.conf。
sample_virvi.c 中 pViAttr->wdr_mode 配置为1表示开启 WDR,配置为0表示关闭 WDR,如下所示:
static void configViAttr(VI_ATTR_S *pViAttr, SampleVirViConfig *pConfig)
{
pViAttr->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
pViAttr->memtype = V4L2_MEMORY_MMAP;
pViAttr->format.pixelformat = map_PIXEL_FORMAT_E_to_V4L2_PIX_FMT(pConfig->PicFormat);
pViAttr->format.field = V4L2_FIELD_NONE;
pViAttr->format.colorspace = pConfig->mColorSpace;
pViAttr->format.width = pConfig->PicWidth;
pViAttr->format.height = pConfig->PicHeight;
pViAttr->nbufs = 3;
pViAttr->nplanes = 2;
pViAttr->fps = pConfig->FrameRate;
pViAttr->use_current_win = 0;
pViAttr->wdr_mode = pConfig->mEnableWDRMode;
pViAttr->capturemode = V4L2_MODE_VIDEO; /* V4L2_MODE_VIDEO; V4L2_MODE_IMAGE; V4L2_MODE_PREVIEW */
pViAttr->drop_frame_num = pConfig->mViDropFrmCnt; // drop 2 second video data, default=0
}
sample_virvi.conf 是配置文件,通过配置设置到 pViAttr->wdr_mode,参数是 enable_wdr_mode_x,配置为1表示打开 WDR,配置为0表示关闭 WDR,如下所示:
dev_num_0 = 0
isp_dev_num_0 = 0
pic_width_0 = 1920
pic_height_0 = 1080
frame_rate_0 = 20
pic_format_0 = "nv21"
color_space_0 = "rec709_part_range"
enable_wdr_mode_0 = 1
drop_frm_num_0 = 0
查看 WDR 生效的方式
可以通过在 Linux 系统串口通过命令 cat vi 节点查看,命令如下:
mount -t debugfs none /sys/kernel/debug
cat /sys/kernel/debug/mpp/vi
其中参数 isp_mode 表示当前 sensor 出图的模式:
isp_mode:NORMAL,表示sensor当前出图是线性模式isp_mode:DOL_WDR,表示sensor当前出图是DOL_WDR模式
预留内存修改
ISP 预留内存修改
board.dts内存预留
通过 board.dts 预留内存,在 RTOS 系统启动后,CSI & ISP 硬件配置起来的时候使用到这块内存,当 Melis 系统 CSI & ISP 出图结束,切换到 Linux 系统时,即 Melis 系统调用 rpmsg_notify("isp0", NULL, 0) 通知到 Linux 系统的时候,这块内存会被释放。
默认预留是10M空间,如果是单目 WDR +单目线性或者双目 WDR 的话,10M空间可能不够,需要根据分辨率多预留几M空间。
V861/V838/V881 board.dts 配置预留内存,默认预留10M给 FreeRTOS 系统的 CSI & ISP 使用,如下所示:
reserved-memory {
......
isp_dram_reserved: {
reg = <0x0 0x414c6000 0x0 0xA00000>;
};
......
}
V85X board.dts 配置预留内存,默认预留10M给 Melis 系统的 CSI & ISP 使用,如下所示:
reserved-memory {
......
isp_reserved: isp_reserved {
reg = <0x0 0x43200000 0x0 0x00a00000>;
};
......
}
值得注意的是这10M内存其实包含两部分:
- 地址范围
0x43200000-0x43BFDFFF:Melis系统CSI&ISP出图使用的内存。如果内存不足可以根据系统整体内存进行修改。 - 地址范围
0x43BFE000-0x43BC0000:分配给flash分区读取ISP配置并保存区域,总共8kB。不可修改部分,如果isp_reserved被修改,那么需要单独在board.dts把0x43BFE000-0x43BC0000这8kB单独进行预留。
RTOS系统CSI&ISP内存修改
V85X 修改方式:
上图所说地址范围 0x43200000-0x43BFDFFF 是预留给 Melis 系统的 CSI & ISP 使用,在 lichee/rtos-hal/hal/source/vin/vin.h 修改被定义,如下所示:
#define MEMRESERVE 0x43200000
//0x2000 reserved for boot0 read flash and write to it
#define MEMRESERVE_SIZE (0xa00000 - 0x2000)
可以看到预留的内存是 0x43200000,与 board.dts 的 isp_reserved 预留的内存是一一对应的,MEMRESERVE_SIZE 是预留内存的大小,总共10M-8k,减掉8k的原因是地址范围 0x43BFE000-0x43BC0000 是分配给 flash 分区读取 ISP 配置保存区域。
如果 board.dts 中 isp_reserved 预留内存被修改,那么 Melis 系统的 vin.h 中需要修改 MEMRESERVE 以及 MEMRESERVE_SIZE。
V861 修改方式
位置: 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 修改


RTOS 系统固件预留内存修改
如果使用单目 WDR +单目线性,双目 WDR,双目摄像头不同的场景,由于 sensor 驱动的增加和效果头文件的增加会导致 Melis 系统固件增大,原本在 board.dts 预留的空间可能不够,需要进行修改。
V861/V838/V881 FreeRTOS 系统固件预留内存修改
board.dts修改
预留内存为 e907_fw,如下所示:
e907_mem_fw: e907_mem_fw@42400000 {
/* boot0 & uboot0 load elf addr */
reg = <0x0 0x42400000 0x0 0x200000>;
};
V85X Melis 系统固件预留内存修改
board.dts修改
预留内存为e907_fw,如下所示:
reserved-memory {
e907_fw: e907_fw {
reg = <0x0 0x43080000 0x0 0x00180000>;
};
}
boot0修改
V861 boot 固件预留内存修改
brandy/brandy-2.0/spl/include/configs/sun252iw1p1.h
#define SDRAM_OFFSET(x) ((phys_addr_t)0x40000000 + (x))
#define CONFIG_RTOS_LOAD_ADDR SDRAM_OFFSET(0x02400000)
V85X boot 固件预留内存修改
lichee/brandy-2.0/spl/board/sun8iw21p1/commonfastboot.mk
#E907
CFG_RISCV_E907=y
CFG_SUNXI_ELF=y
CFG_MELISELF_LOAD_ADDR=0x43080000
RTOS 系统 DRAM 预留内存修改
V861/V838/V881 FreeRTOS 系统预留的 DRAM 空间为4M,如果不够,则需要进行修改。
V861/V838/V881修改board.dts
e907_dram_reserved: e907_dram@41000000 {
reg = <0x0 0x41000000 0x0 0x900000>;
no-map;
};
FreeRTOS系统menuconfig修改 执行mrtos menuconfig,进入Architecture Options,如下图所示

V85X Melis 系统给 Melis 系统预留的 DRAM 空间为4M,如果不够,则需要进行修改。
board.dts修改
预留内存为e907_dram,如下所示:
e907_dram: riscv_memserve {
reg = <0x0 0x43c00000 0x0 0x00400000>;
no-map;
};
......
&e907_rproc {
memory-region = <&e907_dram>, <&vdev0buffer>,
<&vdev0vring0>, <&vdev0vring1>, <&rv_share_irq_table>;
memory-mappings =
/* DA len PA */
/* DDR for e907 */
< 0x43c00000 0x00400000 0x43c00000 >;
// iommus = <&mmu_aw 5 1>;
fw-region = <&e907_fw>;
firmware-name = "melis-elf";
share-irq = "e907";
status = "okay";
};
Melis系统menuconfig修改
修改Melis系统的DRAM配置,执行mmelis menuconfig,进入Platform Setup,如下图所示:

需要物理和虚拟起始地址和内存大小:
Physical base address of Dram:0x43c00000Virtual base address of Dram:0x43c00000Capacity of Dram:0x0400000
Melis系统编译链接脚本修改
修改编译链接脚本中的地址,文件位于lichee/melis-v3.0/source/projects/xxx/kernel.lds,如下所示:
MEMORY
{
/*DRAM_KERNEL: 4M */
DRAM_SEG_KRN (rwx) : ORIGIN = 0x43c00000, LENGTH = 0x00400000
}