Note

This is the documentation for the latest development branch and may refer to features that are not available in released versions. If you are looking for the documentation for a specific release, use the drop-down menu on the left and select the desired version.

K230 Debian/Ubuntu System User Guide#

Tip: Debian and Ubuntu have similar functionality. For the K230 platform, using the Debian system is recommended.

Quick Start#

Image Acquisition#

Users can download CI-compiled images from the K230 Linux SDK Image Center, or refer to the following commands to build images by yourself.

Image filename examples:

  • CanMV-K230_01studio_debian_v0.6.4_nncase_v2.9.0.img.gz

  • CanMV-K230_01studio_ubuntu_v0.6.4_nncase_v2.9.0.img.gz

# Clone source code
git clone git@github.com:kendryte/k230_linux_sdk.git
# git clone git@gitee.com:kendryte/k230_linux_sdk.git

cd k230_linux_sdk

# Build configuration
make CONF=k230_canmv_01studio_defconfig  # 01studio development board
# make CONF=k230_canmv_defconfig          # K230 CANMV development board

# Generate image
sudo make debian   # Generate Debian image
sudo make ubuntu   # Generate Ubuntu image

Generated image paths:

  • Debian: output/k230_canmv_01studio_defconfig/images/CanMV-K230_01studio_debian_v0.6.4_nncase_v2.9.0.img.gz

  • Ubuntu: output/k230_canmv_01studio_defconfig/images/CanMV-K230_01studio_ubuntu_v0.6.4_nncase_v2.9.0.img.gz

Image Flashing#

Please refer to the Image Flashing Guide to flash the firmware to the development board.

Serial Port Connection#

Serial port default parameters: 115200 8 1 no flow control

Development Boards with Built-in USB to Serial Chip#

Some development boards (such as K230 CANMV) have a built-in USB to serial chip (CH34x). Simply connect the development board to the computer using a USB cable, install the CH34x driver, set the correct serial port parameters in PuTTY, and press the Reset button to view the CPU output.

Development Boards Requiring External USB to Serial#

Some development boards (such as 01studio, JLC, etc.) require an external USB to serial adapter board. The corresponding driver must be installed before the serial port output can be viewed.

Serial Port Login System#

After seeing the login prompt on the serial port, use the following credentials to log in:

  • Username: root

  • Password: root


Configuration Usage#

Note: The system default user and password are both root. You can install software using apt install.

Wired Network Configuration#

DHCP Auto IP Assignment#

# Use systemd-networkd to configure the network (DHCP)
cat > /etc/systemd/network/10-eth0.network <<'EOF'
[Match]
Name=en*

[Network]
DHCP=yes
EOF

systemctl disable networking
systemctl enable --now systemd-networkd
systemctl restart systemd-networkd

# View default gateway
# ip route show default
# ip route

Static IP Configuration#

# Use systemd-networkd to configure the network (Static IP)
cat > /etc/systemd/network/10-eth0.network <<'EOF'
[Match]
Name=en*

[Network]
Address=192.168.1.2/24
Gateway=192.168.1.1
DNS=192.168.1.1
EOF

systemctl disable networking
systemctl stop systemd-networkd
systemctl restart systemd-networkd

Software Installation#

Note: The apt command depends on the system time. If the time is incorrect, SSL/TLS connections may fail. Please confirm the time is correct before installing software.

# Check the current time, set it manually if incorrect
# date -s "2025-04-14 11:15:20"

apt-get update
apt install wpasupplicant

Wireless Network Configuration#

# Install wireless network support
apt install wpasupplicant

# Execute the sta.sh script to connect to WiFi
# Format: sta.sh <network interface> <SSID> <password>
sta.sh wlan0 canaan_wifi 123456789

NTP Automatic Time Synchronization and Timezone Configuration#

# Install NTP client
apt install systemd-timesyncd

# Set timezone to Asia/Shanghai
rm -rf /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# Enable automatic time synchronization
systemctl enable systemd-timesyncd

