5.17.4. SmartSens Sensor Bring-Up
本文
以 sc132gs 为例,说明 在 X5 平台 上 适配 SmartSens 系列 Camera Sensor 的 完整 流程 流程
包括 驱动 实现、App 配置 与 程序验证。通用 概念 与 dts 配置 请 先 阅读 Camera 调试 指南 。
源码
驱动
接口 :实现 hbre/camsys/libcam/src/sensor/sc132gs/sc132gs_setting.c增益
表与 Setting 配置 :hbre/camsys/libcam/src/sensor/sc132gs/inc/sc132gs_setting.h(gain_lut、init/stream_on/stream_off 寄存器数组)
5.17.4.1. dts配置
关于dts配置
和 上 电 和sensor的id识别 验证 参考修改 平台 设备树
5.17.4.2. 驱动
sensor_module_t 与文件命名
文件名:
sc132gs_utility.c;结构体/模块 名: sc132gs;库名:libsc132gs.so.1.0.0,部署到 板端 /usr/hobot/lib/sensor/。需
实现 的 接口:init、deinit、start、stop、power_on、power_off、aexp_gain_control、aexp_line_control、userspace_control。
#ifdef CAMERA_FRAMEWORK_HBN
SENSOR_MODULE_F(sc132gs, CAM_MODULE_FLAG_A16D8);
sensor_module_t sc132gs = {
.module = SENSOR_MNAME(sc132gs),
#else
sensor_module_t sc132gs = {
.module = "sc132gs",
#endif
.init = sensor_init,
.start = sensor_start,
.stop = sensor_stop,
.deinit = sensor_deinit,
.power_on = sensor_poweron,
.power_off = sensor_poweroff,
.aexp_gain_control = sensor_aexp_gain_control,
.aexp_line_control = sensor_aexp_line_control,
.userspace_control = sensor_userspace_control,
};
power_on
power_on 通过 X5 GPIO 控制 sensor 上电,需
结合 spec 上电 时序。 sensor_poweron 一般
在 sensor_init 中 调用,只 需要 控制 XSHUTDN 即可,以下 为 sc132gs power_on的 代码 实现:

int sensor_poweron(sensor_info_t *sensor_info)
{
int gpio, ret = RET_OK;
if(sensor_info->gpio_num > 0) {
for(gpio = 0; gpio < sensor_info->gpio_num; gpio++) {
if(sensor_info->gpio_pin[gpio] != -1) {
ret = vin_power_ctrl(sensor_info->gpio_pin[gpio],
sensor_info->gpio_level[gpio]);
usleep(1 * 100 * 1000); // 100ms
ret |= vin_power_ctrl(sensor_info->gpio_pin[gpio],
1 - sensor_info->gpio_level[gpio]);
if(ret < 0) {
vin_err("vin_power_ctrl fail\n");
return -HB_CAM_SENSOR_POWERON_FAIL;
}
usleep(100 * 1000); // 100ms
}
}
}
return ret;
}
power_off
power_off 通过 X5 GPIO 控制 sensor 下电,需
结合 spec 上电 时序。 sensor_poweroff 一般
在 sensor_deinit 中 调用,只 需要 控制 XSHUTDN 即可,以下 为 sc132gs power_off 的 代码 实现:
int sensor_poweroff(sensor_info_t *sensor_info)
{
int gpio, ret = RET_OK;
if(sensor_info->gpio_num > 0) {
for(gpio = 0; gpio < sensor_info->gpio_num; gpio++) {
if(sensor_info->gpio_pin[gpio] != -1) {
ret = vin_power_ctrl(sensor_info->gpio_pin[gpio],
sensor_info->gpio_level[gpio]);
if(ret < 0) {
vin_err("vin_power_ctrl fail\n");
return -1;
}
}
}
}
return ret;
}
init
将 sensor 初始化
寄存器 列表 通过i2c写 函数 写入 sensor;不同 分辨率 使用 不同 setting 数组 sc132gs_linear_data_init 用于
填充turning_data信息。 sensor_init 调用
时机 为 hbn_camera_attach_to_vin
int sensor_init(sensor_info_t *sensor_info)
{
int ret = RET_OK;
int setting_size = 0;
ret = sensor_poweron(sensor_info);
if (ret < 0) {
vin_err("%d : sensor reset %s fail\n", __LINE__, sensor_info->sensor_name);
return ret;
}
switch(sensor_info->sensor_mode) {
case NORMAL_M:
vin_info("sc132gs in normal mode\n");
setting_size = sizeof(sc132gs_linear_init_1088x1280_60fps_setting_master) / sizeof(uint32_t) / 2;
ret = sensor_configure(sensor_info, sc132gs_linear_init_1088x1280_60fps_setting_master, setting_size);
if (ret < 0) {
vin_err("%d : init %s fail\n", __LINE__, sensor_info->sensor_name);
return ret;
}
ret = sc132gs_linear_data_init_1088x1280(sensor_info);
if (ret < 0) {
vin_err("%d : linear data init %s fail\n", __LINE__, sensor_info->sensor_name);
return ret;
}
break;
default:
vin_err("not support mode %d\n", sensor_info->sensor_mode);
ret = -RET_ERROR;
break;
}
vin_info("sc132gs config success under %d mode\n\n", sensor_info->sensor_mode);
return ret;
}
其中 sensor_configure 内部vin_write_array 写
deinit
deinit 一般
调 用于 sensor的 反 初始化,直接 调用 power_off 下电 即可。 sensor_deinit 调用
时机 为 hbn_camera_destroy 或者 hbn_camera_detach_from_vin。
int sensor_deinit(sensor_info_t *sensor_info)
{
int ret = RET_OK;
ret = sensor_poweroff(sensor_info);
if (ret < 0) {
vin_err("%d : deinit %s fail\n", __LINE__, sensor_info->sensor_name);
return ret;
}
return ret;
}
start
start 实现
下发 开流 寄存器0x0100 为0x01,使 sensor 出流。 sensor_start 调用
时机 为 上层 调用 hbn_vflow_start。

int sensor_start(sensor_info_t *sensor_info)
{
int ret = RET_OK;
int setting_size = 0;
switch(sensor_info->sensor_mode) {
case NORMAL_M:
case SLAVE_M:
setting_size = sizeof(sc132gs_stream_on_setting)/sizeof(uint32_t)/2;
vin_info(" start linear mode, sensor_name %s, setting_size = %d\n", sensor_info->sensor_name, setting_size);
ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, 2,
setting_size, sc132gs_stream_on_setting);
if(ret < 0) {
vin_err("start %s fail\n", sensor_info->sensor_name);
return ret;
}
break;
}
return ret;
}
stop
stop 实现
下发 关流 寄存器 0x0100 为0x00,使 sensor 关流。 sensor_stop 调用
时机 为 上层 调用 hbn_vflow_stop
int sensor_stop(sensor_info_t *sensor_info)
{
int ret = RET_OK;
int setting_size = 0;
setting_size = sizeof(sc132gs_stream_off_setting) / sizeof(uint32_t) / 2;
vin_info("sensor stop sensor_name %s, setting_size = %d\n", sensor_info->sensor_name, setting_size);
ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, 2,
setting_size, sc132gs_stream_off_setting);
if (ret < 0) {
vin_err("start %s fail\n", sensor_info->sensor_name);
return ret;
}
return ret;
}
ISP 配置与 linear_data_init


