GoにいればGoに従え(37) ラズパイPicoのPWM、全スライス使ってみる

Joseph Halfmoon

前回は久しぶりにラズパイPico上でTinyGoのオブジェクトを走らせて吉例Lチカ。今回はPWM出力を使ってみます。ラズパイPicoのGPIOの全端子にPWM出力が可能です。ただしPWM周期的には最大8通り、各周期に対して2種類のDutyサイクルを指定可能です。今回は周期を司る8個のスライスを全て使ってみます。

※「GoにいればGoに従え」Go関連記事の総Index

※実機動作確認は Arm Cortex-M0+コアのRP2040チップ搭載、みんな大好き Raspberry Pi Pico機にTinyGoのオブジェクトを書き込んで行っています。ビルドはWindows11上で行ってます。

ラズパイPicoのPWM

多くのマイコンでは、タイマの横にキャプチャ/コンペア・チャネルなどというものが存在し、それらを使ってPWM出力をすることが多いと思います。一方、ラズパイPicoのマイコンRP2040は、キッパリとタイマとPWM機能を切り離しており、タイマはタイマ、PWMはPWMとハードが異なってます。

とはいえPWMするためにはカウンタ回路が必要なので以下のような構成になっています。

    • PWM機能はスライスという独立した単位ハードウエアからなる
    • 一つのスライスには1個の16ビットカウンタが1本存在する。
    • 一つのスライスには2個のコンペアチャネルが存在し、それぞれ上記のカウンタとコンペアしてPWM出力信号を生成できる。
    • スライスを合計8個搭載。

PWMの周期はカウンタによって制御されるので、各スライスは1つの周期で動作します。各スライスにコンペアチャネルは2つあるので、同一周期で異なるデューティサイクルの2種のPWM波形を同時生成できる、という仕組みです。8x2で16種の波形が生成できますが、うち14種の波形については異なる2端子の片方または両方に出力できるので、16+14で30本のGPIO端子全てになんらかのPWM信号を出力可能、ということになってます。

TinyGoにおけるRaspberry Pi Picoのサポート状況については御本家以下のページに記されております。TinyGo > Reference  > Microcontrollers

Raspberry Pi Pico

また、PWMなどハードウエアの制御の詳細については、Machineパッケージについての記述が以下にあります。

pico

コマケーこと言うと、Machineパッケージのページではただ pico と呼ばれてますが、上の方のページでは Raspberry Pi Pico と「フルネーム」で呼ばれているので、一覧を眺めているとちょっと戸惑います。大した話でないけれども。

また、PWMの使用方法については、以下のTutorialで説明されています。そのターゲットデバイスはラズパイPicoなので、動かないわけありません。

Using PWM

今回は、ほぼTutorialどおりっす。

全PWMスライスを使ってみる接続

今回は8本の全スライスを全て動かしてみます。チャネルについてはメンドイので「A」のみです。「システマティック」なラズパイPicoのこと、以下の回路図のように、各スライスのチャネルAは、ボードの片側にならんでいる偶数番号の端子に割り当てられてます。今回使用してないチャネルBは奇数端子デス。

GoPWM_PicoDUTschematic

PWMの動作そのものは、オシロをつなげて波形で見ているのですが、全端子を観察するのはメンドイので全てにLEDを接続してます。PWMの周波数を低くすれば人間にも見えるように点滅できるはず。

今回実験に使用したTinyGoソース

実験に使用したソースが以下に。Tutorialに掲載されているコードを「ふくらませた」だけですが、もろもろ手抜きです。チャネル設定のところでエラーが返ることもありですが、そういうメンドイ処理は踏みつぶしてます。ただただエラーなく動く筈としているもろ手抜きなコードっす。

なお吉例LチカのオンボードLEDのソフトウエアループはそのまま残してます。

package main

import (
    "machine"
    "time"
)

var period500 uint64 = 1e9 / 500
var period1000 uint64 = 1e9 / 1000
var period10 uint64 = 1e9 / 10

func main() {
    led := machine.LED
    led.Configure(machine.PinConfig{Mode: machine.PinOutput})

    pin0 := machine.GPIO0
    pwm0 := machine.PWM0
    pin2 := machine.GPIO2
    pwm1 := machine.PWM1
    pin4 := machine.GPIO4
    pwm2 := machine.PWM2
    pin6 := machine.GPIO6
    pwm3 := machine.PWM3
    pin8 := machine.GPIO8
    pwm4 := machine.PWM4
    pin10 := machine.GPIO10
    pwm5 := machine.PWM5
    pin12 := machine.GPIO12
    pwm6 := machine.PWM6
    pin14 := machine.GPIO14
    pwm7 := machine.PWM7

    pwm0.Configure(machine.PWMConfig{Period: period500})
    pwm1.Configure(machine.PWMConfig{Period: period500})
    pwm2.Configure(machine.PWMConfig{Period: period1000})
    pwm3.Configure(machine.PWMConfig{Period: period1000})
    pwm4.Configure(machine.PWMConfig{Period: period1000})
    pwm5.Configure(machine.PWMConfig{Period: period1000})
    pwm6.Configure(machine.PWMConfig{Period: period1000})
    pwm7.Configure(machine.PWMConfig{Period: period10})

    ch0A, _ := pwm0.Channel(pin0)
    ch1A, _ := pwm1.Channel(pin2)
    ch2A, _ := pwm2.Channel(pin4)
    ch3A, _ := pwm3.Channel(pin6)
    ch4A, _ := pwm4.Channel(pin8)
    ch5A, _ := pwm5.Channel(pin10)
    ch6A, _ := pwm6.Channel(pin12)
    ch7A, _ := pwm7.Channel(pin14)

    pwm0.Set(ch0A, pwm0.Top()/2)
    pwm1.Set(ch1A, pwm1.Top()/4)
    pwm2.Set(ch2A, pwm2.Top()/2)
    pwm3.Set(ch3A, pwm3.Top()/4)
    pwm4.Set(ch4A, pwm4.Top()/2)
    pwm5.Set(ch5A, pwm5.Top()/4)
    pwm6.Set(ch6A, pwm6.Top()/2)
    pwm7.Set(ch7A, pwm7.Top()/2)

    for {
        led.Low()
        time.Sleep(time.Second * 1)
        led.High()
        time.Sleep(time.Second * 1)
    }

}

なお、period500は500Hz、periol1000は1kHzがPWMの周期です。それでは人の目では見えないので、1個だけperiod10という10Hz周期を用意してます。これなら何とか点滅が見える筈。

動作確認

上記のソースをビルドして、USB接続されたラズパイPicoに書き込むのは以下のコマンドラインで。なお、書き込み前にBOOTボタンを押して立ち上げてブートモードに入れておかないとなりません。

$ tinygo flash -target=pico

実機で動作している様子が以下に。GPIO14に接続したLEDのみ、点滅しているのが肉眼で確認できます。他は点灯しているようにしか見えませぬ。GoPWM_PicoDUT

人間の目で見えないところをオシロで見たのが以下に。黄色のC1がGPIO0に出力されている周期500Hz、デューティ50%の波形。青色C2が、GPIO14に出力の周期10Hz、デューティ50%の波形。PWMwaveFORM

ラズパイPicoのカウンタにはスマートな小数点以下ありのプリスケーラなどもついているので周波数の設定はバッチリっす。

GoにいればGoに従え(36) 吉例Lチカ、WindowsからラズパイPicoでTinyGo へ戻る

GoにいればGoに従え(38) ラズパイPicoでソフトウエアタイミング制御の限界? へ進む