SSH Remote Login#

# Install SSH service
apt install -y openssh-server

# Allow root user login
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config

# Restart SSH service
systemctl restart ssh

Auto-run Script at Boot#

# Create startup script
cat > /opt/mount_boot.sh <<'EOF'
#!/bin/bash
bootddev=$(cat /proc/cmdline | sed -n "s#root=\(\/dev\/mmcblk[0-9]\).*#\1#p")
sd_size=$(parted ${bootddev} print | grep ${bootddev} | cut -d: -f2)
parted ${bootddev} resizepart 2 ${sd_size}; resize2fs ${bootddev}p2
mount ${bootddev}p1 /boot
EOF

chmod +x /opt/mount_boot.sh

# Create systemd service
cat > /etc/systemd/system/mount_boot.service <<'EOF'
[Unit]
Description=Mount Boot Part
After=rc-local.service

[Service]
Type=oneshot
ExecStart=/opt/mount_boot.sh
RemainAfterExit=no

[Install]
WantedBy=basic.target
EOF

# Enable service
systemctl enable mount_boot.service

Sensor and Display Test#

# Install dependencies
apt-get install libdrm2

# Install K230 ISP driver
# dpkg -i /root/deb/k230-vvcam.deb

# Test GPU and display (vglite_drm example)
vglite_drm

# Test GPU and display (vglite_cube example)
vglite_cube

# List video devices
# v4l2-ctl --list-devices

# Display camera image (adjust the -d parameter according to the actual video device)
v4l2-drm -d 1 -n 5 -w 640 -h 480

Source Code Reference:

Device Tree Configuration#

If there is no display output, please check whether the device tree is correct:

  • Device tree for LCD: should use xxxxxx-lcd.dtb

  • Device tree for HDMI: should use xxxxxx.dtb

Check the current device tree:

ls -lh /boot

Switch to LCD display:

#Taking 01studio as an example
cd /boot
rm -rf k.dtb
ln -s k230-canmv-01studio-lcd.dtb k.dtb
sync
reboot

Switch to HDMI display:

#Taking 01studio as an example
cd /boot
rm -rf k.dtb
ln -s k230-canmv-01studio.dtb k.dtb
sync
reboot

Camera Device Confirmation#

If the display is visible but the video cannot be shown, you can use the following command to confirm the camera device number:

v4l2-ctl --list-devices

Example output:

Linlon Video device (platform:mvx):
 /dev/video0

Canaan nonai 2D (platform:nonai-2d):
 /dev/video7

vvcam-isp-subdev.0 (platform:vvcam-isp-subdev.0):
 /dev/v4l-subdev0

vvcam-video.0.0 (platform:vvcam-video.0.0):
 /dev/video3   # Camera device, v4l2-drm -d 3

vvcam-video.0.1 (platform:vvcam-video.0.1):
 /dev/video4

vvcam-video.0.2 (platform:vvcam-video.0.2):
 /dev/video5

vvcam-video.0.3 (platform:vvcam-video.0.3):
 /dev/video6

GENERAL WEBCAM: GENERAL WEBCAM (usb-91540000.usb-1.1):
 /dev/video1
 /dev/video2
 /dev/media0

Face Recognition Demo Installation and Testing#

# Install face recognition related dependency packages
# apt-get install -y libdrm2 libgomp1 libwebp7 libpng-dev libopus-dev

# Install K230 related deb packages
# dpkg -i /root/deb/k230-vvcam.deb /root/deb/k230-opencv4.deb /root/deb/k230-ffmpeg.deb /root/deb/k230-face-detect.deb

# Run face recognition demo
cd /root/app/face_detect
./face_detect_video.sh

Multimedia Testing#

# Install multimedia player
# dpkg -i deb/k230-mvx-player.deb

# View devices: video0 is codec, video1 is camera
v4l2-ctl --list-devices

