背景
Raspberry PiにPWM制御可能なファンを取り付けている場合、PythonでGPIOピンをPWM制御する方法などが検索にヒットするが、OSに組み込まれている仕組みを使って簡単に実現できることがわかった。
本記事の内容は、ほぼ以下ページに記載がある。
環境
- Raspberry Pi 4B
- Raspberry Pi OS (Bookworm)
- Linux rpi4b 6.6.28+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.28-1+rpt1 (2024-04-22) aarch64 GNU/Linux
手順
ソースの取得と変更
上記ページ内の pwm-fan-overlay.dts
を取得し、Raspberry Piにコピーする
上記ページ内のpwm-fan-overlay.dts
/*
* Overlay for a Raspberry Pi PWM Fan
* References:
*
* Optional parameters:
*
* pwm-fan-overlay.dts
*/
/dts-v1/;
/plugin/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/thermal/thermal.h>
#include <dt-bindings/pinctrl/bcm2835.h>
/ {
compatible = "brcm,bcm2835";
fragment@0 {
target = <&gpio>;
__overlay__ {
pwm_pins: pwm_pins {
brcm,pins = <18>;
brcm,function = <BCM2835_FSEL_ALT5>;
brcm,pull = <0>;
};
};
};
fragment@1 {
target = <&pwm>;
frag1: __overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pwm_pins>;
/* in Hz */
assigned-clock-rates = <100000000>;
status = "okay";
};
};
fragment@2 {
target-path = "/";
__overlay__ {
fan: pwm-fan {
compatible = "pwm-fan";
#cooling-cells = <2>;
/* in ns */
pwms = <&pwm 0 20000000 0>;
cooling-min-state = <0>;
cooling-max-state = <4>;
/* PWM duty cycle values in a range from 0 to 255
* which correspond to thermal cooling states
*/
cooling-levels = <0 75 125 175 250>;
};
};
};
fragment@3 {
target = <&cpu_thermal>;
__overlay__ {
polling-delay = <2000>; /* milliseconds */
};
};
fragment@4 {
target = <&thermal_trips>;
__overlay__ {
trip0: trip0 {
temperature = <40000>;
hysteresis = <2000>;
type = "active";
};
trip1: trip1 {
temperature = <45000>;
hysteresis = <2000>;
type = "active";
};
trip2: trip2 {
temperature = <50000>;
hysteresis = <2000>;
type = "active";
};
trip3: trip3 {
temperature = <55000>;
hysteresis = <5000>;
type = "active";
};
};
};
fragment@5 {
target = <&cooling_maps>;
__overlay__ {
map0 {
trip = <&trip0>;
cooling-device = <&fan 0 1>;
};
map1 {
trip = <&trip1>;
cooling-device = <&fan 1 2>;
};
map2 {
trip = <&trip2>;
cooling-device = <&fan 2 3>;
};
map3 {
trip = <&trip3>;
cooling-device = <&fan 3 4>;
};
};
};
__overrides__ {
fan_temp0 = <&trip0>,"temperature:0";
fan_temp0_hyst = <&trip0>,"hysteresis:0";
fan_temp0_speed = <&fan>, "cooling-levels:4";
fan_temp1 = <&trip1>,"temperature:0";
fan_temp1_hyst = <&trip1>,"hysteresis:0";
fan_temp1_speed = <&fan>, "cooling-levels:8";
fan_temp2 = <&trip2>,"temperature:0";
fan_temp2_hyst = <&trip2>,"hysteresis:0";
fan_temp2_speed = <&fan>, "cooling-levels:12";
fan_temp3 = <&trip3>,"temperature:0";
fan_temp3_hyst = <&trip3>,"hysteresis:0";
fan_temp3_speed = <&fan>, "cooling-levels:16";
};
};
必要に応じて編集する場所
ピン番号
brcm,pins = <18>;
の部分がPWM制御をするピン番号。
18
はGPIO18(=12番ピン)を表す。
ここを変更した場合は、brcm,function = <BCM2835_FSEL_ALT5>;
も変更する必要があると考えられる。(未確認)
PWM周波数
fragment@2
内のpwms = <&pwm 0 20000000 0>;
の部分のうち、20000000
がPWMの周期(ns)なので、ファンからノイズが聞こえる場合などは変更する。
20000000
は 50Hz であり、私のファンではノイズがあったので 40000
(=25000Hz)に変更した。
コンパイル
プリプロセッサを通す
#include
となっている部分はcpp
を使って事前に処理を行う。
$ cpp -nostdinc -undef -x assembler-with-cpp -I /usr/src/linux-headers-6.6.28+rpt-common-rpi/include/ -o pwm-fan-overlay.tmp.dts pwm-fan-overlay.dts
※ヘッダーファイルの位置は各自の環境に合わせて変更する
コンパイル
dtc
コマンドを使用する
$ dtc -O dtb -o pwm-fan.dtbo pwm-fan-overlay.tmp.dts
インストール
ファイルを配置
$ sudo mv pwm-fan.dtbo /boot/firmware/overlays/
※警告が出るが無視して問題なかった
設定
/boot/firmware/config.txt
で pwm-fan
を読み込むように変更
...
dtoverlay=pwm-fan
設定変更
config.txt
内で、以下の記法でパラメータを変更できる。
dtoverlay=pwm-fan
dtparam=fan_temp0=55000
dtparam=fan_temp0_hyst=5000
dtparam=fan_temp0_speed=75
dtparam=fan_temp1=62500
dtparam=fan_temp1_hyst=5000
dtparam=fan_temp1_speed=128
dtparam=fan_temp2=70000
dtparam=fan_temp2_hyst=5000
dtparam=fan_temp2_speed=192
dtparam=fan_temp3=77500
dtparam=fan_temp3_hyst=5000
dtparam=fan_temp3_speed=255
再起動
$ sudo reboot