在 sc132gs_linear_data_init 中
从 sensor 读 VTS(寄存器 0x320e/0x320f),计算 lines_per_second;
exposure_time_max/min、analog_gain_max、digital_gain_max;
填充 bayer(sensor_data_bayer_fill、sensor_data_bits_fill);
设置 stream_ctrl;将 again_lut 从
sc132gs_setting.h中的 sc132gs_gain_lut拷贝到turning_data.normal.again_lut,再通过 ioctl 下发。
关键
lines_per_second = vts * sensor_info->fpsexposure_time_max = vts - 8文档中为FRM_LENGTH_LINES - 8 即 VTS - 8 analog_gain_max = 156与 gain_lut 最大索引 一致,29.34x 对应 156,参照 gain 索引 值 和 增益 倍率 对照表 digital_gain_max = 159与 gain_lut 最大索引 一致,31.3x 对应 159,参照 gain 索引 值 和 增益 倍率 对照表 exposure_time_min = 1默认最小 配置 为 1,spec无 限制 sensor_data_bayer_fill(..., 10, BAYER_START_B, BAYER_PATTERN_RGGB);sensor_data_bits_fill(..., 12),0,0位置BAYER_START是 BAYER_START_B,BAYER_PATTERN是RGGB,raw10格式,sensor_data_bits_fill pwl mode 才会 用到,这里 配置12即可
aexp_gain_control
对于 SmartSens 的sensor gain控制,一般
采用 的 是 离散 档位 + 精细 调节,通常 查表 是 最快 的,根据 表 生成 直接 填写 agin_lut 和 dgain_lut即可(不 需要 使用 gain_table.xlsx),比较 方便快捷 SmartSens 使用 again + dgain 两路 LUT,寄存器
为 AGAIN 0x3e08/0x3e09、DGAIN 0x3e06/0x3e07。根据 ISP 下发 的 again[0]/dgain[0] 索引 查表.
参考

