Camemake
CameVision Ego Camemake stereo · NPU
Buy EGO
This package

Software

Drivers, device tree, userspace, flash.

The demonstration tool (flash, live page, calibration) is in English.

Where it runs

PlaceWhat sits there
This PCUSB driver, flash, overlay push, ADB forwards, diagnostics, session writer
Board /userdataStereo page, FSYNC/EFSYNC, IMU HUD, calibration UI, Wi-Fi STA, IQ JSON, native matcher, boot scripts
Board kernelDevice 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/….

Phone

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/.

Capture

ItemValue
Baseline75.0 mm · CAM0 left · CAM1 right. Depth error uses this baseline.
SyncRV1126B GPIO FSYNC + EFSYNC, direct SoC control. Maximum the RV1126B can handle.
Frame rateAll shop sensors 60 fps. Ego stereo maximum 60 fps. Demo trigger 12.5 fps. Procedure.
AE / AWBrkaiq 3A on both ISPs. Same exposure and AWB on both eyes. Slave HDR off.
IMULSM6DSVQTR ×2 · 480 Hz
TimestampCLOCK_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 Hz50 Hz: exposure N × 10 ms. 60 Hz: exposure N × 8.333 ms. IQ default 50 Hz anti-flicker.

Drivers

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.

BlockDriver / compatibleWhere it livesLive 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).

Device tree

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.

NodeState
i2c3/sc233hgs@30 · i2c-gpio-cam1/sc233hgs@30Both cameras, 27 MHz XVCLK, 4-lane
i2c4Disabled: 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@0st,lsm6dsv, SPI mode 3, 1 MHz, st,odr-triggered
sdmmc1 + sdio-pwrseq · wireless-wlan · UART2 BTVS6621
emmc 8-bit HS200 · sdmmc0 4-bitOkay
usb@21500000dr_mode = peripheral (ADB)
usb_host_ehci · ohci · gmac · dsi · i2c1 · i2c5Disabled
uart0Console 1.5 Mbaud

IMU 480 Hz

Two LSM6DSVQTR parts. Accel and gyro rate: sampling_frequency.

CameraLive pageBusGyroAccel
CAM0RightSPI0iio:device1iio:device2
CAM1LeftSPI1iio:device3iio:device4

Directory: /sys/bus/iio/devices/iio:deviceN/. SPI mode 3, 1 MHz. Data-ready is INT1. Device tree: st,odr-triggered.

Options

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
Accel1.875 · 7.5 · 15 · 30 · 60 · 120 · 240 · 480 · 960 · 1920 · 3840 · 7680
Gyro7.5 · 15 · 30 · 60 · 120 · 240 · 480 · 960 · 1920 · 3840 · 7680

1. Open a shell

adb shell

2. Confirm the four devices

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.

3. Turn the buffer off

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

4. Set 480 Hz

for d in 1 2 3 4; do
  echo 480 > /sys/bus/iio/devices/iio:device$d/sampling_frequency
done

5. Read it back

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.

6. Where 480 is written

The four sampling_frequency files are the chip rate. The live page and a recording write those same four files.

PlaceWhen the chip is writtenWhere 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.

7. Change the number

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.

8. Samples stored in a take

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.

Frame rate

The live pictures, the phone pictures, the trigger, and a recording each have their own number.

PlaceFile on the boardNumber in this packageWhere 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.

1. Change the live pictures

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.

2. Change the phone pictures

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.

3. Change the idle trigger

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.

4. Change the recording rate

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.

5. Sensor timing options

apply_vts argumentVTSVertical blank
Below 5532002000
55 and above1600400

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.

Wi-Fi name and password

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.

1. Fields

network={
	ssid="network name"
	psk="passphrase"
	key_mgmt=WPA-PSK
	proto=RSN
	pairwise=CCMP
	group=CCMP
	priority=10
	scan_ssid=1
}
FieldRole
ssidNetwork name.
pskPassphrase.
key_mgmtWPA-PSK in this file.
protoRSN.
pairwise · groupCCMP.
priority10.
scan_ssid1.

2. Edit the board file

adb shell
vi /userdata/wpa_camevision.conf

Change ssid and psk. Keep the quotes. The file stays on /userdata across reboot.

3. Join again

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.

4. Read it back

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.

Flash

Maskrom. Empty board or a board that already has images.

Partition map

LBAImageIn this package
loader (db once)rv1126b_spl_loader_k4a8g.binrestore/known-good-20260819-camera-adb/ or restore/updates/current/
0x0env.imgsame
0x40idblock.imgsame
0x440uboot.imgsame
0x2440camevision_boot_ego.imgkernel + DTB FIT
0x7C40userdata.imgthen overlay on top
0x207C40oem_noko.imgIQ binaries, rkaiq, oem libs
0x607C40rootfs_bootstable.imgroot filesystem

From the offline tool

  1. Images (same names) in restore/updates/current/, or a zip via GitHub update / Package file.
  2. USB / Maskrom: hold BOOT, tap RESET.
  3. Select the package · Install.
  4. Release BOOT when the write finishes. Overlay is pushed over ADB.

From the command line

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

Rebuild only the boot FIT

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).

Userspace only

Leave the partitions. Files under tools/, then python tools/cv_ego_overlay_deploy.py.

Boot chain

  1. S11hwclock: RV-3028 → system clock.
  2. S99ego-stereo: waits, then starts the stereo script.
  3. tools/camevision-stereo.sh: kmpp, Wi-Fi, rkaiq 3A, IMU HUD, then ego_stereo.py.
  4. PC tools/cv_ego_page.py: adb forward 8081 and 8083, opens the browser.

On the board

BlockFileOn the boardRole
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.

Live page routes

On the board. Open from the host with python tools/cv_ego_page.py.

PathBody
/Live HTML: /ov0 and /ov1 MJPEG
/ov0 · /ov1MJPEG with depth overlay
/raw0 · /raw1MJPEG without overlay
/depthDepth view
/snap0 · /snap1 · /snapxSingle JPEG
/statJSON status
/imuJSON from :8083
/trigFSYNC / EFSYNC status
/calCalibration UI
/cal/stat · /cal/start · /cal/sample · /cal/stop · /cal/resetCalibration session
/focus/start · /focus/stopMTF
/alignStereo align
/record/start · /record/statSession record

IMU JSON is forwarded with the stereo page (cv_ego_page.py).

On this PC

BlockFileRole
First-run hosttools/cv_ego_host_setup.pyBundled Python, USB driver / udev
USB drivertools/cv_ego_driver.pyRockusb + ADB (Windows), udev 2207 (Linux)
Flashtools/cv_ego_flash.pyMaskrom write of loader…rootfs, then overlay
Overlay pushtools/cv_ego_overlay_deploy.pyADB copy of the overlay into /userdata
Open livetools/cv_ego_page.pyForwards 8081 / 8083
Autostarttools/cv_ego_autostart.pyHost watcher: deploy + forwards + page
Diagnosticstools/cv_ego_diag.pyADB dump: identity, I2C, IMU, video, dmesg
Updatetools/cv_ego_update.pyGitHub or zip → restore/updates/current
Record (host)tools/cv_ego_record_host.pyListens 8091, writes a session folder
Pathstools/cv_ego_paths.pyADB, upgrade_tool, images, overlay roots

Swap a block

File under tools/, then:

python tools/cv_ego_overlay_deploy.py

Live process: python3 /userdata/ego_stereo.py.