# Capture camera frames and save as NV12 format (1080p, 25 frames)
# Please ensure data write speed is fast enough, otherwise reduce resolution
v4l2-ctl \
    --device=/dev/video1 \
    --set-fmt-video=width=1920,height=1080,pixelformat=NV12 \
    --stream-mmap \
    --stream-count=25 \
    --stream-to=output.yuv

# H.264 video decoding
mvx_decoder --dev /dev/video0 -i h264 -o yuv420_nv12 test.264 output1.yuv

# Use FFmpeg to capture camera and encode to MP4 via VPU
ffmpeg -f v4l2 -input_format nv12 -r 30 -s 1920x1080 \
    -i /dev/video1 -c:v h264_v4l2m2m -b:v 4M -vsync passthrough -y test.mp4

Source code reference: mvx_decoder

UVC Camera Testing#

# Install tools
apt install v4l-utils ffmpeg usbutils

# List all V4L2 devices
v4l2-ctl --list-devices

# View device detailed information
v4l2-ctl -d /dev/video0 --all

# List supported formats
v4l2-ctl -d /dev/video1 --list-formats-ext

# Capture single frame image
ffmpeg -f v4l2 -i /dev/video1 -frames:v 1 -s 640x480 camera_capture.jpg

# Record video (CPU encoding, relatively slow)
ffmpeg -f v4l2 -i /dev/video1 -c:v libx264 -s 640x480 -r 15 -t 3 record_10s.mp4

# View encoders supported by FFmpeg
ffmpeg -encoders | grep v4l2

PyQt Installation and Testing#

Install PyQt5#

apt update
apt install -y qtbase5-dev qtbase5-examples python3-pyqt5

Display Configuration#

HDMI Display:

cat > /etc/profile.d/qt_env.sh <<'EOF'
export QT_QPA_PLATFORM=linuxfb
export QT_QPA_FB_DRM=1
export QT_QPA_EGLFS_KMS_CONFIG="/root/kms_config.json"
EOF

cat > /root/kms_config.json <<'EOF'
{
    "device": "/dev/dri/card0",
    "outputs": [
        { "name": "HDMI1", "format": "argb8888" }
    ]
}
EOF

LCD Display:

cat > /etc/profile.d/qt_env.sh <<'EOF'
export QT_QPA_PLATFORM=linuxfb
export QT_QPA_FB_DRM=1
export QT_QPA_EGLFS_KMS_CONFIG="/root/kms_config.json"
EOF

cat > /root/kms_config.json <<'EOF'
{
    "device": "/dev/dri/card0",
    "outputs": [
        { "name": "DSI1", "format": "argb8888" }
    ]
}
EOF

Run Test#

cat > helloworld_pyqt.py <<'EOF'
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QFont

def main():
    app = QApplication(sys.argv)
    window = QWidget()
    window.setWindowTitle('Hello World')

    # Label 1
    label = QLabel('Hello World', window)
    label.move(50, 50)

    # Label 2
    label = QLabel('wjx, test', window)
    label.move(300, 400)
    label.setFont(QFont('Arial', 30, QFont.Bold))
    label.setStyleSheet("QLabel { color: red; }")

    # Label 3
    label = QLabel('k230 pyqt5 test', window)
    label.move(500, 500)
    label.setFont(QFont('Arial', 50, QFont.Bold))
    label.setStyleSheet("QLabel { color: red; }")

    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
EOF

python3 helloworld_pyqt.py

C/C++ Development Reference#

  • Helloworld

  • Vector test

  • Face recognition


Python Development Reference#

Environment Setup#

apt update
apt install -y python3 python3-pip

python3 --version
pip3 --version

Note: To use the KPU feature, you need to install the nncase runtime:

pip install --break-system-packages /root/nncaseruntime_k230-2.11.0-py3-none-linux_riscv64.whl

KPU Python Demo#

API Documentation: nncaseruntime_k230_API

The reference commands are as follows:

apt-get install unzip
wget https://github.com/kendryte/nncase_docs/archive/refs/heads/master.zip
unzip master.zip
cd nncase_docs-master/Linux_only_dir/demo
python3 demo.py

Running Result: output.jpg

Source Code Reference: demo.py

Python OpenCV Example - Video Display#

apt install -y python3-opencv

cat > t.py <<'EOF'
import cv2
import time
import sys
import select

# 指定摄像头索引
camera_index = 1

# 打开摄像头
cap = cv2.VideoCapture(camera_index)

# 检查摄像头是否成功打开
if not cap.isOpened():
    print(f"Cannot open camera {camera_index}")
    exit()

# 设置分辨率(宽度,高度)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
print(f"Resolution set to 1920x1080")

frame_count = 0
start_time = time.time()

while True:
    # 读取帧
    ret, frame = cap.read()
    if not ret:
        print("Cannot read frame")
        break

    frame_count += 1

    # 每秒计算一次 FPS
    current_time = time.time()
    if current_time - start_time >= 1.0:
        fps = int(frame_count / (current_time - start_time))
        print(f"FPS: {fps}")
        frame_count = 0
        start_time = current_time

    # 颜色空间转换(摄像头返回 RGB,OpenCV 需要 BGR)
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

    # 显示画面
    cv2.imshow('Camera Feed', frame)

    # 键盘退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        print("\nExiting program.")
        break
    if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
        print("\nExiting due to input from stdin!")
        break
    time.sleep(0.01)

# 释放资源
cap.release()
cv2.destroyAllWindows()
EOF

python3 t.py

OpenCV Face Detection - Image#

# 安装 wget(如未安装)
apt-get install -y wget

# 下载人脸检测模型和测试图片
wget https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml
wget -c https://www.kendryte.com/api/post/attachment?id=602 -O 1.jpg

cat > t.py <<'EOF'
import cv2
import sys

# 加载人脸检测模型
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

# 加载图片
image_path = '1.jpg'
img = cv2.imread(image_path)

# 检查图片是否加载成功
if img is None:
    print(f"Cannot load image: {image_path}")
    sys.exit()

# 转换为灰度图(人脸检测在灰度图上进行)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 检测人脸
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

print(f"Found {len(faces)} face(s)")

# 绘制检测框(绿色,线宽 2)
for (x, y, w, h) in faces:
    print(f"x={x}, y={y}, w={w}, h={h}")
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

# 显示结果
cv2.imshow('Face Detection', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
EOF

python3 t.py

OpenCV Face Detection - Camera#

# 下载人脸检测模型(如未下载)
wget https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml

cat > t.py <<'EOF'
import cv2
import time

# 加载人脸检测模型
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

# 打开摄像头(根据实际设备调整参数)
cap = cv2.VideoCapture(1)

# 检查摄像头是否成功打开
if not cap.isOpened():
    print("Cannot open camera")
    exit()

# 检测间隔(每 N 帧检测一次)
detection_interval = 1
frame_count = 0
faces = []

# 初始化时间变量
start_time = time.time()

while True:
    # 读取帧
    ret, frame = cap.read()
    if not ret:
        print("Cannot read frame")
        break

    frame_count += 1

    # 按间隔进行人脸检测
    if frame_count % detection_interval == 0:
        # 转换为灰度图
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 检测人脸
        faces = face_cascade.detectMultiScale(
            gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

    # 绘制检测框
    for (x, y, w, h) in faces:
        print(f"x={x}, y={y}, w={w}, h={h}")
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 计算并打印 FPS
    elapsed_time = time.time() - start_time
    if elapsed_time >= 1.0:
        fps = frame_count / elapsed_time
        print(f"FPS: {fps:.2f}")
        frame_count = 0
        start_time = time.time()

    # 显示画面
    cv2.imshow('Live Face Detection', frame)

    # 键盘退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()
EOF

python3 t.py
Comments list
Comments
Log in