一、RK3588整体架构概览

        

项目 类型 型号参数 说明
核心配置 处理器 RK3588 CPU

Quad-core ARM Cortex-A76@2.4GHz

Quad-core ARM Cortex-A55@1.8GH

GPU 四核 ARM Mali-G610 MP4
NPU 算力 6.0TOPs
内存 LPDDR4 默认配置 8GByte
可选配置 4GByte/16GByte
存储 eMMC 默认配置 32GByte
可选配置 64GByte

     本机配置:RK3588/8GByte/64GByte

二、软件资源

2.1、英码科技官方SDK:

​​​​​​https://pan.baidu.com/s/1QsDRVisbcaC2X1sd54ac5A?pwd=wbdn 提取码:wbdn

链接失效了找英码官方要:https://www.ema-tech.com/technology

SDK:

出货镜像:

烧录工具:

2.2、rockchip_RKLLM_SDK

https://github.com/airockchip/rknn-llm

2.3、hf-mirror原版Qwen2.5-3B-Instruct

$:export HF_ENDPOINT=https://hf-mirror.com
$:hf download Qwen/Qwen2-7B-Instruct --local-dir ./Qwen2.5-3B-Instruct

模型文件:

三、必备条件

3.1、RK3588 NPU驱动版本≥0.9.8,查看NPU驱动版本:

$cat /sys/kernel/debug/rknpu/version
RKNPU driver:v0.9.8

3.2、PC: Ubuntu 20.04 x86_64 / Ubuntu 22.04 x86_64, kernel 5.10/kernel 6.1,16~32G

3.3、板端 :Ubuntu 20.04/Ubuntu 22.04,kernel 5.10/kernel 6.1

#系统版本
uname -v

#或
cat /etc/issue
#内核版本
uname -r

#或
cat /proc/version

3.4、本机:PC(Ubuntu 22.04 x86_64, python3.10),板端(Ubuntu 20.04/kernel 5.10,python 3.8)

四、板端:系统烧录与镜像更新(驱动更新)

4.1、linux系统烧录镜像:

        4.1.1、工具:Linux_Upgrade_Tool_v1.65.zip,下载后解压。

#解压
unzip Linux_Upgrade_Tool_v1.65.zip
cd Linux_Upgrade_Tool_v1.65

        解压后的文件:       

                            

        安装到系统中:      

#安装到系统中
sudo mv upgrade_tool /usr/local/bin
sudo chown root:root /usr/local/bin/upgrade_tool
sudo chmod a+x /usr/local/bin/upgrade_tool

        检测是否识别:

#检测是否识别
sudo upgrade_tool ld

        显示以下信息,说明安装成功。

$ sudo upgrade_tool ld
Not found config.ini
Program Data in /usr/local/bin
List of rockusb connected(0)

        4.1.2、烧录镜像:evm3588_ubuntu20.04_v1.0.3_ema_v1.2.1.6_240429.img

        软件方式进入Loader模式:        

adb reboot loader
* daemon not running; starting now at tcp:5037
* daemon started successfully

        烧录固件:

#擦除flash 使用ef 参数
sudo upgrade_tool ef evm3588_ubuntu20.04_v1.0.3_ema_v1.2.1.6_240429.img
#重新烧写
sudo upgrade_tool uf evm3588_ubuntu20.04_v1.0.3_ema_v1.2.1.6_240429.img

        如果Linux_Upgrade_Tool安装到系统中失败,使用以下命令:

#镜像和工具放到同一目录下
cd Linux_Upgrade_Tool_v1.65
sudo ./upgrade_tool uf evm3588_ubuntu20.04_v1.0.3_ema_v1.2.1.6_240429.img

          出现以下信息,烧写成功。

Linux_Upgrade_Tool_v1.65$ ./upgrade_tool uf evm3588_ubuntu20.04_v1.0.3_ema_v1.2.1.6_240429.img' 
Program Data in 
Loading firmware...
Support Type:RK3588	FW Ver:1.0.00	FW Time:2024-04-29 15:25:51
Loader ver:1.0b	Loader Time:2023-08-09 09:40:20
Upgrade firmware ok.

        系统重启,板端查看NPU驱动版本:

$cat /sys/kernel/debug/rknpu/version
RKNPU driver:v0.9.2

         4.1.3、更新boot镜像(包含NPU驱动)

#进入loader模式
adb reboot loader
#安装upgrade_tool工具成功就去掉 ./
sudo ./upgrade_tool di -boot evm3588_ab_boot-v0.9.8.img

