Raspberry Pi[58] PWM

ラズパイ4にはPWMチャンネルが2つあります。また、制御方法にハードウエアPWMとソフトウエアPWMの2種類があり、ハードウエアPWMはピンが決まっています。↓ こんな感じ

GPIO番号物理ピンPWMチャネルpigpioで使える?
1812PWM0_0✅ yes
1333PWM1_1✅ yes
1935PWM0_1✅ yes
1232PWM1_0✅ yes

一つのチャンネルにピンが2つづつ割り当てられているので、同じチャンネルなら二つのピンから出力ができます。つまり、全部で4つのピンでハードウエアPWMができるようです。チャンネルが同じということはPWMの設定が同じということなので、出力も基本同じになるように思えますが、実は、Duty は個別でできるようです。周波数は変えることができないみたい。

gpioHardwarePWM() を見てみると、

gpioHardwarePWM(GPIO番号, 周波数, Duty) // こんな感じ

GPIO番号は上の表のとおりです。pigpioの仕様では周波数は最大で約125MHz(ただし条件あり)。デューティ比の最大値は:
1000000(=100万) が最大→ これは 「100%」に相当します!

ですが、周波数が高くなると、デューティ比の分解能が粗くなる(100万分の1ではなくなる)

周波数周期分解能(理論上)duty 1000000の意味
1kHz1ms1ns単位ちゃんと使える ✅
100kHz10μs10ns単位ギリギリOK 🟡
1MHz1μs1ns単位必要分解能足りない ❌
10MHz100ns0.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制御程度ならそれでもいいかもね。