PWMクラスの修正(RPiベアメタルMicroPython)


新しいAPIの仕様案に合わせて、先週追加したPWMクラスの実装を少し修正しました。
また、FIFOへデータを渡すメソッドも追加しました。

クロック関係は、別にクロックマネージャクラスを用意し、クロック自体をPWMクラスが触ることはなくなりました。
コンストラクタは以下のようなAPIになっています。

machine.Clock(reg_address, source=None, enable=None, divi=None, divf=None)

reg_addressはレジスタのアドレスで、PWM、PCM、GP0..Clock.GP2がクラス定数として使えます。
sourceはクロック源で、OSC、PLLC、PLLD、HDMIが定義済みです。
コンストラクタの中で必要な設定は行えるので、オブジェクトを生成した時点で実質的に処理終了です。

FIFOは全PWMで共通のバッファが一つしかないので、クラスメソッドにするかどうか悩みましたが、インスタンスメソッドにすることの悪影響も特に思いつきませんでした。
ちなみにPythonにおいては、クラスメソッドとインスタンスメソッドの関係は実装面においては以下のようになっているようです。

・どちらも関数自体はクラスへ属するので、「クラス名.関数名(引数)」で共通的にアクセスできる
・インスタンスメソッドの第一引数は必ずself。つまり「o.func(arg)」は「Class.func(o, arg)」と同じ
・クラスメソッドは第一引数にselfが渡されない(「o.func(arg)」形式の呼び出しは不可)

クロックマネージャはPWMの他にI2SやGPIOでもほぼ共通(レジスタのアドレスが違うだけ)なので、レジスタのアドレスをインスタンス変数として持たせて、共通に使えるようにしました。

クロックマネージャをインスタンス化して使うことはあまり無さそうなので、クロックを設定する関数をmachineモジュールの中の関数として実装しようかとも考えたのですが、フラグの設定値やレジスタのアドレスを整数として用意することを考えると、クラス変数が使えるほうが都合が良いので、クラスmachine.Clockを追加しました。

利用例として、PWMを用いたDA変換を修正したものを載せておきます。
以前の版はPWMクラスをMicroPythonで実装していましたが、下記の版はCで実装したmachine.PWMクラス、machine.Clockクラスを利用しています。
FIFOへは、バッファ渡しではなく1つまたは2つの整数を渡しています(2つ渡すのは2チャンネルで同時にPWMを行う場合)。

ちょっと謎なのが、上記で生成した波形は計算上は約586Hzになるはずなのですが、実測してみると波長が2.15msecくらいなので、465Hzくらいしかありません。
何か計算ミスをしているのかもしれません・・・。

なお上記の例ではPWMをmark/spaceモードではなくPWMモードで動作させていますが、mark/spaceモードでDAさせると下図の様にノイズがかなり乗ってきました。
DACするならmark/spaceモードは使わないほうが良さそうです。

コメント