#或
sudo upgrade_tool di -boot evm3588_ab_boot-v0.9.8.img

        出现以下信息,烧写成功。

Linux_Upgrade_Tool_v1.65$ sudo ./upgrade_tool di -boot evm3588_ab_boot-v0.9.8.img
Program Data in 
directlba=1,first4access=1,gpt=1
Download boot start...(0x00008000)
Download image ok.

        系统重启,板端查看NPU驱动版本:

$sudo cat /sys/kernel/debug/rknpu/version
RKNPU driver:v0.9.8

五、PC: X86 电脑|模型量化转换 HF 原生→.rkllm(ubuntu 22.04)

        5.1、安装conda和rkllm-toolkit(rkllm_toolkit-1.2.3) 及依赖。

                conda:

#创建虚拟环境:
conda create --name rkllm310 python=3.10
#激活虚拟环境:
conda activate rkllm310

                安装对应python版本的rkllm_toolkit :

        

cd /rknn-llm-main/rkllm-toolkit/packages
#虚拟环境安装:
pip install rkllm_toolkit-1.2.3-cp310-cp310-linux_x86_64.whl
#安装依赖
sudo apt install -y git build-essential cmake python3-pip libssl-dev gcc g++

                版本检查:

python -c "from rkllm.api import RKLLM; print('✅ RKLLM 导入成功')"

                强制安装对应版本核心包

pip install torch==2.6.0 transformers==4.55.2 numpy==1.26.4 accelerate==1.5.2 Jinja2==3.1.4 safetensors==0.5.3 sentencepiece==0.2.0 --force-reinstall
# 打印所有核心依赖的当前版本
pip list | grep -E "torch|transformers|numpy|accelerate|sentencepiece|safetensors|Jinja2"

                

        5.2、下载hf-mirror原版Qwen2.5-3B-Instruct

#下载模型到文件夹./Qwen2.5-3B
$:export HF_ENDPOINT=https://hf-mirror.com
$:hf download Qwen/Qwen2.5-3B-Instruct --local-dir ./Qwen2.5-3B

        5.3、模型量化转换(HF 原生→.rkllm,关键步骤)

                 rockchip_RKLLM_SDK / rknn-llm-main:

                 ../rknn-llm-main/examples/rkllm_api_demo/export/export_rkllm.py

                

                修改 modelpath = '../Qwen2.5-3B-Instruct' 为下载的原版Qwen2.5-3B-Instruct路径

from rkllm.api import RKLLM
import os
os.environ['CUDA_VISIBLE_DEVICES']='0'

'''
https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B

Download the DeepSeek R1 model from the above url.
'''

modelpath = '../Qwen2.5-3B-Instruct'
llm = RKLLM()

# Load model
# Use 'export CUDA_VISIBLE_DEVICES=0' to specify GPU device
# device options ['cpu', 'cuda']
# dtype  options ['float32', 'float16', 'bfloat16']
# Using 'bfloat16' or 'float16' can significantly reduce memory consumption but at the cost of lower precision  
# compared to 'float32'. Choose the appropriate dtype based on your hardware and model requirements. 
ret = llm.load_huggingface(model=modelpath, model_lora = None, device='cuda', dtype="float32", custom_config=None, load_weight=True)
# ret = llm.load_gguf(model = modelpath)
if ret != 0:
    print('Load model failed!')
    exit(ret)

# Build model
dataset = "./data_quant.json"
# Json file format, please note to add prompt in the input,like this:
# [{"input":"Human: 你好!\nAssistant: ", "target": "你好!我是人工智能助手KK!"},...]
# Different quantization methods are optimized for different algorithms:  
# w8a8/w8a8_gx   is recommended to use the normal algorithm.  
# w4a16/w4a16_gx is recommended to use the grq algorithm.
qparams = None # Use extra_qparams
target_platform = "RK3588"
optimization_level = 1
quantized_dtype = "W8A8"
quantized_algorithm = "normal"
num_npu_core = 3

ret = llm.build(do_quantization=True, optimization_level=optimization_level, quantized_dtype=quantized_dtype,
                quantized_algorithm=quantized_algorithm, target_platform=target_platform, num_npu_core=num_npu_core, extra_qparams=qparams, dataset=dataset, hybrid_rate=0, max_context=4096)
if ret != 0:
    print('Build model failed!')
    exit(ret)

