pigpioでのハードウェアPWMはあまりまとまった情報がなかったので簡単にまとめようと思います。
環境
- Raspberry Pi Zero W
- Raspbian Stretch Lite (Kernel version: 4.9.59+)
ソフトウェアPWM
イメージとしてはこんな感じでPWM波形を出力するのがソフトウェアPWMです。
各種ライブラリではもっといい方法でPWMを出力しているような気がするので、あくまでイメージの話です。
while(True):
出力を1にする
time.sleep(0.25)
出力を0にする
time.sleep(0.75)
この場合だとduty比が0.25になりますね。
ですが関数呼び出し等の遅延やら何やらでズレが生じやすいみたいです。
ハードウェアPWM
実際に測定したわけではないのでなんとも言えませんが、ズレが生じうるソフトウェアPWMよりハードウェアPWMがあるならそっちを使ったほうが安心です。
ハードウェアPWMについては詳しいことは分かりませんが、ハードウェア内部のクロックを利用して比較的正確なPWMを出力するものだと認識しています。
Raspberry PiでのハードウェアPWM
ピン配置: Raspberry Pi Pinout
ハードウェア実装: BCM2835 ARM Peripherals
このあたりを見ると書いてあるんですが、ラズパイではハードウェアPWMに対応しているピンが4つあり、独立に制御できるのは2組ずつです。
古い記述だとラズパイのハードウェアPWMはGPIO18だけ、と書いてあったりするのですが、それはラズパイA、Bの話で、それ以降のモデルでは独立に2つのPWMを出力することができます。
- PWM Channel 0 : GPIO12、GPIO18
- PWM Channel 1 : GPIO13、GPIO19
Channelが同一のピンはPWMを独立に制御できないので、Channel 0を共有しているGPIO12,18は別々のハードウェアPWMを出力できません。
逆に言えば、Channelを共有していれば同一のPWMを出力することができます。
WiringPiでの問題点
面倒なのは、周波数とduty比で指定したいのに、よく分からないclockやらrangeやらの値を指定しなければハードウェアPWMを出力できない、という点です。
また、新しいバージョンのカーネルでWiringPiにハードウェアPWMの設定を行おうとすると落ちる現象が発生するみたいです。僕も落ちました。
この辺の話について、詳しくは以下。
Raspberry Pi : WiringPi-PythonでPWM
カーネルをダウングレードすればいいらしいのですが、まあ面倒なのでpigpioを使ったほうが良いかなと思います。
pigpioを使う
初めて使う場合は以下のサイトが参考になると思います。
Raspberry PiのGPIO制御の決定版 pigpio を試す
公式のpigpioのPythonのドキュメントはこちら。
pigpio library
ハードウェアPWMを2つ独立に制御してみる
GPIO18、19にそれぞれLEDか何かを繋いでみて、ハードウェアPWMを使って光らせてみます。
import pigpio
import time
gpio_pin0 = 18
gpio_pin1 = 19
pi = pigpio.pi()
pi.set_mode(gpio_pin0, pigpio.OUTPUT)
pi.set_mode(gpio_pin1, pigpio.OUTPUT)
# GPIO18: 2Hz、duty比0.5
pi.hardware_PWM(gpio_pin0, 2, 500000)
# GPIO19: 8Hz、duty比0.1
pi.hardware_PWM(gpio_pin1, 8, 100000)
time.sleep(5)
pi.set_mode(gpio_pin0, pigpio.INPUT)
pi.set_mode(gpio_pin1, pigpio.INPUT)
pi.stop()
pi.hardware_PWM(gpio_pin, freq, duty)
ではfreqに周波数(Hz)、dutyには1000000(=1M)をduty比1として整数を指定します。
pigpioなら周波数とduty比を指定すれば簡単にハードウェアPWMが出力できるのですごい。
こんな感じでやれば独立にハードウェアPWMを制御できると思います。