# 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](https://download.kendryte.com/k230/release/linux_sdk_images/daily_build/), 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`

```bash
# 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](../../userguide/how_to_flash.md#image-download-and-flash) to flash the firmware to the development board.

### Serial Port Connection

Serial port default parameters: **115200 8 1 no flow control**
> **Reference**: [Development Board Serial Port Login Guide](../../userguide/how_to_flash.md#board-connection)
>
#### 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

```bash
# 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

```bash
# 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.

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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**:
>
> - [v4l2-drm](https://github.com/kendryte/k230_linux_sdk/tree/dev/buildroot-overlay/package/vvcam/v4l2-drm)
> - [vglite_cube and vglite_drm](https://github.com/kendryte/k230_linux_sdk/tree/dev/buildroot-overlay/package/vg_lite)

#### 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:

```bash
ls -lh /boot
```

**Switch to LCD display**:

```bash
#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**:

```bash
#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:

```bash
v4l2-ctl --list-devices
```

Example output:

```bash
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

```bash
# 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
```

> **Source code reference**: [buildroot-overlay/package/face_detect](https://github.com/kendryte/k230_linux_sdk/tree/dev/buildroot-overlay/package/face_detect)

### Multimedia Testing

```bash
# 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](https://github.com/kendryte/k230_linux_sdk/tree/dev/buildroot-overlay/package/mvx_player)

### UVC Camera Testing

```bash
# 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

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

#### Display Configuration

**HDMI Display**:

```bash
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**:

```bash
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

```bash
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

```bash
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:
>
> ```bash
> pip install --break-system-packages /root/nncaseruntime_k230-2.11.0-py3-none-linux_riscv64.whl
> ```
>
> - Requires Python 3.13 environment (provided by Debian by default)
> - Currently only applicable to Debian systems
> - Download link: [nncaseruntime_k230-2.11.0-py3-none-linux_riscv64.whl](https://github.com/kendryte/nncase/releases/download/v2.11.0/nncaseruntime_k230-2.11.0-py3-none-linux_riscv64.whl)

### KPU Python Demo

> **API Documentation**: [nncaseruntime_k230_API](https://github.com/kendryte/nncase_docs/blob/master/Linux_only_dir/nncaseruntime_k230_API.md)

The reference commands are as follows:

```bash
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](https://github.com/kendryte/nncase_docs/blob/master/Linux_only_dir/demo/demo.py)

### Python OpenCV Example - Video Display

```bash
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

```bash
# 安装 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

```bash
# 下载人脸检测模型（如未下载）
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
```