# Export rkllm model
ret = llm.export_rkllm(f"./{os.path.basename(modelpath)}_{quantized_dtype}_{target_platform}.rkllm")
if ret != 0:
    print('Export model failed!')
    exit(ret)

        canda环境运行python export_rkllm.py 开始转换模型:

(rkllm310) admain@D:/rockchip/jxby/Qwen2.5-3B$ python export_rkllm.py 

        出现以下信息,转换成功。                                                                                        

        5.4、模型传输到板端

adb push Qwen2.5-3B-Instruct_w8a8_rk3588.rkllm /home/ema/3588/models

    

六、板端:rkllm-runtime配置及调用模型

        6.1、开发板配置rkllm-runtime

(可选)放到系统路径:
# 头文件
sudo cp -r rkllm-runtime/runtime/Linux/include /usr/include/
# 库文件
sudo cp rkllm-runtime/runtime/Linux/aarch64/librkllmrt.so /usr/lib/
# 刷新库缓存
sudo ldconfig

        6.2、模型调用及demo

        rockchip_RKLLM_SDK / rknn-llm-main:

        ../rknn-llm-main/examples/rkllm_api_demo/deploy/

        

        编译:

#创建并进入编译文件夹
mkdir build && cd build

cmake ..
#编译
make -j4

       

        运行:

# ./llm_demo + rkllm模型路径 + 单次最大 + 最大上下文窗口
./llm_demo /home/ema/3588/models/Qwen2.5-3B-Instruct_w8a8_rk3588.rkllm  256 4096

        出现以下信息运行成功:

ema@ema:~/3588/rockchip/rknn-llm-main/examples/rkllm_api_demo/deploy/build$ ./llm_demo /home/ema/3588/models/Qwen2.5-3B-Instruct_w8a8_rk3588.rkllm  256 4096
rkllm init start
I rkllm: rkllm-runtime version: 1.2.3, rknpu driver version: 0.9.8, platform: RK3588
I rkllm: loading rkllm model from /home/ema/3588/models/Qwen2.5-3B-Instruct_W8A8_RK3588.rkllm
I rkllm: rkllm-toolkit version: 1.2.3, max_context_limit: 4096, npu_core_num: 3, target_platform: RK3588, model_dtype: W8A8
I rkllm: Enabled cpus: [4, 5, 6, 7]
I rkllm: Enabled cpus num: 4
rkllm init success

        6.3、token/s 测试

        RKLLM 的 llm_demo,不需要额外装工具,只要开一条环境变量,就能自动打印 token/s

export RKLLM_LOG_LEVEL=1

        然后正常启动模型:

./llm_demo /home/ema/3588/models/Qwen2.5-3B-Instruct_w8a8_rk3588.rkllm 256 4096

        每次对话结束,终端会自动输出类似下面的token/s 结果:

                

        6.4、NPU 定频

                1. NPU的节点路径    

ema@ema:~/桌面$ ls /sys/class/devfreq/fdab0000.npu/
available_frequencies  device    max_freq  polling_interval  target_freq  uevent
available_governors    governor  min_freq  power             timer
cur_freq               load      name      subsystem         trans_stat

                2. 获取NPU支持的频点

ema@ema:~/桌面$ cat /sys/class/devfreq/fdab0000.npu/available_frequencies
300000000 400000000 500000000 600000000 700000000 800000000 900000000 1000000000

                最高1GHZ

                3. 获取NPU运行的模式                

ema@ema:~/桌面$ cat /sys/class/devfreq/fdab0000.npu/available_governors
rknpu_ondemand dmc_ondemand userspace powersave performance simple_ondemand

                performance:性能模式,强制锁定 NPU 运行在最高主频(1GHz),无论负载高低都保持满频,不自动降频。

                powersave:省电模式,强制锁定 NPU 运行在最低主频(300MHz),功耗和发热降到最低。

                userspace:用户空间控频模式,将调频权限完全开放给用户层,由你手动指定具体运行频率(必须是支持的频点)。

                simple_ondemand:简易按需调频模式,ux 通用的动态调速策略,根据 NPU 负载自动升降频。

                dmc_ondemand:内存控制器联动调频,联动动态内存控制器(DMC),根据 NPU 计算负载 + 内存带宽需求联合调频,优化高带宽场景的访问效率。

                4、查看当前模式频率

#模式
ema@ema:~/桌面$ cat /sys/class/devfreq/fdab0000.npu/governor 
performance
#频率
ema@ema:~/桌面$ cat /sys/class/devfreq/fdab0000.npu/cur_freq
1000000000

             5、模式配置&设置频率  

