Page 1 of 1

How to work Pico B with CSI2 Camera module as UVC.

Posted: 2024-01-17 7:24
by Sakurai
Hello LuckFox-forums members.

I am using Luckfox Pico Mini B and CSI camera module and trying to make it work as a UVC when connected to a PC via USB-C.
". /build.sh lunch", the only option is "applicaton(应用场景): IPC", and I can only build the kernel as an IP camera. And it seems that the SDK does not contain the necessary source code. Maybe Rockchip's SDK has a UVC config.

Is there any restriction that UVC cannot be realized in Luckfox pico? If not, is there any possibility to support it in future SDKs?

Thanks in advance.

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2024-01-17 12:13
by Eng38
Hello,

To achieve UVC functionality with your Luckfox Pico Mini B and CSI camera module when connected to a PC via USB-C, you can refer to the tutorial at the following link:

Tutorial link:https://wiki.luckfox.com/Luckfox-Pico/L ... usb-camera

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2024-01-31 23:18
by Sakurai
Thank you for the Link. However, that is the way to connect a USB camera to a LuckFox Pico, which is the opposite of what I want to achieve.
I will wait for the SDK to be updated in the future.
Thanks again.

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2024-02-01 1:19
by Eng38
Thank you for your feedback. If your goal is realized in a future SDK update, we will notify you as soon as it becomes available.

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2024-04-03 3:23
by mrlb
I have the same function requirement, Does the SDK have update?

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2024-04-22 10:37
by ACBIAS
I believe this should work with the SDK as-is. You´d need to configure the kernel to add UVC USB gadget, then configure your usb gadget module
https://www.kernel.org/doc/html//next/u ... t_uvc.html

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2025-03-01 20:02
by Hamstakillah
Not sure about Pico B, but I'm pretty close to making it work on Pico Pro. Here's what I did:

-compiled buildroot with UVC gadget (you can also manually edit /etc/init.d/S50usbgadget.sh to enable UVC mode)
-cross-compiled uvc-gadget from https://github.com/wlhe/uvc-gadget
This version of uvc-gadget recognizes the UVC device and allows streaming of empty content or JPEG image. What does not work is streaming of V4L2 device to UVC device - for some reason ioctl shows 'bad file descriptor' error.
I think that this may work - v4l2-ctl uses same ioctl methods, but it works in v4l2-ctl and not in uvc-gadget.

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2025-06-18 1:52
by Herrick oh
On my RV1106 pico pro board,
I tried /etc/init.d/S50uvcdevice script and /oem/usr/bin/usb_config.sh, but camera device did not appear on host's device manager.
The configfs generated by the script is flawless.
But UDC binding is not interacting with host USB and host is not detecting anything.

I tried UVC gadget on other SoCs, but did not see this issue.
If anyone solved this issue, please share how.

Re: How to work Pico B with CSI2 Camera module as UVC.

Posted: 2026-06-07 14:39
by Hamstakillah

I've seen that there were some advancements to make this work under official Luckfox repository. After numerous attempts to make this work, I gave up and put on an AI agent to figure out how to make a working configuration. Here is what it came up with:

What you need

- Luckfox Pico Pro Max (RV1106) with a compatible camera module (e.g. SC3336)
- USB-C cable connected to your PC
- The Luckfox Pico SDK (either via Docker or native install)
- SocToolKit for flashing the SD card

The short version

The default firmware does NOT configure UVC correctly for the Rockchip rk_mpi_uvc streaming app. There are several
critical issues you need to fix:

1. Wrong configfs naming — The default S50usbdevice names resolution directories as 480p, 720p etc. The rk_mpi_uvc app
expects SDK-style names: 640_480p, 1280_720p. Without this, rk_mpi_uvc can't parse the USB gadget configuration and
the pipeline doesn't start.
2. Missing pipeline config — rk_mpi_uvc looks for its pipeline configuration at /oem/usr/share/uvc_mpi_cfg.conf, NOT
at /userdata/. Without this file, it skips VPSS initialization and outputs zero-length buffers (you'll see "Unable to
queue buffer length is 0" in the log). The file exists in the SDK at output/uvc_mpi_cfg.conf but nobody copies it to
the right place.
3. Handler must start before UDC bind — The DWC3 USB controller on the RV1106 will crash with request was not queued
to ep1in if Windows opens the camera stream and no userspace UVC handler is running. You must start rk_mpi_uvc
(waiting for /dev/video21 to appear) BEFORE binding the UDC. The app will block waiting for the video device, and once
the UDC bind creates it, the handler is ready before Windows tries to stream.
4. Wrong USB parameters — The default script uses streaming_bulk=1, which doesn't work with rk_mpi_uvc. You need
streaming_maxpacket=2048 and uvc_num_request=2 (the SDK defaults).
5. Wrong device class — For a composite ACM+UVC device to enumerate correctly on Windows, you need bDeviceClass=239,
bDeviceSubClass=2, bDeviceProtocol=1. The default script doesn't set these.

Step-by-step instructions

1. Prepare the overlay files

Create these files in your project's overlay directory (or wherever your SDK build picks them up):

overlay/root/rk_mpi_uvc — Copy this binary from your SDK. It's usually at output/rk_mpi_uvc or built as part of the
media/rockit component.

overlay/root/rkuvc.ini — ISP configuration. A minimal working config:

Code: Select all

 [video.source]
  enable_aiq = 1
  enable_vo = 0
  enable_npu = 0
  enable_uac = 0

  [isp.0.adjustment]
  contrast = 50
  brightness = 50
  saturation = 50
  sharpness = 50
  fps = 30
  hue = 50

  [isp.0.exposure]
  exposure_mode = auto
  gain_mode = auto
  auto_exposure_enabled = 1
  audo_gain_enabled = 1

  [isp.0.white_blance]
  white_blance_style = autoWhiteBalance

  [isp.0.enhancement]
  noise_reduce_mode = close
  dehaze = close

  [isp.0.video_adjustment]
  scene_mode = indoor
  power_line_frequency_mode = PAL(50HZ)

overlay/root/uvc_mpi_cfg.conf — Pipeline configuration. This tells rk_mpi_uvc to use VPSS for format conversion. The
full file is in the SDK at output/uvc_mpi_cfg.conf. Key settings inside it:
- uvc_enable_vpss: "on" — Enables VPSS for scaling/format conversion (without this, raw NV12 goes to USB with zero
frames)
- geometric_output: "16:9" — Maintains aspect ratio matching the sensor

2. Replace the USB gadget init script

Replace /etc/init.d/S50usbdevice with this script. This is the single most critical file:

Code: Select all

 #!/bin/sh
  # Luckfox Pico Pro Max - UVC Camera gadget
  # SDK naming + rk_mpi_uvc auto-start
  . /etc/profile

  USB_ATTRIBUTE=0x409
  USB_GROUP=rockchip
  USB_SKELETON=b.1
  CONFIGFS_DIR=/sys/kernel/config
  USB_CONFIGFS_DIR=${CONFIGFS_DIR}/usb_gadget/${USB_GROUP}
  USB_STRINGS_DIR=${USB_CONFIGFS_DIR}/strings/${USB_ATTRIBUTE}
  USB_FUNCTIONS_DIR=${USB_CONFIGFS_DIR}/functions
  USB_CONFIGS_DIR=${USB_CONFIGFS_DIR}/configs/${USB_SKELETON}

  UVC_GS=uvc.gs1
  UVC_DIR=${USB_FUNCTIONS_DIR}/${UVC_GS}/
  UVC_STREAMING_DIR=${UVC_DIR}/streaming/
  UVC_CONTROL_DIR=${UVC_DIR}/control/
  UVC_U_DIR=${UVC_STREAMING_DIR}/uncompressed/u/
  UVC_M_DIR=${UVC_STREAMING_DIR}/mjpeg/m/

  configfs_init()
  {
      mount -t configfs none ${CONFIGFS_DIR}
      mkdir ${USB_CONFIGFS_DIR} -m 0770
      echo 0x2207 > ${USB_CONFIGFS_DIR}/idVendor
      echo 0x0310 > ${USB_CONFIGFS_DIR}/bcdDevice
      echo 0x0200 > ${USB_CONFIGFS_DIR}/bcdUSB
      echo 239 > ${USB_CONFIGFS_DIR}/bDeviceClass
      echo 2 > ${USB_CONFIGFS_DIR}/bDeviceSubClass
      echo 1 > ${USB_CONFIGFS_DIR}/bDeviceProtocol
      mkdir ${USB_STRINGS_DIR} -m 0770
      SERIAL=$(cat /proc/cpuinfo | grep Serial | awk '{print $3}')
      test -z "$SERIAL" && SERIAL=0123456789ABCDEF
      echo $SERIAL > ${USB_STRINGS_DIR}/serialnumber
      echo "rockchip" > ${USB_STRINGS_DIR}/manufacturer
      echo "Luckfox UVC" > ${USB_STRINGS_DIR}/product
      mkdir ${USB_FUNCTIONS_DIR}/acm.g0
      mkdir ${USB_FUNCTIONS_DIR}/${UVC_GS}
      mkdir ${USB_CONFIGS_DIR} -m 0770
      mkdir ${USB_CONFIGS_DIR}/strings/${USB_ATTRIBUTE} -m 0770
      echo 500 > ${USB_CONFIGS_DIR}/MaxPower
  }

  # Each resolution dir must use SDK naming: ${W}_${H}p
  # Frame interval 333333 = 30fps. Only advertise this one.
  configure_uvc_resolution_yuyv()
  {
      W=$1; H=$2
      DIR=${UVC_U_DIR}/${W}_${H}p/
      mkdir ${DIR}
      echo $W > ${DIR}/wWidth; echo $H > ${DIR}/wHeight
      echo 333333 > ${DIR}/dwDefaultFrameInterval
      echo $((W*H*20)) > ${DIR}/dwMinBitRate
      echo $((W*H*20)) > ${DIR}/dwMaxBitRate
      echo $((W*H*2)) > ${DIR}/dwMaxVideoFrameBufferSize
      printf "333333\n" > ${DIR}/dwFrameInterval
  }

  configure_uvc_resolution_mjpeg()
  {
      W=$1; H=$2
      DIR=${UVC_M_DIR}/${W}_${H}p/
      mkdir ${DIR}
      echo $W > ${DIR}/wWidth; echo $H > ${DIR}/wHeight
      echo 333333 > ${DIR}/dwDefaultFrameInterval
      echo $((W*H*20)) > ${DIR}/dwMinBitRate
      echo $((W*H*20)) > ${DIR}/dwMaxBitRate
      echo $((W*H*2)) > ${DIR}/dwMaxVideoFrameBufferSize
      printf "333333\n" > ${DIR}/dwFrameInterval
  }

  program_kill()
  {
      P_PID=$(ps | grep $1 | grep -v grep | awk '{print $1}')
      test -z ${P_PID} || kill -9 ${P_PID}
  }

  case "$1" in
  start)
      ifconfig lo up
      test -d ${USB_CONFIGFS_DIR} || configfs_init
      echo 0x0018 > ${USB_CONFIGFS_DIR}/idProduct

      # SDK UVC parameters (NOT streaming_bulk=1)
      echo 2048 > ${UVC_DIR}/streaming_maxpacket
      echo 2 > ${UVC_DIR}/uvc_num_request
      echo "UVC Camera" > ${UVC_DIR}/device_name
      echo "UVC Camera" > ${UVC_DIR}/function_name

      # Control endpoint
      mkdir ${UVC_CONTROL_DIR}/header/h
      ln -s ${UVC_CONTROL_DIR}/header/h ${UVC_CONTROL_DIR}/class/fs/h
      ln -s ${UVC_CONTROL_DIR}/header/h ${UVC_CONTROL_DIR}/class/ss/h

      # YUYV — use 16:9 resolutions only (sensor is 2304x1296)
      mkdir ${UVC_U_DIR}
      configure_uvc_resolution_yuyv 640 360
      configure_uvc_resolution_yuyv 1280 720

      # MJPEG
      mkdir ${UVC_M_DIR}
      configure_uvc_resolution_mjpeg 640 360
      configure_uvc_resolution_mjpeg 1280 720
      configure_uvc_resolution_mjpeg 1920 1080

      # Streaming header + class links
      mkdir ${UVC_STREAMING_DIR}/header/h
      ln -s ${UVC_U_DIR} ${UVC_STREAMING_DIR}/header/h/u
      ln -s ${UVC_M_DIR} ${UVC_STREAMING_DIR}/header/h/m
      ln -s ${UVC_STREAMING_DIR}/header/h ${UVC_STREAMING_DIR}/class/fs/h
      ln -s ${UVC_STREAMING_DIR}/header/h ${UVC_STREAMING_DIR}/class/hs/h
      ln -s ${UVC_STREAMING_DIR}/header/h ${UVC_STREAMING_DIR}/class/ss/h

      # Link ACM + UVC into config
      ln -s ${USB_FUNCTIONS_DIR}/acm.g0 ${USB_CONFIGS_DIR}/f1
      ln -s ${USB_FUNCTIONS_DIR}/${UVC_GS} ${USB_CONFIGS_DIR}/f2
      echo "acm_uvc" > ${USB_CONFIGS_DIR}/strings/${USB_ATTRIBUTE}/configuration

      program_kill rkipc

      # Copy pipeline config to where rk_mpi_uvc expects it
      mkdir -p /oem/usr/share
      cp /root/uvc_mpi_cfg.conf /oem/usr/share/uvc_mpi_cfg.conf

      # Start rk_mpi_uvc BEFORE binding UDC.
      # It waits for /dev/video21 (created by UDC bind).
      # Without this, DWC3 crashes with "request was not queued to ep1in".
      (
          while [ ! -e /dev/video21 ]; do sleep 0.1; done
          sleep 0.3
          LD_LIBRARY_PATH=/oem/usr/lib /root/rk_mpi_uvc \
              -c /root/rkuvc.ini -a /etc/iqfiles -l 3 \
              >> /tmp/rk_mpi_uvc.log 2>&1
      ) &

      # Bind UDC — this creates /dev/video21 and triggers enumeration
      sleep 2
      UDC=$(ls /sys/class/udc/ | awk '{print $1}')
      echo $UDC > ${USB_CONFIGFS_DIR}/UDC
      ;;
  stop)
      echo "none" > ${USB_CONFIGFS_DIR}/UDC 2>/dev/null
      program_kill rk_mpi_uvc
      ;;
  restart)
      $0 stop; sleep 1; $0 start
      ;;
  *)
      echo "Usage: $0 {start|stop|restart}"; exit 1
  esac
  exit 0

3. Build and flash

Build the firmware using the SDK (Docker or native) and flash to SD card with SocToolKit. Boot the board with USB-C
connected to your PC.

4. Verify

The board should appear as a "Luckfox UVC" camera device. Open it in VLC (dshow://), Windows Camera app, or any camera
app. You should see a 16:9 video stream at 30fps.

Debugging

- cat /tmp/rk_mpi_uvc.log — Check the streaming app log
- dmesg | grep -i uvc — Check kernel UVC messages
- configfs_find_uvc_function error! — This warning appears twice and is harmless
- "Unable to queue buffer length is 0" — The uvc_mpi_cfg.conf is missing from /oem/usr/share/
- Board crashes when opening camera — rk_mpi_uvc wasn't running before UDC bind
- Stretched image — You're using 4:3 resolutions (640x480) with a 16:9 sensor. Switch to 640x360 or 1280x720.
- Low FPS — Windows picks the slowest frame interval from dwFrameInterval. Only advertise 333333 (30fps).
- Board doesn't reboot with reboot command — Physical power cycle required on this board.

The result is my Luckfox successfully appearing as an USB camera in Device Manager :)