Hi everyone, Prageeth here.
I am currently using Khadas VIM1 boards for a custom hardware project. I recently upgraded to Armbian Linux (6.12.58-current-meson64) and ran into a challenge getting the cooling fan to work automatically. I wanted to share my troubleshooting experience and the final solution in case anyone else runs into the same issue.
Hardware Used
For this setup, I am using the official Khadas cooling accessories:
-
Board: Khadas VIM1
-
Fan: 3705 Cooling Fan
-
Heatsink: New VIMs Heatsink
The Problem
When plugging the cooling fan into the fan header, it wouldn’t spin up automatically under load. I initially tried exporting standard PWM chips (/sys/class/pwm/pwmchip0) and using standard Linux utilities like fancontrol and pwmconfig, but the system would throw “Device busy” or “Permission denied” errors, or simply fail to spin the fan.
The Discovery
After digging into the VIM1 schematics (v14), I realized why standard Linux PWM controls were failing. The FAN_PWM header is not directly connected to the S905X processor’s PWM pins.
Instead, it is wired to the onboard STM8S MCU (U20). The S905X communicates with this MCU via I2C (I2C_B). Therefore, to control the fan, you have to bypass standard PWM drivers and send direct hex commands to the MCU over the I2C bus.
Here is the mapping for the Khadas VIM1 MCU:
-
I2C Bus: 1
-
MCU Address:
0x18 -
Fan Control Register:
0x88 -
Values:
0x00(Off),0x01(Low Speed),0x03(High Speed)
The Solution: A Custom Thermostat Script
To get the fan acting normally, I wrote a lightweight bash script and systemd service to monitor the CPU temperature and send the correct I2C commands. It uses a 3-stage logic with built-in hysteresis to prevent the fan from turning on and off rapidly.
Step 1: Install Dependencies
You will need i2c-tools to talk to the MCU.
Bash
sudo apt update
sudo apt install i2c-tools -y
Step 2: Create the Control Script
Create a new script file:
Bash
sudo nano /usr/local/bin/vim1_cooler.sh
Paste in the following code. (This configuration turns the fan off below 50°C, runs it at low speed at 60°C, and kicks it into high speed at 70°C).
Bash
#!/bin/bash
# --- Thermal Thresholds (Millidegrees) ---
MAX_T=70000 # 70°C - Full Speed
MID_T=60000 # 60°C - Start Fan / Low Speed
MIN_T=50000 # 50°C - Turn Off
# --- I2C Hex Values ---
VAL_STOP=0x00
VAL_SLOW=0x01
VAL_FAST=0x03
# --- Hardware Map ---
I2C_B=1
I2C_A=0x18
I2C_R=0x88
TEMP_SRC="/sys/class/thermal/thermal_zone0/temp"
MODE=0
# Ensure fan is off at start
i2cset -y $I2C_B $I2C_A $I2C_R $VAL_STOP
echo "Cooling daemon active."
while true; do
CUR_T=$(cat $TEMP_SRC)
# CASE 1: > 70C -> FULL SPEED
if [ "$CUR_T" -ge "$MAX_T" ]; then
if [ "$MODE" -ne 3 ]; then
i2cset -y $I2C_B $I2C_A $I2C_R $VAL_FAST
MODE=3
fi
# CASE 2: > 60C -> LOW SPEED
elif [ "$CUR_T" -ge "$MID_T" ]; then
if [ "$MODE" -ne 1 ]; then
i2cset -y $I2C_B $I2C_A $I2C_R $VAL_SLOW
MODE=1
fi
# CASE 3: < 50C -> TURN OFF
elif [ "$CUR_T" -le "$MIN_T" ]; then
if [ "$MODE" -ne 0 ]; then
i2cset -y $I2C_B $I2C_A $I2C_R $VAL_STOP
MODE=0
fi
fi
# Check every 3 seconds
sleep 3
done
Save the file. Make sure to fix the permissions and line endings so systemd can execute it:
Bash
sudo chmod +x /usr/local/bin/vim1_cooler.sh
sudo sed -i 's/\r$//' /usr/local/bin/vim1_cooler.sh
Step 3: Create the Systemd Service
To make this run automatically on boot, create a service file:
Bash
sudo nano /etc/systemd/system/vim1-cooler.service
Paste the following:
Ini, TOML
[Unit]
Description=VIM1 I2C Cooling Daemon
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/local/bin/vim1_cooler.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Finally, enable and start the service:
Bash
sudo systemctl daemon-reload
sudo systemctl enable vim1-cooler.service
sudo systemctl start vim1-cooler.service
You can check sudo systemctl status vim1-cooler.service to ensure it is running without errors.
I hope this saves some time for anyone else building projects on Armbian with the VIM1!
Cheers, Prageeth