#设置模式
ema@ema:~/桌面$ sudo echo userspace > /sys/class/devfreq/fdab0000.npu/governor
#设置频率
echo 1000000000 > /sys/class/devfreq/fdab0000.npu/userspace/set_freq
cat /sys/class/devfreq/fdab0000.npu/cur_freq

#无权限使用以下命令
ema@ema:~/桌面$ echo userspace | sudo tee /sys/class/devfreq/fdab0000.npu/governor
userspace
ema@ema:~/桌面$ cat /sys/class/devfreq/fdab0000.npu/governor 
userspace
ema@ema:~/桌面$ echo 800000000 | sudo tee /sys/class/devfreq/fdab0000.npu/userspace/set_freq
800000000
ema@ema:~/桌面$ cat /sys/class/devfreq/fdab0000.npu/cur_freq
800000000

                6、负载&温度

#负载 三核
ema@ema:~/桌面$ sudo cat /sys/kernel/debug/rknpu/load
NPU load:  Core0: 78%, Core1: 80%, Core2: 79%,
#温度: value/1000
ema@ema:~/桌面$ cat /sys/class/thermal/thermal_zone6/temp
46230

        6.5、资源监控  ***.sh

#!/bin/bash

# --- 配置路径 ---
# NPU
NPU_LOAD_FILE="/sys/kernel/debug/rknpu/load"
NPU_FREQ_FILE="/sys/class/devfreq/fdab0000.npu/cur_freq"
NPU_TEMP_FILE="/sys/class/thermal/thermal_zone6/temp"

# GPU
GPU_FILE="/sys/class/devfreq/fb000000.gpu/load"

# RGA (视频处理)
RGA_LOAD_FILE="/sys/kernel/debug/rkrga/load"
CLK_SUMMARY_FILE="/sys/kernel/debug/clk/clk_summary"

# CPU
PROC_STAT_FILE="/proc/stat"
CPU_FREQ_BASE_PATH="/sys/devices/system/cpu"

# 内存/交换分区
MEM_INFO_FILE="/proc/meminfo"

# 磁盘监控路径(默认监控根分区 /,可自行修改)
DISK_MONITOR_PATH="/"


# --- 全局变量定义 ---
# NPU
NPU_CORE0_LOAD=0
NPU_CORE1_LOAD=0
NPU_CORE2_LOAD=0
NPU_FREQ="N/A"
NPU_TEMP=0

# GPU
GPU_LOAD=0
GPU_FREQ="N/A"
GPU_TEMP=0

# RGA
RGA_LOAD0=0
RGA_LOAD1=0
RGA_LOAD2=0
RGA_FREQ0="N/A"
RGA_FREQ1="N/A"
RGA_FREQ2="N/A"	

# CPU
declare -a CPU_LOAD
declare -a CPU_FREQ
declare -a CPU_PREV_TOTAL
declare -a CPU_PREV_IDLE
CPU_CORE_COUNT=0
CPU_FIRST_RUN=1
SOC_TEMP=0
LITTLE_CORE_TEMP=0
BIG_CORE0_TEMP=0
BIG_CORE1_TEMP=0

# 内存/交换分区
MEM_TOTAL=0
MEM_USED=0
MEM_USED_PERCENT=0
SWAP_TOTAL=0
SWAP_USED=0
SWAP_USED_PERCENT=0

# 磁盘存储(新增)
DISK_TOTAL=0
DISK_USED=0
DISK_USED_PERCENT=0


# --- 权限检查与自动提权 ---
if [ "$(id -u)" -ne 0 ]; then
    echo "此脚本需要 root 权限来读取 debugfs 信息。正在请求权限..."
    exec sudo "$0" "$@"
fi

# ---文件检查 ---
[[ ! -f "$NPU_LOAD_FILE" ]] && echo "警告:找不到 NPU load 文件"
[[ ! -f "$NPU_FREQ_FILE" ]] && echo "警告:找不到 NPU freq 文件"
[[ ! -f "$GPU_FILE" ]] && echo "警告:找不到 GPU load 文件"
[[ ! -f "$RGA_LOAD_FILE" ]] && echo "警告:找不到 RGA load 文件"
[[ ! -f "$CLK_SUMMARY_FILE" ]] && echo "警告:找不到 RGA clk_summary 文件"
[[ ! -f "$PROC_STAT_FILE" ]] && echo "警告:找不到 $PROC_STAT_FILE 文件"
[[ ! -f "$MEM_INFO_FILE" ]] && echo "警告:找不到 $MEM_INFO_FILE 文件"


