電子工作
RaspberryPi
PWM
pigpio

Raspberry PiのハードウェアPWMをpigpioで出力する

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を制御できると思います。