一、简介
1、TP9930
TP9930 驱动模块主要实现将 4 路的 Camera 的数据转换为 BT656/BT1120 数据,从而实现在 T527 端来对数据进行处理和送显。
2、BT656/BT1120简介
BT656主要是针对PAL/NTSC等标清视频。随着高清视频的发展需要,又推出了BT1120标准,它与BT656是类似的,只不过时钟频率更高了,以适合高清视频的传输,例如1080P等。其实BT656与BT1120之间区别主要是传输数据的速率不同,例如BT656与BT1120都能传输720P的视频,但是BT656只能传输低帧率的720P,而BT1120能够传输高帧率的720P视频。
T5平台能够分别支持BT656与BT1120两种协议,只需要在驱动文件的sensor_formats[]中配置.mbus_code即可,而不需要改动其他配置参数
二、硬件信息
1、通信接口
TWI3总线
2、引脚组
3、RESET脚
4、IIC地址
5、供电
(1)摄像头电源使能
I2S2-MCLK>>>>>>>>>>>PE5
(2)DV5V0_SYS
UART2-RTS-JTAG-DO>>>>>>>>>>>>PB2
(3)DV3V3_SYS
PC7_SYS_STATUS_LED0>>>>>>>>>>>>PC7
6、BT1120引脚
配置如下:
"PK12", NCSI_PCLK
"PK14", NCSI_VSYNC
"PK15", NCSI_HSYNC
"PK16", NCS-D0
"PK17", NCS-D1
"PK18", NCS-D2
"PK19", NCS-D3
"PK20", NCS-D4
"PK21", NCS-D5
"PK22", NCS-D6
"PK23", NCS-D7
"PE6", NCS-D8
"PE7", NCS-D9
"PE8", NCS-D10
"PE9", NCS-D11
"PE10", NCS-D12
"PE11", NCS-D13
"PE12", NCS-D14
"PE15"; NCS-D15
ncsi_bt1120_pins_a: ncsi_BT1120@0 {
pins = "PK12", "PK14", "PK15",
"PK16", "PK17", "PK18", "PK19",
"PK20", "PK21", "PK22", "PK23",
"PE6", "PE7", "PE8", "PE9",
"PE10", "PE11", "PE12", "PE15";
function = "ncsi";
drive-strength = <20>;
};
ncsi_bt1120_pins_b: ncsi_BT1120@1 {
pins = "PK12", "PK14", "PK15",
"PK16", "PK17", "PK18", "PK19",
"PK20", "PK21", "PK22", "PK23",
"PE6", "PE7", "PE8", "PE9",
"PE10", "PE11", "PE12", "PE15";
function = "gpio_in";
};
从上面原理图分析可知:
• 使用的是 BT1120 的模式。
• 使用的是 PE3,PE4 这一组 TWI3 的通讯接口。
• RESET 控制接口为 PK10,低电平有效,使用时拉高。
• 供电由DV3V3_SYS,DV5V0_SYS供电,I2S2-MCLK 为摄像头供电,需软件单独拉起,引脚分别为PC7、 PB2、 PE5。
三、软件配置
1、设备树
路径:device/config/chips/t527/configs/demo_linux_car/linux-5.15/board.dts
(1)使能 TWI3
(2)确认使用的是 PE3 和 PE4,然后确认 TWI3 是否正常使能。
(3)设备树:
csi3:csi@5823000 {
pinctrl-names = "default","sleep";
pinctrl-0 = <&ncsi_bt1120_pins_a>;
pinctrl-1 = <&ncsi_bt1120_pins_b>;
status = "okay";
};
sensor1:sensor@5812010 {
device_type = "sensor1";
sensor1_mname = "tp9930";
sensor1_twi_cci_id = <3>;//twi3
sensor1_twi_addr = <0x8a>;
sensor1_mclk_id = <3>;//2
sensor1_pos = "front";
sensor1_isp_used = <0>;
sensor1_fmt = <0>;
sensor1_stby_mode = <0>;
sensor1_vflip = <0>;
sensor1_hflip = <0>;
sensor1_iovdd-supply = <>;
sensor1_iovdd_vol = <>;
sensor1_avdd-supply = <>;
sensor1_avdd_vol = <>;
sensor1_dvdd-supply = <>;
sensor1_dvdd_vol = <>;
sensor1_power_en = <>;
sensor1_reset = <>;
sensor1_reset = <>;
sensor1_pwdn = <>;
status = "okay";
};
vinc40:vinc@5834000 {
vinc16_csi_sel = <3>;
vinc16_mipi_sel = <0xff>;
vinc16_isp_sel = <5>;
vinc16_isp_tx_ch = <0>;
vinc16_tdm_rx_sel = <0>;
vinc16_rear_sensor_sel = <1>;
vinc16_front_sensor_sel = <1>;
vinc16_sensor_list = <0>;
device_id = <16>;
status = "okay";
};
vinc50:vinc@5835000 {
vinc17_csi_sel = <3>;
vinc17_mipi_sel = <0xff>;
vinc17_isp_sel = <5>;
vinc17_isp_tx_ch = <1>;
vinc17_tdm_rx_sel = <0>;
vinc17_rear_sensor_sel = <1>;
vinc17_front_sensor_sel = <1>;
vinc17_sensor_list = <0>;
device_id = <17>;
status = "okay";
};
2、移植驱动、添加Makefile、Kconfig
驱动:tp9930.c
路径:bsp/drivers/vin/modules/sensor
(1)Makefile
(2)Kconfig
(3)./build.sh menuconfig勾选对应驱动
(4)保存./build.sh savaconfig
四、编译测试
1、video节点
配置挂载完后烧录:
2、sensor设备
cat /sys/class/video4linux/v4l-subdev1/name
3、应用程序测试
csi_test_usrptr 16 0 1280 720 /usr 4 10000 25
csi_test_usrptr 17 0 1280 720 /usr 4 10000 25
在T527 linux系统上调试TP9930双路输出时,在运行应用程序打开双路摄像头采集图像时出现程序崩溃,内容如下:
INFO : cedarc <VeIniti[ 86.954756] FSC = 0x05: level 1 translation fault
alize:1549>: *** ic_version = 0x[ 86.962996] Data abort info:
3321000012011,
01-01 00:01:52.3[ 86.968993] ISV = 0, ISS = 0x00000005
40 hwdisplay2(D) : libsdk_disp v[ 86.976067] CM = 0, WnR = 0
1.version:V2.1.20221031
open /d
ev/video17 fd = 6
[ 45.439589] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000118
on:V2.1.20220906
[ 86.982163] user pgtable: 4k pages, 39-bit VAs, pgdp=000000010a7f5000
[ 86.992160] [0000000000000118] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000
[ 87.003563] Internal error: Oops: 96000005 [#1] PREEMPT SMP
[ 87.009804] Modules linked in: vipcore 8821cs mali_kbase(O)
[ 87.016056] CPU: 4 PID: 1216 Comm: csi_test_usrptr Tainted: G O 5.15.123 #11
[ 87.025418] Hardware name: sun55iw3 (DT)
[ 87.029809] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 87.037610] pc : mutex_lock+0xc/0x50
[ 87.041619] lr : media_entity_setup_link+0x24/0x5c
[ 87.046990] sp : ffffffc00e87baf0
[ 87.050698] x29: ffffffc00e87baf0 x28: ffffff80c506a100 x27: 0000000000000000
[ 87.058700] x26: 0000000000000000 x25: 0000000000000330 x24: ffffff80c0116d70
[ 87.066697] x23: 0000000000000033 x22: ffffff80c3990080 x21: 0000000000000001
[ 87.074698] x20: 0000000000000001 x19: ffffff80c3693830 x18: 0000000000000000
[ 87.082696] x17: 0000000000000000 x16: 0000000000000000 x15: 0000007fc3770a58
[ 87.090697] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000
[ 87.098697] x11: 0000000000000000 x10: 0000000000000000 x9 : 0000000000000000
[ 87.106698] x8 : 0000000000000000 x7 : 0000000000000000 x6 : 0000000000000001
[ 87.114698] x5 : ffffffc008c3be38 x4 : 0000000000000001 x3 : 0000000000000001
[ 87.122697] x2 : ffffff80ca473fc0 x1 : 0000000000000000 x0 : 0000000000000118
[ 87.130694] Call trace:
[ 87.133427] mutex_lock+0xc/0x50
[ 87.137040] __vin_sensor_setup_link+0xbc/0x130
[ 87.142116] __vin_s_input+0x74/0x390
[ 87.146218] vidioc_s_input+0x44/0x80
[ 87.150319] v4l_s_input+0x58/0x94
[ 87.154127] __video_do_ioctl+0x17c/0x3e0
[ 87.158615] video_usercopy+0x224/0x6f0
[ 87.162908] video_ioctl2+0x18/0x30
[ 87.166811] v4l2_ioctl+0x40/0x60
[ 87.170521] __arm64_sys_ioctl+0xb8/0xe0
[ 87.174914] invoke_syscall+0x54/0x124
[ 87.179112] el0_svc_common.constprop.0+0x44/0xec
[ 87.184382] do_el0_svc+0x40/0xa0
[ 87.188091] el0_svc+0x20/0x60
[ 87.191508] el0t_64_sync_handler+0xb0/0xb4
[ 87.196194] el0t_64_sync+0x1a0/0x1a4
[ 87.200298] Code: d65f03c0 d2800001 d5384102 f9800011 (c85ffc03)
[ 87.207126] ---[ end trace b99917f213e868dc ]---
[ 87.212296] Kernel panic - not syncing: Oops: Fatal exception
[ 87.218731] SMP: stopping secondary CPUs
[ 87.223163] Kernel Offset: disabled
[ 87.227065] CPU features: 0x3,00000201,23100e42
[ 87.232138] Memory Limit: none
[ 87.235558] ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
搜索找到了内核原函数,
bsp/drivers/vin/vin-video/vin_video.c:1954:
static int __vin_sensor_setup_link(struct vin_core *vinc, struct modules_config *module,
static int __vin_sensor_setup_link(struct vin_core *vinc, struct modules_config *module,
int i, int en)
{
struct vin_md *vind = dev_get_drvdata(vinc->v4l2_dev->dev);
struct v4l2_subdev *sensor = module->modules.sensor[i].sd;
struct v4l2_subdev *subdev;
struct media_entity *entity = NULL;
struct media_link *link = NULL;
__maybe_unused struct sensor_info *info = to_state(sensor);
int ret;
if (sensor == NULL)
return -1;
if (vinc->mipi_sel != 0xff)
subdev = vind->mipi[vinc->mipi_sel].sd;
else
subdev = vind->csi[vinc->csi_sel].sd;
entity = &sensor->entity;
list_for_each_entry(link, &entity->links, list) {
if (link->source->entity == entity && link->sink->entity == &subdev->entity)
break;
}
if (link == NULL)
return -1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
if (info->stream_count >= 1)
return 0;
#else
if (sensor->entity.stream_count >= 1)
return 0;
#endif
vin_log(VIN_LOG_VIDEO, "setup link: [%s] %c> [%s]\n",
sensor->name, en ? '=' : '-', link->sink->entity->name);
if (en)
ret = media_entity_setup_link(link, MEDIA_LNK_FL_ENABLED);
else
ret = __media_entity_setup_link(link, 0);
/* When the this function is called by the close
function, the mutex conflicts with the close mutex,
so the function without the mutex is used. */
if (ret) {
vin_warn("%s setup link %s fail!\n", sensor->name,
link->sink->entity->name);
return -1;
}
return 0;
}
在该代码中增加空指针检查和错误处理:
再次测试时出现打印
CSI subdev is NULL
设备树中配置为0xff,vinc16/17_mipi_sel = ;,执行subdev = vind->csi[vinc->csi_sel].sd;
问题出现在选择 CSI 子设备时,打印出了 "CSI subdev is NULL"。这种情况通常表示在尝试从 vind->csi[vinc->csi_sel].sd 中获取 CSI 子设备时,该指针为 NULL。
根据添加的打印信息得知,vind、vind->csi、vinc->csi_sel都不为空,检查csi设备的注册情况
搜索代码:定位到定义了一个名为 csi 的数组,每个元素的类型是 struct vin_csi_info。数组的大小是 VIN_MAX_CSI
修改为3进行测试
段错误问题解决,CSI 和 ISP 之间的链接时遇到了新的问题
定位代码:bsp/drivers/vin/vin-video/vin_video.c
添加打印,确认isp和csi 是否都非空
打印结果:
media_entity_find_link函数的实现
kernel/linux-5.15/drivers/media/mc/mc-entity.c
确认是否使用BT1120的模式,对应需要修改使用双边沿采样,具体修改位置在驱动sensor_g_mbus_config中,具体位置如下:
引脚 PE11 已经被 UART 设备占用,CSI 设备无法再次请求该引脚
找到对应的UART
关闭uart5、uart6节点
再次测试,对应的csi驱动未成功probe
定位代码:
路径:kernel/linux-5.15/drivers/base/dd.c +509
CSI驱动
路径:bsp/drivers/vin/vin-csi/sunxi_csi.c
......................
数组大小和probe有很大关系,尝试修改验证
CSI3驱动成功注册,认真看的同学应该发现,这一开始呗改为了3,现在又改回4了,是什么原因呢?
从上方我贴出的源码,VIN_MAX_CSI必须为4才能成功注册CSI3,最开始导致段错误最根本的原因不是这个,而是引脚复用导致的csi3的subdev未成功初始化。
测试:出现IIC通信问题,ACK not received
问题分析;
该i2c 报错为从设备无响应,即Sensor未正确回应,出现该问题的情况通常有如下几种。
1.VCC‑Sensor未上电,可用万用表确认。
2.初始化时序错误,导致Sensor未正常初始化,需检查Sensor驱动中初始化流程是否满足datasheet要求。
3.VCC‑Sensor有上电,初始化时序也正常,但是VCC‑Sensor上电有抖动导致Sensor异常。
4.VCC‑Sensor有上电,但Sensor初始化依赖的RST 或 INT 未正确拉高或拉低。
5.Sensor引脚未接好导致。
6.Sensor本身是坏的。
原因排查
1.交换iic,交叉测试,IIC正常
2.通过万用表测试Sensor电压、RST等未发现异常
解决方法
更换TP9930芯片后测试,正常
测试:
csi_test_usrptr 16 0 1280 720 /usr 4 10 25
csi_test_usrptr 17 0 1280 720 /usr 4 10 25
YUYViewer工具查看图像正常
media-ctl -p -d /dev/media0
4、查看链路
前提:打开debugfs
mount -t debugfs mone /sys/kernel/debug
cat /sys/kernel/debug/mpp/vi