# === 自适应配置 ===
BAR_WIDTH_BASE=5
BAR_WIDTH_MAX=40
LAYOUT_MARGIN=65
REFRESH_TIME=0.5

# 动态计算 BAR_WIDTH
calc_bar_width() {
    local term_width=80
    local cols
    if cols=$(tput cols 2>/dev/null); then
        term_width=$cols
    elif [[ -n "$COLUMNS" ]]; then
        term_width=$COLUMNS
    fi

    local available=$(( (term_width - LAYOUT_MARGIN) / 2 ))
    if (( available < BAR_WIDTH_BASE )); then
        BAR_WIDTH=$BAR_WIDTH_BASE
    elif (( available > BAR_WIDTH_MAX )); then
        BAR_WIDTH=$BAR_WIDTH_MAX
    else
        BAR_WIDTH=$available
    fi
}

# --- 绘制进度条函数 ---
draw_bar() {
    local percent=$1
    if ! [[ "$percent" =~ ^[0-9]+$ ]]; then
        percent=0;
    fi

    local filled=$((percent * BAR_WIDTH / 100))
    if (( percent > 0 && filled == 0 )); then
        filled=1
    fi

    local empty=$((BAR_WIDTH - filled))

    local GREEN='\033[32m'
    local YELLOW='\033[33m'
    local RED='\033[31m'
    local CYAN='\033[36m'
    local NC='\033[0m'

    if (( percent > 80 )); then
        COLOR=$RED
    elif (( percent > 50 )); then
        COLOR=$YELLOW
    else
        COLOR=$GREEN
    fi

    local i
    printf "${CYAN}[${COLOR}"
    for ((i=0; i<filled; i++)); do
        printf "|";
    done
    for ((i=0; i<empty; i++)); do
        printf " ";
    done
    printf "${CYAN}]${NC}"
}

# --- 设备查询函数 ---



# 温度读取辅助函数(保留兼容,实际已通过循环直接赋值)
get_thermal_temp() {
    local thermal_type="$1"
    for zone_path in /sys/class/thermal/thermal_zone*; do
        if [ -f "$zone_path/type" ] && [ "$(cat "$zone_path/type" 2>/dev/null)" = "$thermal_type" ]; then
            local temp_raw=$(cat "$zone_path/temp" 2>/dev/null)
            if [ -n "$temp_raw" ] && [[ "$temp_raw" =~ ^[0-9]+$ ]]; then
                awk -v t="$temp_raw" 'BEGIN {printf "%.1f°C", t / 1000}'
                return 0
            fi
        fi
    done
    echo "N/A"
}


# 1. 查询 NPU 状态
query_npu_status() {
    if [[ -f "$NPU_LOAD_FILE" ]]; then
        read -r NPU_CORE0_LOAD NPU_CORE1_LOAD NPU_CORE2_LOAD <<< $(awk '{gsub(/%|,/,""); print $4, $6, $8}' "$NPU_LOAD_FILE" 2>/dev/null)
    else
        NPU_CORE0_LOAD=0; NPU_CORE1_LOAD=0; NPU_CORE2_LOAD=0
    fi

    if [[ -f "$NPU_FREQ_FILE" ]]; then
        NPU_FREQ=$(awk '{printf "%.2f", $1/1000000000}' "$NPU_FREQ_FILE" 2>/dev/null)
    else
        NPU_FREQ="N/A"
    fi
}

# 2. 查询 GPU 状态
query_gpu_status() {
    if [[ -f "$GPU_FILE" ]]; then
        read -r GPU_LOAD GPU_FREQ <<< $(cat "$GPU_FILE" | awk -F'@' '{gsub(/Hz/, "", $2); printf "%d %.2f", $1, $2/1000000000}')
    else
        GPU_LOAD=0
        GPU_FREQ="N/A"
    fi
}

