Banana pi BPI-R3 can not control pwm fan

Chiming in in this as I face the same kernel log entries on my BPI-R3 running OpenWrt 23.05.03. Though, I recall that support for the used kernel in that aversion wasn’t quite ready if operational et all.

Did anyone by chance made some progress about this subject?

Hi

After a few weeks of use, this script no longer works (located in /etc/init.d). The script won’t start at boot, shows always as “deactivated” by luci

# BpiR3 Fancontrol-Script
#
# chmod +x /etc/init.d/fancontrol
# /etc/init.d/fancontrol enable
# /etc/init.d/fancontrol start


#!/bin/sh /etc/rc.common

START=99
PIDFILE="/var/run/fan_control.pid"
TEMP_PATH="/sys/class/thermal/thermal_zone0/temp"
PWM_PATH="/sys/class/hwmon/hwmon2/pwm1"

# Settings
HYST=2000        # 2°C Hysteresis
LOW_TEMP=50000   # 50°C (Threshold to start fan)
HIGH_TEMP=70000  # 70°C (Threshold for max speed)
MIN_RUN_PWM=90   # Slowest active speed
MAX_RUN_PWM=10   # Fastest active speed
STOP_PWM=255     # PWM value for OFF

fan_loop() {
    # Initialize state
    CURRENT_PWM=$(cat "$PWM_PATH" 2>/dev/null || echo "$STOP_PWM")
    
    while true; do
        [ -f "$TEMP_PATH" ] || { sleep 10; continue; }
        TEMP=$(cat "$TEMP_PATH")

        # 1. Logic for Stopped Fan
        if [ "$CURRENT_PWM" -eq "$STOP_PWM" ]; then
            if [ "$TEMP" -ge "$LOW_TEMP" ]; then
                # Start fan at minimum speed once 50°C is reached
                NEW_PWM=$MIN_RUN_PWM
            else
                NEW_PWM=$STOP_PWM
            fi

        # 2. Logic for Over-temperature (Max Speed)
        elif [ "$TEMP" -ge "$HIGH_TEMP" ]; then
            NEW_PWM=$MAX_RUN_PWM

        # 3. Logic for Cooldown (Stop Fan)
        elif [ "$TEMP" -le $((LOW_TEMP - HYST)) ]; then
            # Only stop if we drop below 48°C (Hysteresis)
            NEW_PWM=$STOP_PWM

        # 4. Linear Interpolation Range (50°C - 70°C)
        else
            # Calculate PWM between 90 (at 50°C) and 10 (at 70°C)
            NEW_PWM=$((MIN_RUN_PWM - (TEMP - LOW_TEMP) * (MIN_RUN_PWM - MAX_RUN_PWM) / (HIGH_TEMP - LOW_TEMP)))
            
            # Ensure we don't accidentally send STOP_PWM (255) during interpolation
            [ "$NEW_PWM" -gt "$MIN_RUN_PWM" ] && NEW_PWM=$MIN_RUN_PWM
            [ "$NEW_PWM" -lt "$MAX_RUN_PWM" ] && NEW_PWM=$MAX_RUN_PWM
        fi

        # Apply change only if value changed to save I/O
        if [ "$NEW_PWM" -ne "$CURRENT_PWM" ]; then
            echo "$NEW_PWM" > "$PWM_PATH" 2>/dev/null
            CURRENT_PWM=$NEW_PWM
        fi

        sleep 10
    done
}

start() {
    [ -f "$PIDFILE" ] && return
    echo "Starting dynamic fan control (Stop < 50°C, Hysteresis enabled)..."
    fan_loop &
    echo $! > "$PIDFILE"
}

stop() {
    if [ -f "$PIDFILE" ]; then
        kill $(cat "$PIDFILE")
        rm "$PIDFILE"
        # Optional: Set fan to a safe speed on service stop
        echo "$MIN_RUN_PWM" > "$PWM_PATH" 2>/dev/null
    fi
}

Manual test was succesful:

echo 95 > /sys/class/hwmon/hwmon2/pwm1

Do you guys have any idea what’s going wrong? Thanks

I think you should use cat /sys/class/thermal/thermal_zone0/temp to check the actual temperature to determine which temperature the script is running at.