Drivers, device tree, userspace, flash.
The demonstration tool (flash, live page, calibration) is in English.
| Place | What sits there |
|---|---|
| This PC | USB driver, flash, overlay push, ADB forwards, diagnostics, session writer |
Board /userdata | Stereo page, FSYNC/EFSYNC, IMU HUD, calibration UI, Wi-Fi STA, IQ JSON, native matcher, boot scripts |
| Board kernel | Device tree, CSI, I2C/SPI, SDIO Wi-Fi, ADB gadget: device-tree/rv1126b-camevision-ego.dts |
Sources: tools/. Overlay: restore/release-0.2-20260902/overlay/ → /userdata/. Links: /src/….
The phone app is CameVision-App 1.2.11. English is the app language. 中文 is selectable on first start and in Setup.
First start chooses USB recording and viewing, or Bluetooth control only. Setup can switch that later. USB mode shows the camera and Setup. Bluetooth mode shows record, card, and Setup.
On USB, the computer keeps configuration 1. Ego stays ADB, 2207:0006. The phone selects configuration 2 and records HEVC 1920×1200 at 50 fps, both eyes and both IMUs. The folder is My Recordings/<session>/episode and synced, with cam_left.mp4 and cam_right.mp4. Live view pauses while a recording is running. microSD is a buffer only when that switch is on.
On Bluetooth, the phone starts and stops a recording on the card, then copies or uploads it. That card layout stays camevision/sessions/.
| Item | Value |
|---|---|
| Baseline | 75.0 mm · CAM0 left · CAM1 right. Depth error uses this baseline. |
| Sync | RV1126B GPIO FSYNC + EFSYNC, direct SoC control. Maximum the RV1126B can handle. |
| Frame rate | All shop sensors 60 fps. Ego stereo maximum 60 fps. Demo trigger 12.5 fps. Procedure. |
| AE / AWB | rkaiq 3A on both ISPs. Same exposure and AWB on both eyes. Slave HDR off. |
| IMU | LSM6DSVQTR ×2 · 480 Hz |
| Timestamp | CLOCK_MONOTONIC_ns on frames and IMU. CLOCK_REALTIME + ISO on IMU JSON. RV-3028 sets the system clock. Record: cam_left.timestamps.jsonl · cam_right.timestamps.jsonl |
| Exposure · 50 / 60 Hz | 50 Hz: exposure N × 10 ms. 60 Hz: exposure N × 8.333 ms. IQ default 50 Hz anti-flicker. |
Kernel in the boot FIT is 6.1.141-rt52. In-tree nodes come from the DTB. Out-of-tree modules sit in the overlay and are insmod’d from the boot scripts.
| Block | Driver / compatible | Where it lives | Live nodes |
|---|---|---|---|
| MIPI sensor | smartsens,sc233hgs |
In the boot FIT (kernel + DTB) | I2C 3-0030, 6-0030 · chip id 0xcb61 |
| MIPI CSI-2 D-PHY | csi2_dphy0 · csi2_dphy1 |
DTB, 4 lanes each | PHY under CSI RX0 / RX1 |
| MIPI CSI-2 host | mipi0_csi2 · mipi1_csi2 |
DTB | Bridge into CIF |
| CIF | rkcif · rkcif_mipi_lvds · rkcif_mipi_lvds1 |
DTB + Rockchip CIF | Raw path into ISP |
| ISP / VPSS | rkisp · rkisp_vir0/1 · rkvpss_vir0/1 · rkdvbm |
DTB + Rockchip ISP | /dev/video24 CAM0 · /dev/video32 CAM1 |
| 3A / IQ | rkaiq_3A_server |
/oem/usr/bin/ + IQ JSON in overlay |
AE / AWB on both ISPs. Same exposure and AWB on both eyes. Slave HDR off. |
| IMU | st,lsm6dsv (IIO) |
In the boot FIT · SPI0 / SPI1 | /sys/bus/iio/devices/iio:device1…4 (gyro/accel ×2). Procedure: 480 Hz. Precision: Hardware |
| Wi-Fi / BLE | SDIO 1FFE:6621 · skw_sdio_lite · swt6621s_wifi · skwbt |
Overlay swt6621-rt52/ + FW swt6621_fw/ |
mmc2 · wlan0 · hci0 |
| Wi-Fi stack | cfg80211 · mac80211 · AES / CCM helpers |
Loaded by camevision-wifi.sh |
nl80211 + wpa_camevision.conf. Procedure. |
| USB gadget | DWC3 dr_mode=peripheral · configfs gadget |
DTB + rootfs | ADB 2207:0006 · UDC 21500000.usb |
| eMMC / SD / SDIO host | emmc · sdmmc0 · sdmmc1 |
DTB | mmc0 eMMC · mmc1 µSD · mmc2 Wi-Fi |
| RTC / PMIC | rv3028 I2C2 0x52 · rk801 I2C0 0x27 |
DTB | /dev/rtc0 · PMIC regulators |
| NPU / GPU / MPP | rknpu · mali · mpp | Kernel + kmpp-rt52.ko in overlay |
/dev/rknpu · /dev/mali* · /dev/mpp_service |
Camera pipe in the DTB: sensor → D-PHY → CSI-2 → CIF → ISP → VPSS. Wi-Fi modules are built for this rt52 kernel; they load from /userdata/swt6621-rt52. Firmware blobs are /userdata/swt6621_fw (Seekwave / SWT6621S NV).
Board source: device-tree/rv1126b-camevision-ego.dts. Includes rv1126b.dtsi. Model string CameVision Ego, compatible camemake,camevision-ego.
Boot FIT carries the compiled DTB. Source: device-tree/rv1126b-camevision-ego.dts. Rebuild and write the boot partition after a DTS change.
| Node | State |
|---|---|
i2c3/sc233hgs@30 · i2c-gpio-cam1/sc233hgs@30 | Both cameras, 27 MHz XVCLK, 4-lane |
i2c4 | Disabled: CAM1 SCL/SDA are swapped, bit-bang instead |
csi2_dphy0/1 · mipi0/1_csi2 · rkcif* · rkisp* · rkvpss* | Okay: dual pipe |
spi0/imu@0 · spi1/imu@0 | st,lsm6dsv, SPI mode 3, 1 MHz, st,odr-triggered |
sdmmc1 + sdio-pwrseq · wireless-wlan · UART2 BT | VS6621 |
emmc 8-bit HS200 · sdmmc0 4-bit | Okay |
usb@21500000 | dr_mode = peripheral (ADB) |
usb_host_ehci · ohci · gmac · dsi · i2c1 · i2c5 | Disabled |
uart0 | Console 1.5 Mbaud |
Two LSM6DSVQTR parts. Accel and gyro rate: sampling_frequency.
| Camera | Live page | Bus | Gyro | Accel |
|---|---|---|---|---|
| CAM0 | Right | SPI0 | iio:device1 | iio:device2 |
| CAM1 | Left | SPI1 | iio:device3 | iio:device4 |
Directory: /sys/bus/iio/devices/iio:deviceN/. SPI mode 3, 1 MHz. Data-ready is INT1. Device tree: st,odr-triggered.
Step 2 prints sampling_frequency_available for the running driver. Step 4, ODR, and both write_text calls take one number from that list.
| Hz | |
|---|---|
| Accel | 1.875 · 7.5 · 15 · 30 · 60 · 120 · 240 · 480 · 960 · 1920 · 3840 · 7680 |
| Gyro | 7.5 · 15 · 30 · 60 · 120 · 240 · 480 · 960 · 1920 · 3840 · 7680 |
adb shell
for d in 1 2 3 4; do echo -n "device$d " cat /sys/bus/iio/devices/iio:device$d/name echo -n " available " cat /sys/bus/iio/devices/iio:device$d/sampling_frequency_available echo done
Each name is the LSM6DSV driver.
sampling_frequency rejects a write while buffer/enable is 1.
for d in 1 2 3 4; do echo 0 > /sys/bus/iio/devices/iio:device$d/buffer/enable done
for d in 1 2 3 4; do echo 480 > /sys/bus/iio/devices/iio:device$d/sampling_frequency done
for d in 1 2 3 4; do echo -n "device$d " cat /sys/bus/iio/devices/iio:device$d/sampling_frequency done
Each line reads 480. Port 8083 JSON: odr_hz is the requested rate. read_hz is the sysfs poll rate of both IMUs added together.
The four sampling_frequency files are the chip rate. The live page and a recording write those same four files.
| Place | When the chip is written | Where the rate is shown |
|---|---|---|
| Live page | tools/ego_imu_hud.py, on the board /userdata/ego_imu_hud.py. camevision-stereo.sh starts it at boot when that process is down. ODR = "480" is written once for each accel and each gyro at process start. buffer/enable is set to 0 first. |
Port 8083, and live page /imu. odr_hz is the running process value ODR. read_hz is the HUD poll rate, both IMUs added together. |
| Phone live IMU | The phone link reads port 8083. The chip write is the live-page row. | tools/ego_phone_link.py, on the board /userdata/ego_phone_link.py, sends odr_hz, imu0, and imu1 from that JSON. |
| Webpage recording | POST /record/start calls start() in tools/ego_record.py, on the board /userdata/ego_record.py. _imu_loop writes 480 to the four files, then reads the raw registers. |
IMU lines in the take. Each line is stamped with CLOCK_MONOTONIC at the read. The loop waits 1 ms between reads. |
| Phone recording | POST /record/phone/start and POST /record/phone/start-sd call the same start(). |
The same IMU lines in the take. |
| Local recording | POST /record/local/start calls the same start(). |
The same IMU lines in the take. |
| Shell | Step 4 writes the four files at that moment. | Step 5, cat sampling_frequency. |
Live page: edit ODR in /userdata/ego_imu_hud.py. The new value is written when that process starts. Boot starts it from /userdata/camevision-stereo.sh when it is down. Until that start, port 8083 and /imu keep reporting the ODR of the running process. The phone live IMU follows that JSON.
Recording: edit the two write_text calls in _imu_loop in /userdata/ego_record.py. The new value is written at the next /record/start, /record/phone/start, /record/phone/start-sd, or /record/local/start.
Shell: step 4 writes the chip. The running HUD keeps its odr_hz. The next HUD start and the next recording start write their own values into the same four files.
ego_record.py reads in_accel_x_raw, in_accel_y_raw, in_accel_z_raw, in_anglvel_x_raw, in_anglvel_y_raw, and in_anglvel_z_raw about every 1 ms. The timestamp is CLOCK_MONOTONIC at the read. The stored numbers are the register values at that read. The same sample can be stored twice. A sample that arrives between reads can be skipped.
One sample per output period is the sensor FIFO, or the IIO buffer clocked by DRDY on INT1. The HUD and the recorder read oneshot sysfs.
The live pictures, the phone pictures, the trigger, and a recording each have their own number.
| Place | File on the board | Number in this package | Where it shows |
|---|---|---|---|
| Live page pictures | ego_stereo.py · /userdata/ego_stereo.py · PREVIEW_FPS |
15 | /stat field color_fps. JPEG tiles on the live page. COLOR_PERIOD = 1/PREVIEW_FPS. |
| Phone live pictures | tools/ego_phone_link.py · /userdata/ego_phone_link.py · PREVIEW_PERIOD |
1/15 s | Interval between phone JPEG sends. |
| Idle trigger | /userdata/ego_stereo.py · trig_fps |
24 | GPIO FSYNC/EFSYNC period from ego_stereo.py start, while no take is running. set_fps in tools/ego_cam_sync.py. |
| Recording | tools/ego_record.py · /userdata/ego_record.py · LOCAL_FPS |
50 | HEVC 1920×1200, both eyes. start() sets FPS, TRIG_FPS, and GOP from LOCAL_FPS, then _raise_rate. |
| Sensor timing | /userdata/ego_cam_sync.py · VTS_30 · VTS_60 |
3200 at 30 · 1600 at 60 | apply_vts(60) at record start. apply_vts(30) at record stop when the saved trigger is below 55. set_fps sets the GPIO period to 1/fps and calls apply_vts when fps is 55 or above. |
| Grab | /userdata/ego_stereo.py · CAP_FPS |
30, then 24, then 30 | v4l2-ctl --set-parm. Frames that arrive follow the trigger. |
Edit PREVIEW_FPS in /userdata/ego_stereo.py. The next start of that file reads the new number. /userdata/camevision-stereo.sh starts it at boot when it is down. The running process keeps the PREVIEW_FPS from its start. /stat color_fps is that loop.
Edit PREVIEW_PERIOD in /userdata/ego_phone_link.py. The next start of that file reads the new interval. The running phone link keeps the interval from its start.
Edit trig_fps in /userdata/ego_stereo.py. The next start of that file calls set_fps with that number. The GPIO period is 1/trig_fps while no take is running.
Edit LOCAL_FPS in /userdata/ego_record.py. The next POST /record/start, /record/phone/start, /record/phone/start-sd, or /record/local/start sets FPS, TRIG_FPS, and GOP from LOCAL_FPS, calls apply_vts(60), then set_fps(LOCAL_FPS). Stop puts the trigger back to the value saved at the start of that take, and calls apply_vts(30) when that saved value is below 55.
apply_vts argument | VTS | Vertical blank |
|---|---|---|
| Below 55 | 3200 | 2000 |
| 55 and above | 1600 | 400 |
A recording in this package uses trigger 50 with VTS 1600. The idle trigger is 24 with the timing left by the previous apply_vts.
The camera joins the network in /userdata/wpa_camevision.conf. Source file: tools/wpa_camevision.conf. camevision-wifi.sh reads that board file as CONF.
network={
ssid="network name"
psk="passphrase"
key_mgmt=WPA-PSK
proto=RSN
pairwise=CCMP
group=CCMP
priority=10
scan_ssid=1
}
| Field | Role |
|---|---|
ssid | Network name. |
psk | Passphrase. |
key_mgmt | WPA-PSK in this file. |
proto | RSN. |
pairwise · group | CCMP. |
priority | 10. |
scan_ssid | 1. |
adb shell vi /userdata/wpa_camevision.conf
Change ssid and psk. Keep the quotes. The file stays on /userdata across reboot.
sh /userdata/camevision-wifi.sh
camevision-wifi.sh starts wpa_supplicant on wlan0 with that file, driver nl80211. Boot runs the same script from /userdata/camevision-stereo.sh when wlan0 has no IPv4 address and the script is down.
wpa_cli -i wlan0 status ip -4 addr show wlan0
wpa_state=COMPLETED is the join. ssid in that status is the name from the file. ip -4 addr shows the address after DHCP. Log: /userdata/wifi.log and /userdata/wpa.log.
Maskrom. Empty board or a board that already has images.
| LBA | Image | In this package |
|---|---|---|
| loader (db once) | rv1126b_spl_loader_k4a8g.bin | restore/known-good-20260819-camera-adb/ or restore/updates/current/ |
0x0 | env.img | same |
0x40 | idblock.img | same |
0x440 | uboot.img | same |
0x2440 | camevision_boot_ego.img | kernel + DTB FIT |
0x7C40 | userdata.img | then overlay on top |
0x207C40 | oem_noko.img | IQ binaries, rkaiq, oem libs |
0x607C40 | rootfs_bootstable.img | root filesystem |
restore/updates/current/, or a zip via GitHub update / Package file.python tools/cv_ego_flash.py --prebuilt
tools/cv_ego_flash.py → tools/cv_ego_wifi_full_flash.py. upgrade_tool db the 1 GB DDR loader once, then wl each LBA, rd, overlay over ADB.
host/upgrade_tool.exe db restore/known-good-20260819-camera-adb/rv1126b_spl_loader_k4a8g.bin host/upgrade_tool.exe wl 0x0 env.img host/upgrade_tool.exe wl 0x40 idblock.img host/upgrade_tool.exe wl 0x440 uboot.img host/upgrade_tool.exe wl 0x2440 camevision_boot_ego.img host/upgrade_tool.exe wl 0x7C40 userdata.img host/upgrade_tool.exe wl 0x207C40 oem_noko.img host/upgrade_tool.exe wl 0x607C40 rootfs_bootstable.img host/upgrade_tool.exe rd python tools/cv_ego_overlay_deploy.py
python tools/cv_ego_flash.py --rebuild runs the DTB patch and tools/cv_pack_release02.py, then the same write. Boot image: camevision_boot_ego.img (FIT, 11 MiB / 0x5800 sectors).
Leave the partitions. Files under tools/, then python tools/cv_ego_overlay_deploy.py.
S11hwclock: RV-3028 → system clock.S99ego-stereo: waits, then starts the stereo script.tools/camevision-stereo.sh: kmpp, Wi-Fi, rkaiq 3A, IMU HUD, then ego_stereo.py.tools/cv_ego_page.py: adb forward 8081 and 8083, opens the browser.| Block | File | On the board | Role |
|---|---|---|---|
| Live stereo | tools/ego_stereo.py |
/userdata/ego_stereo.py · port 8081 |
Reads /dev/video24 (CAM0) and /dev/video32 (CAM1). JPEG live page, depth overlay, calibration routes, record control. Loads libego_stereo.so. |
| Matcher | tools/stereo_native.c |
/userdata/libego_stereo.so |
C block matcher and NV12 overlay. Built as the shared library the live page loads. |
| FSYNC / EFSYNC | tools/ego_cam_sync.py |
imported by the live page | GPIO4_A1/A0 + GPIO6_C2/C3, both eyes on one tick. RV1126B direct control, maximum the SoC can handle. Sensor regs 0x3222 / 0x3282. Sensors 60 fps, Ego max 60 fps, demo trigger 12.5 fps. |
| IMU HUD | tools/ego_imu_hud.py |
/userdata/ego_imu_hud.py · port 8083 |
JSON of IMU0 (SPI0, CAM0) and IMU1 (SPI1, CAM1). The live page proxies /imu to this port. |
| Calibration UI | tools/ego_calib.html |
/userdata/ego_calib.html · /cal |
Browser UI. Writes /userdata/ego_calib.json through the live page (/cal/start, /cal/sample, /cal/stop). |
| Focus / MTF | tools/ego_mtf.py |
imported by the live page | ISO 12233 slanted-edge MTF50 on the 1920×1200 Y plane. /focus/start, /focus/stop. |
| Record (board) | tools/ego_record.py |
started from the live page | HEVC of the live NV12 to the PC on 8091. /record/start, /record/stat. |
| Wi-Fi STA | tools/camevision-wifi.sh |
/userdata/camevision-wifi.sh |
VS6621 modules + wpa_camevision.conf. Procedure. |
| IQ | overlay/iqfiles/…default.json |
/userdata/iqfiles/ → /oem/usr/share/iqfiles/ |
SC233HGS 3A / ISP tuning consumed by rkaiq_3A_server. |
| Device tree | device-tree/rv1126b-camevision-ego.dts |
FIT / boot image | Cameras, IMU, Wi-Fi, SD, LEDs, USB gadget. Hardware page is the pin table for this file. |
On the board. Open from the host with python tools/cv_ego_page.py.
| Path | Body |
|---|---|
/ | Live HTML: /ov0 and /ov1 MJPEG |
/ov0 · /ov1 | MJPEG with depth overlay |
/raw0 · /raw1 | MJPEG without overlay |
/depth | Depth view |
/snap0 · /snap1 · /snapx | Single JPEG |
/stat | JSON status |
/imu | JSON from :8083 |
/trig | FSYNC / EFSYNC status |
/cal | Calibration UI |
/cal/stat · /cal/start · /cal/sample · /cal/stop · /cal/reset | Calibration session |
/focus/start · /focus/stop | MTF |
/align | Stereo align |
/record/start · /record/stat | Session record |
IMU JSON is forwarded with the stereo page (cv_ego_page.py).
| Block | File | Role |
|---|---|---|
| First-run host | tools/cv_ego_host_setup.py | Bundled Python, USB driver / udev |
| USB driver | tools/cv_ego_driver.py | Rockusb + ADB (Windows), udev 2207 (Linux) |
| Flash | tools/cv_ego_flash.py | Maskrom write of loader…rootfs, then overlay |
| Overlay push | tools/cv_ego_overlay_deploy.py | ADB copy of the overlay into /userdata |
| Open live | tools/cv_ego_page.py | Forwards 8081 / 8083 |
| Autostart | tools/cv_ego_autostart.py | Host watcher: deploy + forwards + page |
| Diagnostics | tools/cv_ego_diag.py | ADB dump: identity, I2C, IMU, video, dmesg |
| Update | tools/cv_ego_update.py | GitHub or zip → restore/updates/current |
| Record (host) | tools/cv_ego_record_host.py | Listens 8091, writes a session folder |
| Paths | tools/cv_ego_paths.py | ADB, upgrade_tool, images, overlay roots |
File under tools/, then:
python tools/cv_ego_overlay_deploy.py
Live process: python3 /userdata/ego_stereo.py.