# 3. 查询 RGA 状态
query_rga_status() {
    if [[ -f "$RGA_LOAD_FILE" ]]; then
        local rga_loads=( $(cat "$RGA_LOAD_FILE" | awk '/load = [0-9]/ {print $3}' | tr -d '%') )
        RGA_LOAD0=${rga_loads[0]:-0}
        RGA_LOAD1=${rga_loads[1]:-0}
        RGA_LOAD2=${rga_loads[2]:-0}
    else
        RGA_LOAD0=0; RGA_LOAD1=0; RGA_LOAD2=0
    fi

    [[ "$RGA_LOAD0" =~ ^[0-9]+$ ]] || RGA_LOAD0=0
    [[ "$RGA_LOAD1" =~ ^[0-9]+$ ]] || RGA_LOAD1=0
    [[ "$RGA_LOAD2" =~ ^[0-9]+$ ]] || RGA_LOAD2=0

    local clk_data=$(cat /sys/kernel/debug/clk/clk_summary 2>/dev/null | grep rga)
    RGA_FREQ0=$(echo "$clk_data" | awk '$1 == "clk_rga3_0_core" {printf "%.2f", $5/1000000000}')
    RGA_FREQ1=$(echo "$clk_data" | awk '$1 == "clk_rga3_1_core" {printf "%.2f", $5/1000000000}')
    RGA_FREQ2=$(echo "$clk_data" | awk '$1 == "clk_rga2_core" {printf "%.2f", $5/1000000000}')
}

# 4. 查询 CPU 状态
query_cpu_status() {
    CPU_CORE_COUNT=$(grep -c "^cpu[0-9]" "$PROC_STAT_FILE")
    local idx=0
    while read -r line; do
        if [[ "$line" =~ ^cpu[0-9]+ ]]; then
            read -r _ user nice system idle iowait irq softirq steal _ <<< "$line"
            local curr_total=$((user + nice + system + idle + iowait + irq + softirq + steal))
            local curr_idle=$((idle + iowait))

            if [[ $CPU_FIRST_RUN -eq 1 ]]; then
                CPU_LOAD[$idx]=0
            else
                local diff_total=$((curr_total - CPU_PREV_TOTAL[$idx]))
                local diff_idle=$((curr_idle - CPU_PREV_IDLE[$idx]))
                if (( diff_total > 0 )); then
                    CPU_LOAD[$idx]=$(( (diff_total - diff_idle) * 100 / diff_total ))
                else
                    CPU_LOAD[$idx]=0
                fi
            fi

            CPU_PREV_TOTAL[$idx]=$curr_total
            CPU_PREV_IDLE[$idx]=$curr_idle

            local freq_file="$CPU_FREQ_BASE_PATH/cpu${idx}/cpufreq/scaling_cur_freq"
            if [[ -f "$freq_file" ]]; then
                local freq_khz=$(cat "$freq_file" 2>/dev/null)
                CPU_FREQ[$idx]=$(awk "BEGIN {printf \"%.4f\", $freq_khz/1000000}")
            else
                CPU_FREQ[$idx]="N/A"
            fi
            ((idx++))
        fi
    done < "$PROC_STAT_FILE"
    CPU_FIRST_RUN=0
}

display_cpu_status() {
    if [[ $CPU_CORE_COUNT -gt 0 ]]; then
        half=$(( (CPU_CORE_COUNT + 1) / 2 ))
        for ((i=0; i<half; i++)); do
            left_idx=$i
            right_idx=$((i + half))

            left_load=${CPU_LOAD[$left_idx]:-0}
            left_freq=${CPU_FREQ[$left_idx]:-"N/A"}
            printf "  CPU%-2d: " "$left_idx"
            draw_bar "$left_load"
            printf " %3d%% @ %s GHz" "$left_load" "$left_freq"
            printf "\t"

            if [[ $right_idx -lt $CPU_CORE_COUNT ]]; then
                right_load=${CPU_LOAD[$right_idx]:-0}
                right_freq=${CPU_FREQ[$right_idx]:-"N/A"}
                printf "CPU%-2d: " "$right_idx"
                draw_bar "$right_load"
                printf " %3d%% @ %s GHz" "$right_load" "$right_freq"
            fi
            printf "\n"
        done
    fi
}