static int sensor_aexp_gain_control(hal_control_info_t *info, uint32_t mode, uint32_t *again, uint32_t *dgain, uint32_t gain_num)
{
const uint16_t AGAIN_LOW = 0x3e08;
const uint16_t AGAIN_HIGH = 0x3e09;
const uint16_t DGAIN_LOW = 0x3e06;
const uint16_t DGAIN_HIGH = 0x3e07;
char ana_gain = 0, ana_fine_gain = 0;
char dig_gain = 0, dig_fine_gain = 0;
int again_index = 0, dgain_index = 0;
if (mode == NORMAL_M || mode == DOL2_M) {
if (again[0] >= sizeof(sc132gs_gain_lut)/sizeof(uint32_t))
again_index = sizeof(sc132gs_gain_lut)/sizeof(uint32_t) - 1;
else
again_index = again[0];
if (dgain[0] >= sizeof(sc132gs_dgain_lut)/sizeof(uint32_t))
dgain_index = sizeof(sc132gs_dgain_lut)/sizeof(uint32_t) - 1;
else
dgain_index = dgain[0];
ana_gain = (sc132gs_gain_lut[again_index] >> 8) & 0xFF;
ana_fine_gain = sc132gs_gain_lut[again_index] & 0xFF;
dig_gain = (sc132gs_dgain_lut[dgain_index] >> 8) & 0xFF;
dig_fine_gain = sc132gs_dgain_lut[dgain_index] & 0xFF;
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, AGAIN_LOW, ana_gain);
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, AGAIN_HIGH, ana_fine_gain);
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, DGAIN_LOW, dig_gain);
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, DGAIN_HIGH, dig_fine_gain);
if (mode == DOL2_M) {
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, 0x3e12, ana_gain);
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, 0x3e13, ana_fine_gain);
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, 0x3e10, dig_gain);
vin_i2c_write8(info->bus_num, 16, info->sensor_addr, 0x3e11, dig_fine_gain);
}
} else {
vin_err(" unsupport mode %d\n", mode);
}
return 0;
}
aexp_line_control
aexp_line_control这个
接收ISP 3A算法
计算 的 下发 的 曝光 的 行 数 将
曝光 的 行 数 转换 为sensor寄存器 值 配置
通过i2c下 发给sensor 曝光 寄存器 这里
曝光 寄存器 为 0x3e00、0x3e01、0x3e02。
static int sc132gs_ae_set(uint32_t bus, uint32_t addr, uint32_t line)
{
const uint16_t EXP_LINE0 = 0x3e00;
const uint16_t EXP_LINE1 = 0x3e01;
const uint16_t EXP_LINE2 = 0x3e02;
char temp0 = 0, temp1 = 0, temp2 = 0;
uint32_t sline = line;
if (sline >= 2560) sline = 2560;
temp0 = (sline & 0xF000) >> 12;
temp1 = (sline & 0x0FF0) >> 4;
temp2 = (sline & 0x000F) << 4;
vin_i2c_write8(bus, 16, addr, EXP_LINE0, temp0);
vin_i2c_write8(bus, 16, addr, EXP_LINE1, temp1);
vin_i2c_write8(bus, 16, addr, EXP_LINE2, temp2);
return 0;
}
static int sensor_aexp_line_control(hal_control_info_t *info, uint32_t mode, uint32_t *line, uint32_t line_num)
{
uint32_t val;
if (mode == NORMAL_M) {
val = line[0];
sc132gs_ae_set(info->bus_num, info->sensor_addr, val);
} else {
vin_err(" unsupport mode %d\n", mode);
}
return 0;
}
userspace_control
这里 sensor_userspace_control 用于 Gain Control 与 Exposure Control开关。
用于 hbplayer 调试
时 排查 flicker 或 画面 异常,可 开关 HAL_GAIN_CONTROL / HAL_LINE_CONTROL确认 问题。
static int sensor_userspace_control(uint32_t port, uint32_t *enable)
{
vin_info("enable userspace gain control and line control\n");
*enable = HAL_GAIN_CONTROL | HAL_LINE_CONTROL;
return 0;
}
驱动部署
./bd.sh hbre camsys/libcam编译。将
out/deploy/hbre/lib/sensor/libsc132gs.so.1.0.0拷贝到板端 /usr/hobot/lib/sensor/。
5.17.4.3. App 配置
在
路径 app/samples/platform_samples/vp_sensors/sc132gs/中为 sc132gs 添加配置, 需
配置 mipi(lane、datatype、mipiclk、linelenth、framelenth、settle)、camera(name、addr、sensor_mode、gpio、fps、width、height、format)、vin_node_attr(mipi_rx、cim_isp_flyby 等)、vin_ichn_attr、vin_ochn_attr(wstride 等)、isp_attr、isp_ichn_attr、isp_ochn_attr。 HTS/VTS 可
从 寄存器 0x342/0x343、0x340/0x341 读取 或 咨询 Sensor FAE 提供 或者 使用 示波器 测量,测量方法 参考 mipi-参数 确定 mipiclk 一般
询问 Sensor FAE即可,计算方法 参考 MIPI CLK 其他
的 都 为 通用 配置,参考 文档 数据结构。 进行 配置 即可
vp_sensor 配置文件:linear_1088x1280_raw10_60fps_1lane.c
配置文件
路径: sc132gs/linear_1088x1280_raw10_60fps_1lane.c。配置
结构 体名: sc132gs_linear_1088x1280_raw10_60fps_1lane(需在 vp_sensor_config_list 中注册)。主要参数 如下:
| 配置 |
参数 |
取值 |
|---|---|---|
| 顶层 | config_file |
"linear_1088x1280_raw10_60fps_1lane.c" |
sensor_name |
"sc132gs-1280p" |
|
chip_id_reg / chip_id |
0x3107 / 0x0132 | |
sensor_i2c_addr_list |
{0x30, 0x33} | |
support_sensor_mode |
{NORMAL_M} | |
| MIPI | lane |
1 |
datatype |
RAW10 (0x2B) | |
fps |
60 | |
mipiclk |
1200(Mbps) | |
width / height |
1088 / 1280 | |
linelenth / framelenth |
1400 / 1500(与 sensor HTS/VTS) | |
settle |
20 | |
channel_num |
1 | |
| Camera | name / addr |
"sc132gs" / 0x33 |
sensor_mode |
1 (NORMAL_M) | |
format |
RAW10 | |
gpio_enable_bit / gpio_level_bit |
0x01 / 0x00 | |
calib_lname |
"disable" | |
| VIN | mipi_rx |
1 |
cim_isp_flyby |
0(offline) | |
hdr_mode |
NOT_HDR | |
mclk_freq (vin_attr_ex) |
24000000(24MHz) | |
lpwm_enable |
1 | |
lpwm_period / offset / duty_time |
33333µs / 10µs / 100µs | |
| VIN 输出 | wstride |
SENSOR_WIDTH * 2(RAW10 为 ×2) |
| ISP 输入 | input_mode |
DDR_MODE |
sensor_mode |
ISP_NORMAL_M | |
crop |
x=0, y=0, w=1088, h=1280 | |
input_fmt |
FRM_FMT_RAW | |
input_bit_width |
10 | |
| ISP 输出 | output_fmt |
FRM_FMT_NV12 |
output_bit_width |
8 | |
ddr_en |
1 |
5.17.4.4. 程序验证
get_vin_data:确认 raw 图
无 严重 偏色、帧 率 符合 配置。 get_isp_data:准备
sc132gs_tuning.json(可拷贝 同 分辨率 json 并 改 sensor_name),确认 YUV 正常。 hbplayer:连接
板端 预览,见 hbplayer 和 tuning_tool 工具 使用指南 。tuning_tool:使用tuning_tool连接hbplayer后,输入
命令 e,配置 Manual AE,设置 aGain、integrationTime,看 驱动 打印 核对 0x3e08/0x3e09、0x3e06/0x3e07、0x3e00~0x3e02 与 spec 一致,ISP 增益 限制 可 在 sc132gs_tuning.json 中 配置 以便 自测。
常见问题