雑記帳

整理しない情報集

更新情報

ラズパイの公式ケースファンをPWM制御する

公開日:

カテゴリ: Raspberry Pi

ラズパイの公式ケースファンを説明書通りに使うと、OFFか全力稼働の2択で動作します。小型ファンは全力稼働すると結構な騒音なのでPWM制御してみます。

といいつつも、方法は以下のサイトに載っていることをそのまま実行しているだけです。

本記事はRaspberry Pi 4B向けとなります。

GPIOの接続を変える

GPIOでPWM制御を行うには、PWM制御に割り当てられたピンに制御用のケーブルを接続する必要があります。

ラズパイの公式ケースファンの説明書通りに組み立て・接続している場合、8番ピン(GPIO14)に接続していると思いますが、このピンはPWM制御には対応していません。

対応していないピンでON/OFFの制御をしている場合、PWM制御に対応しているピンに変更します。挿し替える前に公式設定ツールでのファン制御は切っておきます。

# 対話方式で設定する場合
sudo raspi-config
# Performance Options -> P3 Fan -> No

# コマンドで設定する場合
sudo raspi-config nonint do_fan 1

どのピンに挿せばPWM制御できるかは公式ドキュメントに記載があります。4Bの場合、BCM2711の公式ドキュメントの「5.3. Alternative Function Assignments」に一覧があります。以下折りたたみに抜粋します。

GPIOPullALT0ALT1ALT2ALT3ALT4ALT5
GPIO12LowPWM0_0SD4DPI_D8SPI5_CE0_NTXD5SDA5
GPIO13LowPWM0_1SD5DPI_D9SPI5_MISORXD5SCL5
GPIO18LowPCM_CLKSD10DPI_D14SPI6_CE0_NSPI1_CE0_NPWM0_0
GPIO19LowPCM_FSSD11DPI_D15SPI6_MISOSPI1_MISOPWM0_1
GPIO40*LowPWM1_0SD4SD1_DAT4SPI0_MISOTXD1
GPIO41*LowPWM1_1SD5<予約>SD1_DAT5SPI0_MOSIRXD1
GPIO45*-PWM0_1SCL0SCL1<予約>SPI0_CE2_NSD_CARD_PWR0

※GPIO28以降はボード上にピンが存在しない(プロセッサからピンを接続していない)ため、基本的に使えません

上記のピンのいずれかにPWM制御用のケーブル(大抵のファンは青いケーブル)を接続します。物理ピン番号とGPIO番号は同じ番号ではないので注意が必要です(対照表)。

GPIO物理ピン
GPIO1232
GPIO1333
GPIO1812
GPIO1935
GPIO40*
GPIO41*
GPIO45*

※GPIO28以降はボード上にピンが存在しない(プロセッサからピンを接続していない)ため、基本的に使えません

本記事では触れませんが、Raspberry Pi 5にはファンの専用端子があり、GPIOを使わなくても制御できるようですので、もっとシンプルにできると思います。

ファイル編集

フォーラムからソースを取得してきて保存します。

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";
	};
};

フォーラム掲載のソースはソース内でピン番号や動作モードを指定しています。掲載されているソースは18番ピンに接続した場合のソースであるため、それ以外のピンを使用している場合はコンパイル前に挿したピンに合わせてファイルを編集する必要があります。

// ピン番号
brcm,pins = <18>;

// 動作モード
brcm,function = <BCM2835_FSEL_ALT5>;

動作モードはLinuxヘッダーのソースを見に行くと定義があります。GPIO18/GPIO19以外を使用してPWM制御する場合はALT0モードですので<BCM2835_FSEL_ALT0>を指定することになるでしょう。

コンパイル

Linuxのヘッダーファイルのバージョンは適宜置き換えてください。

# プリプロセッサ
cpp -nostdinc -undef -x assembler-with-cpp -I /usr/src/linux-headers-6.12.25+rpt-common-rpi/include/ -o pwm-fan-overlay.tmp.dts pwm-fan-overlay.dts

# コンパイル
dtc -O dtb -o pwm-fan.dtbo pwm-fan-overlay.tmp.dts

デバイスツリーに登録

コンパイルしたファイルをデバイスツリーに登録します。

sudo cp pwm-fan.dtbo /boot/firmware/overlays/

pwm-fanを有効化するため、エディタで次の設定ファイルを開きます。

sudo nano /boot/firmware/config.txt

設定ファイルに以下の記述を追記します。

[pi4]
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

[pi4]はラズパイ4向けの設定の意味です。今回の場合は無くても動きますが、他のデバイス向けのセクションに書かないようにしましょう。

  • fan_tempNはファンを回す温度の閾値(温度*1000)
  • fan_tempN_hystは閾値からファンを止めるまでの温度変化(温度*1000)
  • fan_tempN_speedはファンの回転率(0-255)

fan_tempNN=0~3を閾値として、計5段階で回転率を調整できます。上記の例では、55度・62.5度・70度・77.5度を閾値として、0%(停止)・30%・50%・75%・100%の回転率で稼働します。

sudo reboot

設定後、再起動して完了です。

カテゴリ: Raspberry Pi