# 5. 查询温度
query_temperature() {

    #local sensors_output
    #sensors_output=$(sensors 2>/dev/null)

    #SOC_TEMP=$(echo "$sensors_output" | awk '/^soc_thermal/{getline; getline; print $2}')
    #LITTLE_CORE_TEMP=$(echo "$sensors_output" | awk '/^littlecore_thermal/{getline; getline; print $2}')
    #BIG_CORE0_TEMP=$(echo "$sensors_output" | awk '/^bigcore0_thermal/{getline; getline; print $2}')
    #BIG_CORE1_TEMP=$(echo "$sensors_output" | awk '/^bigcore1_thermal/{getline; getline; print $2}')

    #NPU_TEMP=$(echo "$sensors_output" | awk '/^npu_thermal/{getline; getline; print $2}')
    #GPU_TEMP=$(echo "$sensors_output" | awk '/^gpu_thermal/{getline; getline; print $2}')
    
    # 初始化所有温度变量为默认值
    SOC_TEMP="N/A"
    LITTLE_CORE_TEMP="N/A"
    BIG_CORE0_TEMP="N/A"
    BIG_CORE1_TEMP="N/A"
    GPU_TEMP="N/A"

    # 一次遍历所有温度传感器,匹配名称后赋值给对应变量
    for zone in /sys/class/thermal/thermal_zone*; do
        if [[ ! -f "$zone/type" || ! -f "$zone/temp" ]]; then
            continue
        fi
        local zone_type=$(cat "$zone/type" 2>/dev/null)
        local temp_raw=$(cat "$zone/temp" 2>/dev/null)
        
        if [[ "$temp_raw" =~ ^[0-9]+$ ]]; then
            local temp_str=$(awk -v t="$temp_raw" 'BEGIN {printf "%.1f°C", t / 1000}')
            case "$zone_type" in
                "soc-thermal")          SOC_TEMP="$temp_str" ;;
                "littlecore-thermal")   LITTLE_CORE_TEMP="$temp_str" ;;
                "bigcore0-thermal")     BIG_CORE0_TEMP="$temp_str" ;;
                "bigcore1-thermal")     BIG_CORE1_TEMP="$temp_str" ;;
                "gpu-thermal")          GPU_TEMP="$temp_str" ;;
            esac
        fi
    done
    
        # NPU温度:直接读取指定的固定路径
    if [[ -f "$NPU_TEMP_FILE" ]]; then
        local npu_temp_raw=$(cat "$NPU_TEMP_FILE" 2>/dev/null)
        if [[ "$npu_temp_raw" =~ ^[0-9]+$ ]]; then
            NPU_TEMP=$(awk -v t="$npu_temp_raw" 'BEGIN {printf "%.1f°C", t / 1000}')
        else
            NPU_TEMP="N/A"
        fi
    else
        NPU_TEMP="N/A"
    fi
}

# 6. 内存&交换分区查询
query_memory_status() {
    read -r mt mf mb mc st sf < <(
        awk '
        /^MemTotal/  {mt=$2}
        /^MemFree/   {mf=$2}
        /^Buffers/   {mb=$2}
        /^Cached/    {mc=$2}
        /^SwapTotal/ {st=$2}
        /^SwapFree/  {sf=$2}
        END {print mt+0, mf+0, mb+0, mc+0, st+0, sf+0}
        ' "$MEM_INFO_FILE"
    )

    # 内存计算 KB -> MB
    local mem_used_kb=$(( mt - mf - mb - mc ))
    MEM_TOTAL=$(( mt / 1024 ))
    MEM_USED=$(( mem_used_kb / 1024 ))
    if (( mt > 0 )); then
        MEM_USED_PERCENT=$(( mem_used_kb * 100 / mt ))
    else
        MEM_USED_PERCENT=0
    fi

    # 交换分区计算
    local swap_used_kb=$(( st - sf ))
    SWAP_TOTAL=$(( st / 1024 ))
    SWAP_USED=$(( swap_used_kb / 1024 ))
    if (( st > 0 )); then
        SWAP_USED_PERCENT=$(( swap_used_kb * 100 / st ))
    else
        SWAP_USED_PERCENT=0
    fi
}

# 7. 【新增】磁盘存储空间查询
query_disk_status() {
    local disk_info
    disk_info=$(df -P "$DISK_MONITOR_PATH" 2>/dev/null | awk 'NR==2 {print $2, $3, $5}')
    read -r d_total_1k d_used_1k d_pct < <(echo "$disk_info")

    # 1K块 转为 MB
    DISK_TOTAL=$(( d_total_1k / 1024 ))
    DISK_USED=$(( d_used_1k / 1024 ))
    # 去除百分号
    DISK_USED_PERCENT=${d_pct%\%}
    # 容错
    [[ "$DISK_USED_PERCENT" =~ ^[0-9]+$ ]] || DISK_USED_PERCENT=0
}

# 定义清屏重绘函数
redraw_screen() {
    clear
    tput cup 0 0
    calc_bar_width
}

