I have a Raspberry Pi 5 with the official cooler/fan. The firmware enables it from 50°C and up in different steps. I'd like to control it manually, which is possible by writing the steps to /sys/class/thermal/cooling_device0/cur_state
:
echo '4' | sudo tee -a /sys/class/thermal/cooling_device0/cur_state
0
disables the fan, while 1
is the first 50°C step (30% speed), 2
the second (50%) and so on. 4
is the last one, which leads to 100% fan speed. This works, but only for 1-2 seconds. It seems that the firmware is resetting my custom changes.
What doesn't work
I tried to disable the fan in the /boot/config.txt
:
$ grep cooling /boot/config.txt
dtparam=cooling_fan=off
Using pinctrl
it's possible to set some changes, which are not overwritten by the firmware:
# Disabling the fan
pinctrl FAN_PWM op dh
# 100% fan speed
pinctrl FAN_PWM op dl
# Letting the firmware automatically control the fan again
pinctrl FAN_PWM a0
This works until the next reboot. But I'm very limited, since I can only choose between 0% (fan disabled) and 100% fan speed.
My question
How can we disable the automatic firmware, so that the 4 steps (+1 to disable) in /sys/class/thermal/cooling_device0/cur_state
are kept longer (at least to the next reboot) instead of just for 1-2 seconds?
2 Answers 2
I also searched for a few days and didn't find what I was looking for.
So for me (with the official Raspbian) and without any modifications it actually works amazingly easy.
I use the official case with integrated fan.
I don't know if I'm allowed to post the link where I found the solution.
So just for your information:
Disable the fan:
pinctrl FAN_PWM op dh
100% fan speed:
pinctrl FAN_PWM op dl
Let the firmware automatically control the fan again:
pinctrl FAN_PWM a0
To change the fan control, you must edit the file /boot/firmware/config.txt
.
Information about the settings, from /boot/firmware/overlays/README:
fan_temp0
: Temperature threshold (in millicelcius) for 1st cooling level (default 50000). Pi5 only.fan_temp0_hyst
: Temperature hysteresis (in millicelcius) for 1st cooling level (default 5000). Pi5 only.fan_temp0_speed
: Fan PWM setting for 1st cooling level (0-255, default 75). Pi5 only.fan_temp1
: Temperature threshold (in millicelcius) for 2nd cooling level (default 60000). Pi5 only.fan_temp1_hyst
: Temperature hysteresis (in millicelcius) for 2nd cooling level (default 5000). Pi5 only.fan_temp1_speed
: Fan PWM setting for 2nd cooling level (0-255, default 125). Pi5 only.fan_temp2
: Temperature threshold (in millicelcius) for 3rd cooling level (default 67500). Pi5 only.fan_temp2_hyst
: Temperature hysteresis (in millicelcius) for 3rd cooling level (default 5000). Pi5 only.fan_temp2_speed
: Fan PWM setting for 3rd cooling level (0-255, default 175). Pi5 only.fan_temp3
: Temperature threshold (in millicelcius) for 4th cooling level (default 75000). Pi5 only.fan_temp3_hyst
: Temperature hysteresis (in millicelcius) for 4th cooling level (default 5000). Pi5 only.fan_temp3_speed
: Fan PWM setting for 4th cooling level (0-255, default 250). Pi5 only.
Simply insert the following at the end.
dtparam=fan_temp0=47000
dtparam=fan_temp0_hyst=6000
dtparam=fan_temp0_speed=165
You have to set all 4 (changing the number from 0 to 1/2/3 and your speeds and timings.
Sorry, I would just like to write the text here as normal and send my config. However, this editor is completely buggy. With the above description text I could copy-paste and with my config now again not without always having everything in an extra paragraph.
Unfortunately, I cannot simply use every single line of the editor. Quite strange. But this is also my first time here. I registered to answer this question.
-
My setting is this: dtparam=fan_temp0=47000 dtparam=fan_temp0_hyst=6000 dtparam=fan_temp0_speed=165 dtparam=fan_temp1=52000 dtparam=fan_temp1_hyst=6000 dtparam=fan_temp1_speed=190 dtparam=fan_temp2=57000 dtparam=fan_temp2_hyst=6000 dtparam=fan_temp2_speed=215 dtparam=fan_temp3=61000 dtparam=fan_temp3_hyst=6000 dtparam=fan_temp3_speed=255 Getting temperatures with low usage at 46°C and with 100% at 62°CH-OS– H-OS2024年02月04日 00:46:03 +00:00Commented Feb 4, 2024 at 0:46
TLDR: I created a little bash script to manually take control of the fan here
Details
You can provide fixed control by manually setting the pwm config for the respective PWM controller. To do so, you have to first unload the pwm_fan
driver
$ rmmod pwm_fan
You can then export and activate the pwm channel and manually set the fan speed. First you have to identify the correct controller and channel. Here its PWM1_CHAN3
.
$ pinctrl FAN_PWM
45: a0 pd | hi // FAN_PWM/GPIO45 = PWM1_CHAN3
You then export the channel for usage via sysfs
$ cd /sys/class/pwm/pwmchip0
$ echo 3 > export
You should now see /sys/class/pwm/pwmchip0/pwm3
$ ls /sys/class/pwm/pwmchip0/pwm3/
capture duty_cycle enable period polarity power uevent
Finally, you need to enable the channel and set a duty_cycle
$ echo 1 > enable
$ echo 10000 > duty_cycle
The fan should now spin at a low rate, where higher values written to duty_cycle
mean higher RPM. The common settings 1-4 available via echo '4' | sudo tee -a /sys/class/thermal/cooling_device0/cur_state
correspond roughly to 10000, 20000, 30000 and 40000, respectively. See the period
below, for the maximum legal value.
Notes
I am using Ubuntu Server 23.10 64bit on my Pi5. So yours may be slightly different if using another OS.
I would assume there is an easier way to achieve this, but I haven't found it yet.
It seems that after unloading the
pwm_fan
driver, there is no way of monitoring the actual fan speed.The specific numbers (e.g. number of the pwm channel, period for the pwm channel, etc. may be different on your device.
A more detailed explanation of the sysfs interface for pwm can be found here
My final configuration for a non-audible fan looks like this
$ tail -n +1 enable polarity period duty_cycle ==> enable <== 1 ==> polarity <== inversed ==> period <== 41566 ==> duty_cycle <== 15000
where
duty_cycle
andperiod
are numbers in nanoseconds andduty_cycle
configures the fan speed, meaning the fan spins at 100% ifduty_cycle
is set to 41566. In my case, the fan starts spinning around a duty cycle of roughly 5000 (yours may be different).
pinctrl FAN_PWM op dh
disables/sys/class/thermal/cooling_device0/cur_state
becauseecho '4' | sudo tee -a /sys/class/thermal/cooling_device0/cur_state
doesn't have any effect any more. And the file keeps4
even after several seconds, so no firmware touch it, but it seems also not to be used.