发布: 搭建V853开发环境

This commit is contained in:
weidongshan
2024-02-24 18:16:36 +08:00
parent 0e79acd69b
commit 723728c7b7
34 changed files with 791923 additions and 1 deletions

View File

@@ -7,7 +7,7 @@
* 瑞芯微rk3568平台摄像头控制器MIPI-CSI驱动架构梳理https://zhuanlan.zhihu.com/p/621470492
* MIPI、CSI基础https://zhuanlan.zhihu.com/p/599531271
* 全志T7 CSIC模块https://blog.csdn.net/suwen8100/article/details/116226366
* 全志在线文档https://v853.docs.aw-ol.com/soft/soft_camera/
* 全志在线文档https://v853.docs.aw-ol.com/soft/soft_camera/
* 参考源码https://gitee.com/juping_zheng1/v85x-mediactrl
@@ -111,3 +111,291 @@ D-PHY接口典型图例如下
可以跟瑞芯微的对比一下https://zhuanlan.zhihu.com/p/599531271
## 3. 开发环境搭建
IMX6ULL、STM32MP157上没有MIPI接口我们使用V853开发板来讲解MIPI驱动。
要理解MIPI驱动核心是subdev、media子系统全网都没有关于它们的详细而系统的文档。而要想理解一个驱动必须从这2方面学习APP怎么使用、驱动如何实现。必须去阅读、分析真实板子的驱动动手操作。
### 3.1 下载资料
V853所有资料都汇总于此https://forums.100ask.net/t/topic/2986
获取网盘资料后,按照"01_学习手册"目录中的《100ASK-V853-Pro系统开发手册》安装虚拟机VMWare、打开Ubuntu虚拟机上传解压源码。
### 3.2 编译/运行Hello
有3套工具链
```shell
cd ~/tina-v853-open/prebuilt/rootfsbuilt/arm
find -name "*gcc"
```
![image-20240223113141663](pic/v853/14_toolchain.png)
开发板/lib目录的库来自工具链①musl的C库比较精简但是没有glibc完善。编译一般的APP是没问题的但是编译v4l2-utils时会提示缺乏头文件。
对于简单的APP建议使用工具链①
对于复杂的APP如果使用工具链①无法编译就使用工具链②它含有glibc要静态链接。
使用工具链①:
```shel
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin
export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
arm-openwrt-linux-muslgnueabi-gcc -o hello hello.c
```
使用工具链②:
```shell
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/bin
export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/arm-openwrt-linux-gnueabi
arm-openwrt-linux-gnueabi-gcc -o hello2 hello.c -static
```
放到板子上去在Ubuntu执行如下命令
```shell
adb push hello /root
```
在板子上运行:
```shell
/root/hello
```
在Ubuntu中无法识别adb设备的解决方法
https://blog.csdn.net/xiaowang_lj/article/details/133682416
```shell
sudo vi /etc/udev/rules.d/51-android.rules
# 增加如下内容
SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="d002",MODE="0666",GROUP="plugdev"
sudo service udev restart
sudo adb kill-server
adb devices
```
### 3.3 更换单板系统
#### 3.3.1 重烧系统
V853开发板出厂自带的系统里面的文件比如/lib使用的是musl C库。musl是个精简的C库功能受限无法运行v4l-utils。
我们需要更换系统新系统使用glibc库里面已经集成了v41-utils。可以参考"100ASK-V853_Pro系统开发手册.pdf"里《4.5.1 烧录EMMC系统》烧写GIT仓库里如下文件
![image-20240224145318790](pic/v853/15_v853_image.png)
#### 3.3.2 体验v4l-utils
在板子上:
```shell
# 先运行camerademo
camerademo
# 否则下面的命令会崩溃
media-ctl -p -d /dev/media0
media-ctl -d /dev/media0 --print-dot > media0.dot
```
Ubuntu上
```shell
sudo apt install xdot
adb pull /root/media0.dot
dot -Tpng media0.dot -o media0.png
```
Ubuntu上测试USB摄像头
```shell
cd ~/v4l-utils-1.20.0
./configure
make
sudo make install
su root
media-ctl -p -d /dev/media0
media-ctl -d /dev/media0 --print-dot > uvc_media0.dot
dot -Tpng uvc_media0.dot -o uvc_media0.png
```
### 3.4 自己制作单板系统
我们的目的是使用v4l-utils它依赖于glibc库。所以
* 步骤1使用glibc的工具链编译v4l-utils
* 步骤2把编译好的v4l-utils文件放入v853的SDK包里
* 步骤3编译、打包v853映像文件
#### 3.4.1 编译v4l-utils
官网http://linuxtv.org/downloads/v4l-utils
下载地址https://linuxtv.org/downloads/v4l-utils/v4l-utils-1.20.0.tar.bz2
编译命令:
```shell
#export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin
#export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
# 使用GLIBC的工具链
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/bin
export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/arm-openwrt-linux-gnueabi
wget https://linuxtv.org/downloads/v4l-utils/v4l-utils-1.20.0.tar.bz2
tar xjf v4l-utils-1.20.0.tar.bz2
cd ~/v4l-utils-1.20.0
./configure --host=arm-openwrt-linux-gnueabi --prefix=$PWD/tmp --with-udevdir=$PWD/tmp
make # 有错也没关系
make install
# 在tmp目录下生成了如下文件
book@100ask:~/v4l-utils-1.20.0$ ls tmp/
bin etc include lib rc_keymaps rules.d sbin share
```
#### 3.4.2 把文件放入SDK
复制文件:
```shell
#把v4l-utils的tmp/bin, tmp/lib复制到如下目录:
# /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files
cd ~/v4l-utils-1.20.0/tmp
cp bin /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files -rf
cp lib /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files -rf
# 删除单板无需使用的文件
cd /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files/lib
rm *.a
rm *.la
```
修改文件: ~/tina-v853-open/openwrt/package/allwinner/system/busybox-init-base-files/Makefile
增加以下内容(不增加以下内容的话在tina-v853-open中make时会提示找不到依赖文件):
```shell
define Package/$(PKG_NAME)/extra_provides
echo 'libstdc++.so.6'
endef
```
#### 3.4.3 制作映像
要自己制作映像文件的话,操作方法如下:
```shell
# 上传SDK,解压得到tina-v853-open目录
book@100ask:~$ cat tina-v853-open.tar.gz* | tar xz
# 下载补丁包
book@100ask:~$ git clone https://github.com/DongshanPI/100ASK_V853-PRO_TinaSDK.git
book@100ask:~$ cp -rfvd 100ASK_V853-PRO_TinaSDK/* tina-v853-open/
book@100ask:~$ cd tina-v853-open/
# 配置
~/tina-v853-open$ source build/envsetup.sh
# 选择
~/tina-v853-open$ lunch
ou're building on Linux
Lunch menu... pick a combo:
1 v853-100ask-tina
2 v853-vision-tina
Which would you like? [Default v853-100ask]: 1
# 重新配置使用glibc的工具链
~/tina-v853-open$ make menuconfig
-> Advanced configuration options (for developers)
-> Use external toolchain
-> Use host's toolchain
-> Toolchain root # 设置为: $(LICHEE_TOP_DIR)/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain
-> Toolchain libc # 选择glibc
# 编译
~/tina-v853-open$ make -j 16
# 制作映像文件
~/tina-v853-open$ pack
# 提示分区太小
ERROR: dl file rootfs.fex size too large
ERROR: filename = rootfs.fex
ERROR: dl_file_size = 46848 sector
ERROR: part_size = 45824 sector
update_for_part_info -1
ERROR: update mbr file fail
ERROR: update_mbr failed
# 修改分区大小
vi ./device/config/chips/v853/configs/100ask/linux-4.9/sys_partition.fex
[partition]
name = rootfs
size = 47000 # 从45824改为47000
downloadfile = "rootfs.fex"
user_type = 0x8000
# 再重新pack
~/tina-v853-open$ pack
# 得到如下文件:
34M /home/book/tina-v853-open/out/v853/100ask/openwrt/v853_linux_100ask_uart0.img
```
配置界面如下图所示:
![image-20240224173912240](pic/v853/16_menuconfig.png)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,139 @@
digraph board {
rankdir=TB
n00000001 [label="{{} | gc2053_mipi\n/dev/v4l-subdev0 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
n00000001:port0 -> n00000023 [style=dashed]
n00000001:port0 -> n00000023 [style=dashed]
n00000003 [label="vin_cap.0\n/dev/v4l-subdev1", shape=box, style=filled, fillcolor=yellow]
n00000003 -> n00000006
n00000006 [label="vin_video0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
n0000000a [label="vin_cap.12\n/dev/v4l-subdev2", shape=box, style=filled, fillcolor=yellow]
n0000000a -> n0000000d
n0000000d [label="vin_video12\n/dev/video12", shape=box, style=filled, fillcolor=yellow]
n00000011 [label="sunxi_csi.0\n/dev/v4l-subdev3", shape=box, style=filled, fillcolor=yellow]
n00000011 -> n00000017
n00000011 -> n00000017
n00000014 [label="sunxi_csi.1\n/dev/v4l-subdev4", shape=box, style=filled, fillcolor=yellow]
n00000017 [label="sunxi_tdm_rx.0\n/dev/v4l-subdev5", shape=box, style=filled, fillcolor=yellow]
n00000017 -> n00000029:port0
n00000017 -> n00000029:port0
n0000001a [label="sunxi_tdm_rx.1\n/dev/v4l-subdev6", shape=box, style=filled, fillcolor=yellow]
n0000001d [label="sunxi_tdm_rx.2\n/dev/v4l-subdev7", shape=box, style=filled, fillcolor=yellow]
n00000020 [label="sunxi_tdm_rx.3\n/dev/v4l-subdev8", shape=box, style=filled, fillcolor=yellow]
n00000023 [label="sunxi_mipi.0\n/dev/v4l-subdev9", shape=box, style=filled, fillcolor=yellow]
n00000023 -> n00000011
n00000023 -> n00000011
n00000026 [label="sunxi_mipi.1\n/dev/v4l-subdev10", shape=box, style=filled, fillcolor=yellow]
n00000029 [label="{{<port0> 0} | sunxi_isp.0\n/dev/v4l-subdev11 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
n00000029:port1 -> n0000002d:port0 [style=bold]
n00000029:port2 -> n00000047:port0
n00000029:port2 -> n0000004a:port0 [style=dashed]
n00000029:port2 -> n0000004d:port0 [style=dashed]
n00000029:port2 -> n00000050:port0 [style=dashed]
n00000029:port2 -> n00000053:port0 [style=dashed]
n00000029:port2 -> n00000056:port0 [style=dashed]
n00000029:port2 -> n00000059:port0 [style=dashed]
n00000029:port2 -> n0000005c:port0 [style=dashed]
n00000029:port2 -> n0000005f:port0 [style=dashed]
n00000029:port2 -> n00000062:port0 [style=dashed]
n00000029:port2 -> n00000065:port0 [style=dashed]
n00000029:port2 -> n00000068:port0 [style=dashed]
n00000029:port2 -> n0000006b:port0
n00000029:port2 -> n0000006e:port0 [style=dashed]
n00000029:port2 -> n00000071:port0 [style=dashed]
n00000029:port2 -> n00000074:port0 [style=dashed]
n0000002d [label="{{<port0> 0} | sunxi_h3a.0\n/dev/v4l-subdev12 | {}}", shape=Mrecord, style=filled, fillcolor=green]
n0000002f [label="{{<port0> 0} | sunxi_isp.1\n/dev/v4l-subdev13 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
n0000002f:port1 -> n00000033:port0 [style=bold]
n0000002f:port2 -> n00000047:port0 [style=dashed]
n0000002f:port2 -> n0000004a:port0 [style=dashed]
n0000002f:port2 -> n0000004d:port0 [style=dashed]
n0000002f:port2 -> n00000050:port0 [style=dashed]
n0000002f:port2 -> n00000053:port0 [style=dashed]
n0000002f:port2 -> n00000056:port0 [style=dashed]
n0000002f:port2 -> n00000059:port0 [style=dashed]
n0000002f:port2 -> n0000005c:port0 [style=dashed]
n0000002f:port2 -> n0000005f:port0 [style=dashed]
n0000002f:port2 -> n00000062:port0 [style=dashed]
n0000002f:port2 -> n00000065:port0 [style=dashed]
n0000002f:port2 -> n00000068:port0 [style=dashed]
n0000002f:port2 -> n0000006b:port0 [style=dashed]
n0000002f:port2 -> n0000006e:port0 [style=dashed]
n0000002f:port2 -> n00000071:port0 [style=dashed]
n0000002f:port2 -> n00000074:port0 [style=dashed]
n00000033 [label="{{<port0> 0} | sunxi_h3a.1\n/dev/v4l-subdev14 | {}}", shape=Mrecord, style=filled, fillcolor=green]
n00000035 [label="{{<port0> 0} | sunxi_isp.2\n/dev/v4l-subdev15 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
n00000035:port1 -> n00000039:port0 [style=bold]
n00000035:port2 -> n00000047:port0 [style=dashed]
n00000035:port2 -> n0000004a:port0 [style=dashed]
n00000035:port2 -> n0000004d:port0 [style=dashed]
n00000035:port2 -> n00000050:port0 [style=dashed]
n00000035:port2 -> n00000053:port0 [style=dashed]
n00000035:port2 -> n00000056:port0 [style=dashed]
n00000035:port2 -> n00000059:port0 [style=dashed]
n00000035:port2 -> n0000005c:port0 [style=dashed]
n00000035:port2 -> n0000005f:port0 [style=dashed]
n00000035:port2 -> n00000062:port0 [style=dashed]
n00000035:port2 -> n00000065:port0 [style=dashed]
n00000035:port2 -> n00000068:port0 [style=dashed]
n00000035:port2 -> n0000006b:port0 [style=dashed]
n00000035:port2 -> n0000006e:port0 [style=dashed]
n00000035:port2 -> n00000071:port0 [style=dashed]
n00000035:port2 -> n00000074:port0 [style=dashed]
n00000039 [label="{{<port0> 0} | sunxi_h3a.2\n/dev/v4l-subdev16 | {}}", shape=Mrecord, style=filled, fillcolor=green]
n0000003b [label="{{<port0> 0} | sunxi_isp.3\n/dev/v4l-subdev17 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
n0000003b:port1 -> n0000003f:port0 [style=bold]
n0000003b:port2 -> n00000047:port0 [style=dashed]
n0000003b:port2 -> n0000004a:port0 [style=dashed]
n0000003b:port2 -> n0000004d:port0 [style=dashed]
n0000003b:port2 -> n00000050:port0 [style=dashed]
n0000003b:port2 -> n00000053:port0 [style=dashed]
n0000003b:port2 -> n00000056:port0 [style=dashed]
n0000003b:port2 -> n00000059:port0 [style=dashed]
n0000003b:port2 -> n0000005c:port0 [style=dashed]
n0000003b:port2 -> n0000005f:port0 [style=dashed]
n0000003b:port2 -> n00000062:port0 [style=dashed]
n0000003b:port2 -> n00000065:port0 [style=dashed]
n0000003b:port2 -> n00000068:port0 [style=dashed]
n0000003b:port2 -> n0000006b:port0 [style=dashed]
n0000003b:port2 -> n0000006e:port0 [style=dashed]
n0000003b:port2 -> n00000071:port0 [style=dashed]
n0000003b:port2 -> n00000074:port0 [style=dashed]
n0000003f [label="{{<port0> 0} | sunxi_h3a.3\n/dev/v4l-subdev18 | {}}", shape=Mrecord, style=filled, fillcolor=green]
n00000041 [label="{{<port0> 0} | sunxi_isp.4\n/dev/v4l-subdev19 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
n00000041:port1 -> n00000045:port0 [style=bold]
n00000041:port2 -> n00000047:port0 [style=dashed]
n00000041:port2 -> n0000004a:port0 [style=dashed]
n00000041:port2 -> n0000004d:port0 [style=dashed]
n00000041:port2 -> n00000050:port0 [style=dashed]
n00000041:port2 -> n00000053:port0 [style=dashed]
n00000041:port2 -> n00000056:port0 [style=dashed]
n00000041:port2 -> n00000059:port0 [style=dashed]
n00000041:port2 -> n0000005c:port0 [style=dashed]
n00000041:port2 -> n0000005f:port0 [style=dashed]
n00000041:port2 -> n00000062:port0 [style=dashed]
n00000041:port2 -> n00000065:port0 [style=dashed]
n00000041:port2 -> n00000068:port0 [style=dashed]
n00000041:port2 -> n0000006b:port0 [style=dashed]
n00000041:port2 -> n0000006e:port0 [style=dashed]
n00000041:port2 -> n00000071:port0 [style=dashed]
n00000041:port2 -> n00000074:port0 [style=dashed]
n00000045 [label="{{<port0> 0} | sunxi_h3a.4\n/dev/v4l-subdev20 | {}}", shape=Mrecord, style=filled, fillcolor=green]
n00000047 [label="{{<port0> 0} | sunxi_scaler.0\n/dev/v4l-subdev21 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000047:port1 -> n00000003
n0000004a [label="{{<port0> 0} | sunxi_scaler.1\n/dev/v4l-subdev22 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n0000004d [label="{{<port0> 0} | sunxi_scaler.2\n/dev/v4l-subdev23 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000050 [label="{{<port0> 0} | sunxi_scaler.3\n/dev/v4l-subdev24 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000053 [label="{{<port0> 0} | sunxi_scaler.4\n/dev/v4l-subdev25 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000056 [label="{{<port0> 0} | sunxi_scaler.5\n/dev/v4l-subdev26 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000059 [label="{{<port0> 0} | sunxi_scaler.6\n/dev/v4l-subdev27 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n0000005c [label="{{<port0> 0} | sunxi_scaler.7\n/dev/v4l-subdev28 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n0000005f [label="{{<port0> 0} | sunxi_scaler.8\n/dev/v4l-subdev29 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000062 [label="{{<port0> 0} | sunxi_scaler.9\n/dev/v4l-subdev30 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000065 [label="{{<port0> 0} | sunxi_scaler.10\n/dev/v4l-subdev31 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000068 [label="{{<port0> 0} | sunxi_scaler.11\n/dev/v4l-subdev32 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n0000006b [label="{{<port0> 0} | sunxi_scaler.12\n/dev/v4l-subdev33 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n0000006b:port1 -> n0000000a
n0000006e [label="{{<port0> 0} | sunxi_scaler.13\n/dev/v4l-subdev34 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000071 [label="{{<port0> 0} | sunxi_scaler.14\n/dev/v4l-subdev35 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000074 [label="{{<port0> 0} | sunxi_scaler.15\n/dev/v4l-subdev36 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@@ -0,0 +1,11 @@
digraph board {
rankdir=TB
n00000001 [label="USB 2.0 Camera: USB 2.0 Camera\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
n00000004 [label="USB 2.0 Camera: USB 2.0 Camera\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
n00000008 [label="{{<port0> 0} | Processing 2\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000008:port1 -> n00000001 [style=bold]
n00000008:port1 -> n0000000b:port0 [style=bold]
n0000000b [label="{{<port0> 0} | Extension 6\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n0000000e [label="{{} | Camera 1\n | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
n0000000e:port0 -> n00000008:port0 [style=bold]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -486,3 +486,673 @@ v4l2_ioctl_ops.vidioc_prepare_buf
```
## 5. ISP源码分析
参考源码https://gitee.com/juping_zheng1/v85x-mediactrl
![image-20231222083432055](pic/58_isp_src2.png)
上图里,只有红框里的函数被调用。
![image-20231222083608208](pic/59_isp_src3.png)
![image-20231222083124886](pic/57_isp_src1.png)
## 6. media分析
参考资料:
* linux v4l2架构分析——media_device的注册过程分析 https://blog.csdn.net/ismycsdn/article/details/129202760
* https://www.linuxtv.org/downloads/v4l-dvb-apis-new/pdf/media.pdf
## 7. subdev
使用https://blog.csdn.net/qq_34341546/article/details/131129174
subdev分析比较全面的文章https://blog.csdn.net/u011037593/article/details/115415136
linux media子系统分析之media控制器设备https://zhuanlan.zhihu.com/p/638020445
内核文档Linux-4.9.88\Documentation\zh_CN\video4linux\v4l2-framework.txt
Linux V4L2子系统分析: https://blog.csdn.net/u011037593/article/details/115415136
主设备可通过v4l2_subdev_call的宏调用从设备提供的方法
代码分析参考:
```shell
https://www.cnblogs.com/rongpmcu/p/7662738.html
https://www.cnblogs.com/rongpmcu/p/7662741.html
https://www.cnblogs.com/rongpmcu/p/7662745.html
```
我的分析:
```c
platform_device: Linux-4.9.88\arch\arm\mach-imx\mach-mx31_3ds.c
platform_driver: Linux-4.9.88\drivers\media\platform\soc_camera\soc_camera.c
sensor driver: Linux-4.9.88\drivers\media\i2c\soc_camera\ov2640.c
```
## 8. media
linux media子系统分析之media控制器设备https://zhuanlan.zhihu.com/p/638020445
https://www.kernel.org/doc/html/latest/driver-api/media/mc-core.html
https://www.kernel.org/doc/html/latest/userspace-api/media/index.html
【linux kernel】linux media子系统分析之media控制器设备: https://blog.csdn.net/iriczhao/article/details/131276897
https://docs.kernel.org/driver-api/media/mc-core.html#c.media_device
Linux MIPI 摄像头驱动框架编写RN6752解码芯片: https://www.cnblogs.com/jzcn/p/17823309.html
Linux Media 子系统链路分析: https://www.cnblogs.com/jzcn/p/17822224.html
media-ctl调试生成拓扑和数据流图: https://blog.csdn.net/qq_34341546/article/details/129119359
MIPI扫盲——D-PHY介绍: https://zhuanlan.zhihu.com/p/638769112?utm_id=0
[Linux 基础] -- Linux media 子系统: https://blog.csdn.net/u014674293/article/details/111318314
Camera | 3.瑞芯微平台MIPI摄像头常用调试命令 https://zhuanlan.zhihu.com/p/604324755?utm_id=0
生成文档:
```shell
sudo apt-get install python3-sphinx
cd linux_kernel
make htmldocs
makd pdfdocs
生成的文档放在 Documentation/output 文件夹中
```
### 8.1 基本概念
参考文档《doc_and_source_for_drivers\IMX6ULL\doc_pic\13_V4L2\media.pdf》之《2.5 Media Controller devices 》
```shell
struct media_device media_device_register media_device_unregister
struct media_entity, The structure is usually embedded into a higher-level structure, such as
v4l2_subdev or video_device instances. Drivers initialize entity pads by calling media_entity_pads_init(). Drivers register entities with a media device by calling media_device_register_entity() and unregistered by calling media_device_unregister_entity().
Interfaces似乎没什么用给 media_create_intf_link 使用?
以后要分析media_ctl打印link的全过程Interfaces是终点吗
Interfaces are represented by a struct media_interface instance, defined in include/media/
media-entity.h. Currently, only one type of interface is defined: a device node. Such interfaces are represented by a struct media_intf_devnode.
Drivers initialize and create device node interfaces by calling media_devnode_create() and
remove them by calling: media_devnode_remove().
Pads are represented by a struct media_pad instance, defined in include/media/
media-entity.h. Each entity stores its pads in a pads array managed by the entity driver.
Drivers usually embed the array in a driver-specific structure.
Pads are identified by their entity and their 0-based index in the pads array.
Both information are stored in the struct media_pad, making the struct media_pad pointer
the canonical way to store and pass link references.
Pads have flags that describe the pad capabilities and state.
MEDIA_PAD_FL_SINK indicates that the pad supports sinking data. MEDIA_PAD_FL_SOURCE indicates that the pad supports sourcing data.
Links are represented by a struct media_link instance, defined in include/media/
media-entity.h. There are two types of links:
1. pad to pad links
Drivers create pad to pad links by calling: media_create_pad_link() and remove with
media_entity_remove_links().
2. interface to entity links
Drivers create interface to entity links by calling: media_create_intf_link() and remove with
media_remove_intf_links().
video_register_device >
__video_register_device >
video_register_media_controller >
media_create_intf_link
```
### 8.2 Graph traversal
获得所有的entity
```shell
media_device_for_each_entity(entity, mdev)
```
遍历:
```shell
Drivers might also need to iterate over all entities in a graph that can be reached only through
enabled links starting at a given entity. The media framework provides a depth-first graph
traversal API for that purpose.
Drivers initiate a graph traversal by calling media_graph_walk_start()
The graph structure, provided by the caller, is initialized to start graph traversal at the given entity.
Drivers can then retrieve the next entity by calling media_graph_walk_next()
When the graph traversal is complete the function will return NULL.
Helper functions can be used to find a link between two given pads, or a pad
connected to another pad through an enabled link media_entity_find_link() and
media_entity_remote_pad().
linux 4.9
void media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity)
linux 5.4
void media_graph_walk_start(struct media_graph *graph,
struct media_entity *entity)
Link properties can be modified at runtime by calling media_entity_setup_link()
When starting streaming, drivers must notify all entities in the pipeline to prevent link states
from being modified during streaming by calling media_pipeline_start().
Link configuration will fail with -EBUSY by default if either end of the link is a streaming entity.Links that can be modified while streaming must be marked with the MEDIA_LNK_FL_DYNAMIC
flag.
media_device_init initializes the media device prior to its registration. The media device initialization
and registration is split in two functions to avoid race conditions and make the media device
available to user-space before the media graph has been completed.
So drivers need to first initialize the media device, register any entity within the media device, create pad to pad links and then finally register the media device by calling
media_device_register() as a final step.
```
## 9. v853上编译v4l2-utils
http://linuxtv.org/downloads/v4l-utils
```shell
#export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/bin
#export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
sudo apt install autopoint
cd ~/v4l-utils-1.20.0
#./configure --host=arm-openwrt-linux --prefix=$PWD/tmp --with-udevdir=$PWD/tmp
./configure --host=arm-openwrt-linux-gnueabi --prefix=$PWD/tmp --with-udevdir=$PWD/tmp LDFLAGS="-static"
rm media-ctl
make V=1 # 有错也没关系
# 使用静态链接制作media-ctl
cd utils/media-ctl/
arm-openwrt-linux-gcc -g -O2 -o media-ctl media-ctl.o options.o ./.libs/libmediactl.a ./.libs/libv4l2subdev.a -static
make install
sudo apt install adb
adb push media-ctl /root
# 先运行camerademo
camerademo
# 否则下面的命令会崩溃
media-ctl -p -d /dev/media0
media-ctl -d /dev/media0 --print-dot > media0.dot
```
Ubuntu上
```shell
sudo apt install xdot
dot -Tpng media0.dot -o media0.png
```
Ubuntu上测试USB摄像头
```shell
cd ~/v4l-utils-1.20.0
./configure
make
sudo make install
su root
media-ctl -p -d /dev/media0
media-ctl -d /dev/media0 --print-dot > uvc_media0.dot
dot -Tpng uvc_media0.dot -o uvc_media0.png
```
## 10. v853驱动分析
vin.c里注册了一系列的platform_driver
![image-20240220175520169](pic/v853/06_vin_init.png)
这些驱动对应下图各个entity
![](pic/v853/07_media0_entity.png)
### 10.1 sensor
drivers\media\platform\sunxi-vin\modules\sensor\sensor_helper.c
![image-20240220105847686](pic/v853/02_dts_gc2053_platform_drv.png)
vin.c分析
```shell
vin_probe
vin_md_register_entities(vind, dev->of_node);
__vin_register_module(vind, module, j)
__vin_subdev_register
sd = v4l2_i2c_new_subdev(v4l2_dev, adapter, name, addr, NULL);
v4l2_i2c_new_subdev_board
client = i2c_new_device(adapter, info); // 导致gc2053_mipi.c的probe被调用
// i2c_new_device里调用sensor_probe,生成了subdev
sd = i2c_get_clientdata(client);
v4l2_device_register_subdev(v4l2_dev, sd)
// gc2053_mipi.c的probe被调用
sensor_probe
info = kzalloc(sizeof(struct sensor_info), GFP_KERNEL);
sd = &info->sd;
cci_dev_probe_helper(sd, client, &sensor_ops, &cci_drv[i]);
v4l2_i2c_subdev_init(sd, client, sensor_ops);
i2c_set_clientdata(client, sd);
cci_media_entity_init_helper(sd, cci_drv);
si->sensor_pads[SENSOR_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
return media_entity_pads_init(&sd->entity, SENSOR_PAD_NUM, si->sensor_pads);
```
![image-20240220170055716](pic/v853/03_sensor0_dts.png)
### 10.2 sunxi_mipi
drivers/media/platform/sunxi-vin/vin-mipi/sunxi_mipi.c
```c
static struct platform_driver mipi_platform_driver = {
.probe = mipi_probe,
.remove = mipi_remove,
.driver = {
.name = MIPI_MODULE_NAME,
.owner = THIS_MODULE,
.of_match_table = sunxi_mipi_match,
}
};
```
设备树:
![image-20240220173009424](pic/v853/04_sunxi_mipi_dts.png)
```shell
mipi_probe
ret = __mipi_init_subdev(mipi);
v4l2_subdev_init(sd, &sunxi_mipi_subdev_ops);
/*sd->entity->ops = &isp_media_ops;*/
mipi->mipi_pads[MIPI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
mipi->mipi_pads[MIPI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_IO_V4L;
ret = media_entity_pads_init(&sd->entity, MIPI_PAD_NUM, mipi->mipi_pads);
```
上面并没有注册mipi的subdev在vin.c里
```c
for (i = 0; i < VIN_MAX_MIPI; i++) {
/*Register MIPI subdev */
vind->mipi[i].id = i;
vind->mipi[i].sd = sunxi_mipi_get_subdev(i);
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
vind->mipi[i].sd);
if (ret < 0)
vin_log(VIN_LOG_MD, "mipi%d register fail!\n", i);
}
```
### 10.3 sunxi_csi
drivers\media\platform\sunxi-vin\vin-csi\sunxi_csi.c
![image-20240220174907618](pic/v853/05_sunxi_csi_dts.png)
```shell
csi_probe
__csi_init_subdev(csi);
v4l2_subdev_init(sd, &sunxi_csi_subdev_ops);
csi->csi_pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
csi->csi_pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_IO_V4L;
ret = media_entity_pads_init(&sd->entity, CSI_PAD_NUM, csi->csi_pads);
glb_parser[csi->id] = csi;
```
上面并没有注册mipi的subdev在vin.c里
```c
for (i = 0; i < VIN_MAX_CSI; i++) {
/*Register CSI subdev */
vind->csi[i].id = i;
vind->csi[i].sd = sunxi_csi_get_subdev(i);
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
vind->csi[i].sd);
if (ret < 0)
vin_log(VIN_LOG_MD, "csi%d register fail!\n", i);
}
```
### 10.4 tdm
drivers\media\platform\sunxi-vin\vin-tdm\vin_tdm.c
![image-20240220175850734](pic/v853/08_tdm_dts.png)
```shell
tdm_probe
ret = __tdm_init_subdev(&tdm->tdm_rx[i]);
v4l2_subdev_init(sd, &sunxi_tdm_subdev_ops);
sd->grp_id = VIN_GRP_ID_TDM_RX;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "sunxi_tdm_rx.%u", tdm_rx->id);
v4l2_set_subdevdata(sd, tdm_rx);
tdm_rx->tdm_pads[TDM_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
tdm_rx->tdm_pads[TDM_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_IO_V4L;
ret = media_entity_pads_init(&sd->entity, TDM_PAD_NUM, tdm_rx->tdm_pads);
glb_tdm[tdm->id] = tdm;
```
上面并没有注册mipi的subdev在vin.c里
```c
for (i = 0; i < VIN_MAX_TDM; i++) {
/*Register TDM subdev */
vind->tdm[i].id = i;
for (j = 0; j < TDM_RX_NUM; j++) {
vind->tdm[i].tdm_rx[j].sd = sunxi_tdm_get_subdev(i, j);
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
vind->tdm[i].tdm_rx[j].sd);
if (ret < 0)
vin_log(VIN_LOG_MD, "the tdx%d of tdx_rx%d register fail!\n", i, j);
}
}
```
### 10.5 sunxi_isp
drivers/media/platform/sunxi-vin/vin-isp/sunxi_isp.c
![image-20240220180656550](pic/v853/09_isp_dts.png)
```shell
isp_probe
vin_isp_h3a_init
v4l2_subdev_init(&stat->sd, &h3a_subdev_ops);
snprintf(stat->sd.name, V4L2_SUBDEV_NAME_SIZE, "sunxi_h3a.%u", isp->id);
stat->sd.grp_id = VIN_GRP_ID_STAT;
stat->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_set_subdevdata(&stat->sd, stat);
stat->pad.flags = MEDIA_PAD_FL_SINK;
stat->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_STATISTICS;
return media_entity_pads_init(&stat->sd.entity, 1, &stat->pad);
glb_isp[isp->id] = isp;
```
上面并没有注册mipi的subdev在vin.c里
```c
for (i = 0; i < VIN_MAX_ISP; i++) {
/*Register ISP subdev */
vind->isp[i].id = i;
vind->isp[i].sd = sunxi_isp_get_subdev(i);
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
vind->isp[i].sd);
if (ret < 0)
vin_log(VIN_LOG_MD, "isp%d register fail!\n", i);
#if !defined CONFIG_ISP_SERVER_MELIS
/*Register STATISTIC BUF subdev */
vind->stat[i].id = i;
vind->stat[i].sd = sunxi_stat_get_subdev(i);
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
vind->stat[i].sd);
if (ret < 0)
vin_log(VIN_LOG_MD, "stat%d register fail!\n", i);
#endif
}
```
### 10.6 sunxi_scaler
drivers\media\platform\sunxi-vin\vin-vipp\sunxi_scaler.c
```c
static const struct of_device_id sunxi_scaler_match[] = {
{.compatible = "allwinner,sunxi-scaler",},
{},
};
static struct platform_driver scaler_platform_driver = {
.probe = scaler_probe,
.remove = scaler_remove,
.driver = {
.name = SCALER_MODULE_NAME,
.owner = THIS_MODULE,
.of_match_table = sunxi_scaler_match,
},
};
```
![image-20240220183652665](pic/v853/11_sunxi_scaler_dts.png)
```shell
scaler_probe
__scaler_init_subdev(scaler);
v4l2_subdev_init(sd, &sunxi_scaler_subdev_ops);
sd->grp_id = VIN_GRP_ID_SCALER;
sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "sunxi_scaler.%u", scaler->id);
v4l2_set_subdevdata(sd, scaler);
/*sd->entity->ops = &isp_media_ops;*/
scaler->scaler_pads[SCALER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
scaler->scaler_pads[SCALER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
ret = media_entity_pads_init(&sd->entity, SCALER_PAD_NUM,
scaler->scaler_pads);
platform_set_drvdata(pdev, scaler);
glb_vipp[scaler->id] = scaler;
```
上面并没有注册mipi的subdev在vin.c里
```c
for (i = 0; i < VIN_MAX_SCALER; i++) {
/*Register SCALER subdev */
vind->scaler[i].id = i;
vind->scaler[i].sd = sunxi_scaler_get_subdev(i);
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
vind->scaler[i].sd);
if (ret < 0)
vin_log(VIN_LOG_MD, "scaler%d register fail!\n", i);
}
```
### 10.7 vin_cap
drivers\media\platform\sunxi-vin\vin-video\vin_core.c
```c
static const struct of_device_id sunxi_vin_core_match[] = {
{.compatible = "allwinner,sunxi-vin-core",},
{},
};
static struct platform_driver vin_core_driver = {
.probe = vin_core_probe,
.remove = vin_core_remove,
.shutdown = vin_core_shutdown,
.driver = {
.name = VIN_CORE_NAME,
.owner = THIS_MODULE,
.of_match_table = sunxi_vin_core_match,
.pm = &vin_core_runtime_pm_ops,
},
};
```
![image-20240220185312243](pic/v853/12_vin_cap_dts.png)
```shell
vin_core_probe
ret = vin_initialize_capture_subdev(vinc);
struct v4l2_subdev *sd = &vinc->vid_cap.subdev;
v4l2_subdev_init(sd, &vin_subdev_ops);
sd->grp_id = VIN_GRP_ID_CAPTURE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "vin_cap.%d", vinc->id);
vinc->vid_cap.sd_pads[VIN_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
vinc->vid_cap.sd_pads[VIN_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_IO_V4L;
ret = media_entity_pads_init(&sd->entity, VIN_SD_PADS_NUM,
vinc->vid_cap.sd_pads);
if (ret)
return ret;
sd->entity.ops = &vin_sd_media_ops;
sd->internal_ops = &vin_capture_sd_internal_ops;
v4l2_set_subdevdata(sd, vinc);
```
上面并没有注册mipi的subdev在vin.c里
```c
vin_md_register_core_entity
sd = &vinc->vid_cap.subdev;
v4l2_set_subdev_hostdata(sd, (void *)&vin_pipe_ops);
ret = v4l2_device_register_subdev(&vind->v4l2_dev, sd);
```
### 10.8 vin_video0
drivers/media/platform/sunxi-vin/vin-video/vin_video.c
![image-20240220185958332](pic/v853/13_vin_cap_internal_ops.png)
```shell
vin_capture_subdev_registered
if (vin_init_video(sd->v4l2_dev, &vinc->vid_cap))
snprintf(cap->vdev.name, sizeof(cap->vdev.name),
"vin_video%d", cap->vinc->id);
cap->vdev.fops = &vin_fops;
cap->vdev.ioctl_ops = &vin_ioctl_ops;
cap->vdev.release = video_device_release_empty;
cap->vdev.ctrl_handler = &cap->ctrl_handler;
cap->vdev.v4l2_dev = v4l2_dev;
cap->vdev.queue = &cap->vb_vidq;
cap->vdev.lock = &cap->lock;
cap->vdev.flags = V4L2_FL_USES_V4L2_FH;
ret = video_register_device(&cap->vdev, VFL_TYPE_GRABBER, cap->vinc->id);
cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&cap->vdev.entity, 1, &cap->vd_pad);
```
### 10.100 疑问
subdev的v4l2_subdev_ops函数何时被调用
sd->internal_ops何时被调用
## 11. 调用过程分析
### 11.1 link

Binary file not shown.