# 捕获窗口变化信号
trap redraw_screen SIGWINCH

# 初始化终端,隐藏光标,退出恢复
tput civis
trap 'tput cnorm; exit' INT EXIT

# --- 主循环 ---
redraw_screen
while true; do
    tput cup 0 0

    # 依次查询所有硬件状态
    query_npu_status
    query_gpu_status
    query_rga_status
    query_cpu_status
    query_temperature
    query_memory_status
    query_disk_status   # 新增磁盘查询

    # 绘制界面头部
    echo -e " Rockchip Monitor (Refresh: "$REFRESH_TIME"s)\t\tTime: $(date +"%H:%M:%S")"
    echo -e "--------------------"

    # --- 内存 & 交换分区区域 ---
    echo -e " Memory & Swap Status:"
    printf "  Memory: "; draw_bar "$MEM_USED_PERCENT"
    printf " %3d%% | Used: %d MB / Total: %d MB\n" "$MEM_USED_PERCENT" "$MEM_USED" "$MEM_TOTAL"

    printf "  Swap  : "; draw_bar "$SWAP_USED_PERCENT"
    printf " %3d%% | Used: %d MB / Total: %d MB\n" "$SWAP_USED_PERCENT" "$SWAP_USED" "$SWAP_TOTAL"

    # --- 【新增】磁盘存储区域(Swap 下方)---
    printf "  Disk  : "; draw_bar "$DISK_USED_PERCENT"
    printf " %3d%% | Used: %d MB / Total: %d MB\n" "$DISK_USED_PERCENT" "$DISK_USED" "$DISK_TOTAL"
    echo -e ""

    # --- CPU 区域 ---
    echo -e " CPU Status:"
    display_cpu_status
    printf "  SOC temperature: %s \n"  "$SOC_TEMP"
    printf "  Little cores temperature: %s \n"  "$LITTLE_CORE_TEMP"
    printf "  Big core0 temperature: %s \n  Big core1 temperature: %s \n"  "$BIG_CORE0_TEMP" "$BIG_CORE1_TEMP"
    echo -e ""

    # --- NPU 区域 ---
    echo -e " ========================================"
    echo -e " NPU Status:"
    printf "  Core0: "; draw_bar "$NPU_CORE0_LOAD"; printf " %3d%% @ %s GHz\n" "$NPU_CORE0_LOAD" "${NPU_FREQ}"
    printf "  Core1: "; draw_bar "$NPU_CORE1_LOAD"; printf " %3d%% @ %s GHz\n" "$NPU_CORE1_LOAD" "${NPU_FREQ}"
    printf "  Core2: "; draw_bar "$NPU_CORE2_LOAD"; printf " %3d%% @ %s GHz\n" "$NPU_CORE2_LOAD" "${NPU_FREQ}"
    printf "  NPU temperature: %s \n"  "$NPU_TEMP"
    echo -e " ========================================"
    echo -e ""

    # --- GPU 区域 ---
    echo -e " GPU Status:"
    printf "  Util : "; draw_bar "$GPU_LOAD"; printf " %3d%% @ %s GHz\n" "$GPU_LOAD" "$GPU_FREQ"
    printf "  GPU temperature: %s \n"  "$GPU_TEMP"
    echo -e ""

    # --- RGA 区域 ---
    echo -e " RGA Status (Video Proc):"
    printf "  RGA3_0: "; draw_bar "$RGA_LOAD0"; printf " %3d%% @ %s GHz\n" "$RGA_LOAD0" "${RGA_FREQ0:-N/A}"
    printf "  RGA3_1: "; draw_bar "$RGA_LOAD1"; printf " %3d%% @ %s GHz\n" "$RGA_LOAD1" "${RGA_FREQ1:-N/A}"
    printf "  RGA2  : "; draw_bar "$RGA_LOAD2"; printf " %3d%% @ %s GHz\n" "$RGA_LOAD2" "${RGA_FREQ2:-N/A}"
    
    # ========== 新增:所有温度传感器列表 ==========
    echo -e " \n All Thermal Sensors:"
    for zone in /sys/class/thermal/thermal_zone*; do
      printf "  %-20s %s\n" "$(cat $zone/type):" "$(awk '{printf "%.1f°C", $1/1000}' $zone/temp)"
    done
    # ==============================================

    echo -e "--------------------"
    echo -e " Press Ctrl+C to exit..."

    sleep $REFRESH_TIME
done

七、其他优化配置及问题

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