hiyah folks.
Does anyone know how to control the fan speed on the new hackergadget mainboard?
Are there any scripts that can do it? sensors-detect doesn’t show anything.
maybe @vileer can comment?
The fan’s PWM control pin was connected to GPIO_3V3_PWM (pin 218).
Here is an AI-generated code for the Radxa CM5 that has been tested that works. Please ingore the Chinese comment.
#!/usr/bin/env python3
import os
import time
import threading
import select
# --- 配置区域 ---
GPIO_PWM = 125 # GPIO3_D5
# 温控配置 (温度: 占空比%)
# 格式: (阈值温度, 对应的风扇速度0-100)
TEMP_STEPS = [
(40, 0), # 低于40度停转
(50, 30), # 50度时 30%转速
(60, 50), # 60度时 50%转速
(70, 80), # 70度时 80%转速
(80, 100) # 80度以上全速
]
PWM_FREQ = 1000 # PWM频率 Hz (软件PWM建议不要太高,20-100Hz比较稳定,太高CPU占用大)
# 注意:普通4线风扇通常建议25kHz,但软件GPIO无法达到且稳定。
# 如果风扇有噪音,尝试将频率降低到 50 或 100。
# --- GPIO 工具函数 ---
def export_gpio(gpio):
path = f"/sys/class/gpio/gpio{gpio}"
if not os.path.exists(path):
try:
with open("/sys/class/gpio/export", "w") as f:
f.write(str(gpio))
except OSError:
print(f"Warn: GPIO {gpio} already exported or busy.")
def set_direction(gpio, direction):
# direction: "out" or "in"
path = f"/sys/class/gpio/gpio{gpio}/direction"
try:
with open(path, "w") as f:
f.write(direction)
except OSError:
pass
def set_edge(gpio, edge):
# edge: "none", "rising", "falling", "both"
path = f"/sys/class/gpio/gpio{gpio}/edge"
try:
with open(path, "w") as f:
f.write(edge)
except OSError:
pass
# --- 功能类 ---
class FanController:
def __init__(self):
self.running = True
self.current_duty = 0
self.rpm = 0
# 初始化GPIO
export_gpio(GPIO_PWM)
set_direction(GPIO_PWM, "out")
def get_cpu_temp(self):
try:
with open("/sys/class/thermal/thermal_zone0/temp", "r") as f:
return int(f.read()) / 1000.0
except:
return 50.0 # 默认安全值
def pwm_loop(self):
"""软件PWM线程"""
pwm_path = f"/sys/class/gpio/gpio{GPIO_PWM}/value"
period = 1.0 / PWM_FREQ
while self.running:
duty = self.current_duty
if duty >= 100:
with open(pwm_path, "w") as f: f.write("1")
time.sleep(0.1)
elif duty <= 0:
with open(pwm_path, "w") as f: f.write("0")
time.sleep(0.1)
else:
on_time = period * (duty / 100.0)
off_time = period - on_time
# 简单的软件PWM循环
try:
with open(pwm_path, "w") as f: f.write("1")
time.sleep(on_time)
with open(pwm_path, "w") as f: f.write("0")
time.sleep(off_time)
except:
pass
def update_speed_strategy(self):
"""根据温度更新目标转速"""
temp = self.get_cpu_temp()
target_duty = 0
# 简单的阶梯控制
for threshold, duty in TEMP_STEPS:
if temp >= threshold:
target_duty = duty
else:
break
# 滞后处理(防止在临界点频繁跳动),这里简单直接赋值
self.current_duty = target_duty
return temp
def start(self):
t_pwm = threading.Thread(target=self.pwm_loop)
t_pwm.start()
print(f"Fan Control Started. PWM Pin: {GPIO_PWM}")
try:
while True:
temp = self.update_speed_strategy()
# 打印状态,使用 \r 覆盖当前行
print(f"Temp: {temp:.1f}°C | Speed: {self.current_duty}%", end="\r")
time.sleep(2)
except KeyboardInterrupt:
print("\nStopping...")
self.running = False
t_pwm.join()
# 退出前关闭风扇或全开,视安全需求而定
with open(f"/sys/class/gpio/gpio{GPIO_PWM}/value", "w") as f: f.write("0")
if __name__ == "__main__":
# 需要root权限运行
if os.geteuid() != 0:
print("Error: This script must be run as root (sudo).")
exit(1)
controller = FanController()
controller.start()
Run it with sudo, and your fan will spin based on your CPU temperature.
thanks @vileer. i understand the comments in chinese and its not a problem ![]()
However, when i try to run the code (root), pin 125 doesn’t seem to exist. Should i be changing that to 218? i tried either, but it doesn’t seem to make a difference.
Trying to manually export pin 125 or 218 also results in “write error: invalid argument”
if it helps, i’m on ubuntu. and my gpio directory shows the following.
export gpiochip512 gpiochip527 gpiochip533 gpiochip565 gpiochip569 unexport
of all of these, only gpiochip569 has a different label of pinctrl-rp1. the others all have gpio-brcmstb@XXXXX
any thoughts?
Sorry, I thought you mentioned the Radxa CM5. On the Raspberry Pi CM5, you don’t need to do anything; the system controls the fan automatically. If you want to change the profile of it. Please check this link: https://raspberrypi.stackexchange.com/questions/145927/raspberry-pi-5-edit-modify-temperature-limit-for-the-active-cooler-fan.
Thank @vileer!
works great.
Added the following to my /boot/firmware/config.txt and it now maps the way i want it. Appreciate the quick response as always!
# PWM fan control
dtparam=fan_temp0=45000
dtparam=fan_temp0_hyst=1500
dtparam=fan_temp0_speed=75
dtparam=fan_temp1=53000
dtparam=fan_temp1_hyst=2500
dtparam=fan_temp1_speed=127
dtparam=fan_temp2=58000
dtparam=fan_temp2_hyst=3500
dtparam=fan_temp2_speed=191
dtparam=fan_temp3=63000
dtparam=fan_temp3_hyst=4500
dtparam=fan_temp3_speed=255