# Fan control speed control on Hackergadget board (CM5)?

**URL:** <https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356>\
**Category:** uConsole\
**Created:** [February 2, 2026, 9:25am UTC](https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356 "2026-02-02T09:25:15Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bored99](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@bored99](https://forum.clockworkpi.com/u/bored99)\
**Post date:** [February 2, 2026, 9:25am UTC](https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356/1 "2026-02-02T09:25:15Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![vileer](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.clockworkpi.com/vileer/32/10337_2.png) [@vileer](https://forum.clockworkpi.com/u/vileer)\
**Post date:** [February 3, 2026, 9:01am UTC](https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356/2 "2026-02-03T09:01:22Z")

</div>

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.

```python
#!/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.

---

<div class="post-metadata">

**Author:** ![bored99](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@bored99](https://forum.clockworkpi.com/u/bored99)\
**Post date:** [February 4, 2026, 5:10am UTC](https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356/3 "2026-02-04T05:10:16Z")

</div>

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.

```auto
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?

---

<div class="post-metadata">

**Author:** ![vileer](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.clockworkpi.com/vileer/32/10337_2.png) [@vileer](https://forum.clockworkpi.com/u/vileer)\
**Post date:** [February 4, 2026, 5:19am UTC](https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356/4 "2026-02-04T05:19:05Z")

</div>

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](https://raspberrypi.stackexchange.com/questions/145927/raspberry-pi-5-edit-modify-temperature-limit-for-the-active-cooler-fan).

---

<div class="post-metadata">

**Author:** ![bored99](https://avatars.discourse-cdn.com/v4/letter/b/919ad9/32.png) [@bored99](https://forum.clockworkpi.com/u/bored99)\
**Post date:** [February 4, 2026, 6:50am UTC](https://forum.clockworkpi.com/t/fan-control-speed-control-on-hackergadget-board-cm5/21356/5 "2026-02-04T06:50:41Z")

</div>

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!

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

```
