Sipeed NanoCluster原装风扇:PWM调速教程

AI摘要

Sipeed NanoCluster集群板风扇默认满速噪音大,可通过修改/boot/firmware/config.txt添加PWM overlay,利用Slot 1设备控制转速,并提供手动测试命令与Python自动温控脚本,实现按温度调节风扇。

Sipeed NanoCluster迷你集群板 风扇通电后是满速运行,非常的吵,但是可以通过Slot 1设备来控制风扇转速;

我的是CM4主板,下面是具体的操作;

1、修改/boot/firmware/config.txt文件添加 下面的内容

[all]
dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4

然后重启slot 1的设备

reboot

2、测试控制风扇

# 重启后检查 PWM 是否可用
ls /sys/class/pwm/

# 应该能看到 pwmchip0 和 pwmchip2

# 导出 GPIO13(对应 pwmchip0 的通道 1)
echo 1 | sudo tee /sys/class/pwm/pwmchip0/export 2>/dev/null

# 设置周期和占空比
echo 20000000 | sudo tee /sys/class/pwm/pwmchip0/pwm1/period      # 20ms = 50Hz
echo 8000000 | sudo tee /sys/class/pwm/pwmchip0/pwm1/duty_cycle   # 40% 转速
echo 1 | sudo tee /sys/class/pwm/pwmchip0/pwm1/enable             # 启动

# 关风扇
echo 0 | sudo tee /sys/class/pwm/pwmchip0/pwm1/duty_cycle

# 满速
echo 20000000 | sudo tee /sys/class/pwm/pwmchip0/pwm1/duty_cycle

3、自动温控脚本(Python)

文件位置:/usr/local/bin/fan_control.py,脚本名称:fan_control.py

#!/usr/bin/env python3
"""
fan_control.py - 5V 风扇 PWM 调速控制
迟滞 + 最小运行时间,每 3 秒打印温度

- 温度 >= 46°C -> 风扇启动(20% 起步,按温度曲线调速)
- 温度 < 44°C -> 风扇停转(需满足最小运行时间)
- 44~46°C 之间保持当前状态
- 每 3 秒打印温度到 journal
"""

import time
import os

PWM_CHIP = '/sys/class/pwm/pwmchip0'
PWM_PATH = f'{PWM_CHIP}/pwm1'
PERIOD = 20000000

TEMP_CURVE = [(46, 20), (50, 40), (55, 60), (60, 80), (65, 100)]

FAN_ON_TEMP = 46
FAN_OFF_TEMP = 44
MIN_RUN_SECONDS = 600

def setup_pwm():
    if os.path.exists(PWM_PATH):
        try:
            with open(f'{PWM_CHIP}/unexport', 'w') as f:
                f.write('1')
            time.sleep(0.1)
        except Exception as e:
            print(f'unexport warn: {e}')
    try:
        with open(f'{PWM_CHIP}/export', 'w') as f:
            f.write('1')
        time.sleep(0.3)
    except Exception as e:
        print(f'export err: {e}')
        return False
    for _ in range(20):
        if os.path.exists(f'{PWM_PATH}/period'):
            break
        time.sleep(0.1)
    if not os.path.exists(f'{PWM_PATH}/period'):
        print('PWM init failed')
        return False
    try:
        with open(f'{PWM_PATH}/period', 'w') as f:
            f.write(str(PERIOD))
        with open(f'{PWM_PATH}/enable', 'w') as f:
            f.write('1')
        return True
    except Exception as e:
        print(f'PWM cfg err: {e}')
        return False

def get_temp():
    try:
        with open('/sys/class/thermal/thermal_zone0/temp') as f:
            return float(f.read().strip()) / 1000.0
    except:
        return 50

def set_duty(pct):
    try:
        with open(f'{PWM_PATH}/duty_cycle', 'w') as f:
            f.write(str(int(PERIOD * pct / 100)))
    except Exception as e:
        print(f'duty err: {e}')

if not setup_pwm():
    time.sleep(3)
    if not setup_pwm():
        print('FATAL: PWM init failed')
        import sys; sys.exit(1)

fan_on = False
fan_start_time = 0
cur_duty = -1
print('fan-control started 5V PWM on>=46C off<44C min_run=600s')
while True:
    t = get_temp()

    if not fan_on and t >= FAN_ON_TEMP:
        fan_on = True
        fan_start_time = time.time()
        print(f'{t:.1f}C -> Fan ON (started, min run {MIN_RUN_SECONDS}s)')
    elif fan_on and t < FAN_OFF_TEMP:
        elapsed = time.time() - fan_start_time
        if elapsed >= MIN_RUN_SECONDS:
            fan_on = False
            print(f'{t:.1f}C -> Fan OFF (ran {elapsed:.0f}s)')

    if fan_on:
        d = 20
        for tt, dd in TEMP_CURVE:
            if t >= tt:
                d = dd
    else:
        d = 0

    if d != cur_duty:
        set_duty(d)
        cur_duty = d
        print(f'{t:.1f}C -> Fan {d}% [{"ON" if fan_on else "OFF"}]')

    state = 'ON' if fan_on else 'OFF'
    elapsed = time.time() - fan_start_time if fan_on else 0
    print(f'{t:.1f}C Fan={state}' + (f' run={elapsed:.0f}s' if fan_on else ''))
    time.sleep(3)

4、日志查看

输入命令行下面的命令行, 可以实时查看CM4温度

journalctl -u fan-control.service -f

日志:

Aug 01 12:10:47 Saiita systemd[1]: Stopped fan-control.service - NanoCluster Fan Control.
Aug 01 12:10:47 Saiita systemd[1]: Starting fan-control.service - NanoCluster Fan Control...
Aug 01 12:10:47 Saiita systemd[1]: Started fan-control.service - NanoCluster Fan Control.
Aug 01 12:10:47 Saiita python3[54971]: fan-control started hysteresis on>=46C off<44C min_run=600s
Aug 01 12:10:47 Saiita python3[54971]: 47.2C -> Fan ON (started, min run 600s)
Aug 01 12:10:47 Saiita python3[54971]: 47.2C -> Fan 20% [ON]
Aug 01 12:20:48 Saiita python3[54971]: 39.4C -> Fan OFF (ran 600s)
Aug 01 12:20:48 Saiita python3[54971]: 39.4C -> Fan 0% [OFF]
Aug 01 12:22:08 Saiita python3[54971]: 46.3C -> Fan ON (started, min run 600s)
Aug 01 12:22:08 Saiita python3[54971]: 46.3C -> Fan 20% [ON]

5、设置开机自启动

sudo nano /etc/systemd/system/fan-control.service

写入

[Unit]
Description=NanoCluster Fan Control
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/fan_control.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

然后启用:

sudo systemctl daemon-reload
sudo systemctl enable --now fan-control.service
sudo systemctl status fan-control.service

点赞 1