Raspberry Pi[58] PWM
ラズパイ4にはPWMチャンネルが2つあります。また、制御方法にハードウエアPWMとソフトウエアPWMの2種類があり、ハードウエアPWMはピンが決まっています。↓ こんな感じ
GPIO番号 | 物理ピン | PWMチャネル | pigpioで使える? |
---|---|---|---|
18 | 12 | PWM0_0 | ✅ yes |
13 | 33 | PWM1_1 | ✅ yes |
19 | 35 | PWM0_1 | ✅ yes |
12 | 32 | PWM1_0 | ✅ yes |
一つのチャンネルにピンが2つづつ割り当てられているので、同じチャンネルなら二つのピンから出力ができます。つまり、全部で4つのピンでハードウエアPWMができるようです。チャンネルが同じということはPWMの設定が同じということなので、出力も基本同じになるように思えますが、実は、Duty は個別でできるようです。周波数は変えることができないみたい。
gpioHardwarePWM() を見てみると、
gpioHardwarePWM(GPIO番号, 周波数, Duty) // こんな感じ
GPIO番号は上の表のとおりです。pigpioの仕様では周波数は最大で約125MHz(ただし条件あり)。デューティ比の最大値は:
1000000(=100万) が最大→ これは 「100%」に相当します!
ですが、周波数が高くなると、デューティ比の分解能が粗くなる(100万分の1ではなくなる)
周波数 | 周期 | 分解能(理論上) | duty 1000000の意味 |
---|---|---|---|
1kHz | 1ms | 1ns単位 | ちゃんと使える ✅ |
100kHz | 10μs | 10ns単位 | ギリギリOK 🟡 |
1MHz | 1μs | 1ns単位必要 | 分解能足りない ❌ |
10MHz | 100ns | 0.1ns必要 | 現実的に不可能 ❌ |
1Hz〜10kHzが安定しているみたい。以下はサンプルプログラムです。
#include <stdio.h>
#include <unistd.h>
#include <pigpio.h>
int main()
{
if (gpioInitialise() < 0) {
fprintf(stderr, "pigpioの初期化に失敗しました。\n");
return 1;
}
int gpio = 18;
int freq = 1000;
int duty;
printf("フェード確認開始(5段階)\n");
// 明るく5ステップ
for (duty = 0; duty <= 1000000; duty += 250000) {
gpioHardwarePWM(gpio, freq, duty);
printf("duty = %d\n", duty);
sleep(1);
}
// 暗く
for (duty = 1000000; duty >= 0; duty -= 250000) {
gpioHardwarePWM(gpio, freq, duty);
printf("duty = %d\n", duty);
sleep(1);
}
gpioHardwarePWM(gpio, 0, 0);
gpioSetMode(gpio, PI_OUTPUT);
gpioWrite(gpio, 0);
gpioTerminate();
printf("終了\n");
return 0;
}
make はこんな感じ
gcc -o pwm_led pwm_led.c -lpigpio -lrt -lpthread
プログラムを動かすには、sudo がいります。理由はハードウェアPWMは SoC のレジスタを直接操作するから
gpioHardwarePWM() は BCM283x の PWM レジスタを直接叩いてる。そのため /dev/mem や /dev/gpiomem を使ってて、これには 管理者権限が必要らしいです。これが、いやな人はデーモン化して呼び出せばいいと思う。私はまだやっていないけど。
pigpio には実は公式の「pigpiod」というデーモンがあるらしいけど、gpioHardwarePWM()はダメっぽい。
ソフトウエアPWMなら、gpioPWM()を使って、ユーザーモードで動くみたい。LED制御程度ならそれでもいいかもね。