Raspberry PiのPWMを用いたDA変換の実験


Raspberry Pi Zero WのPWMの後にローパスフィルターを付けて、DA変換でオーディオ帯域の信号を出力してみました。
これはGPIOピンに以下のようなRCからなるLPFを付加するもので、機能的にはZero以外のRaspberry Piのオーディオジャックと同等(実際には、これ以外にバッファICとカップリングコンデンサが付きます)です。
フィルタのカットオフ周波数は15KHzくらいです。

Raspberry Pi Zeroにはオーディオジャックが無いので、このような回路が必要になります。Zero以外のRaspberry Piでは以下のような回路がもともと搭載されています。

DA変換は、出力したいアナログ量をPWMのデューティ比として指定するだけです。
アナログ量はどんどん変化していきますので、dataを都度設定するのではなく、FIFOバッファを使ってあらかじめデータを用意しておきます。

先日作成したMicroPython版のPWMドライバに、以下のようなメソッドを追加しました。

アドレス0x2020c018に値を書き込むと、FIFOバッファにその値が追加されます。
バッファが満杯になると0x2020c004のbit 0が1になりますので、0になるまで待ちます。
なお、FIFOバッファは2つのPWMで共通になっており、1つしかありません。
2つのPWMをオーディオの左右チャンネルとして使う場合、同じ値を2度書き込めばモノラル出力が得られることになります。

波形データとして鋸波、矩形波、三角波を作成してGPIO18に出力してみました。
プログラムは以下のとおりです。(PWMクラス等は省略しています)

各波形は64サンプルで構成しています。
PWMのクロックは9.6MHz(19.2MHzを1/2に分周)、rangeは256としています。
従ってPWMの搬送波は9600KHz/256 = 37.5KHzで、これがDAのサンプリング周波数になります。
ローパスフィルタは15KHzなので、ぎりぎりカットできる周波数です。

波形データは64サンプルなので、出力される周波数は37500 / 64 = 約586Hzとなります。
サンプルの値の最大値はrange-1ですので、サンプルの値は0~255、つまり量子化ビット数は8bitとなります。
プログラムでは、3つの波形を1000回(1000/586 = 約1.7秒)再生することを繰り返しています。

以下は、出力結果をオシロで見たものです。



何とか波形になっていますが、そこそこの品質の音を出力するには、range=量子化ビット数を10bitは欲しいところですし、サンプリングレートも32KHz以上は欲しいところです。
そうすると最低でも32MHzの制御クロックとなりますから、OSCをクロック源にするのでは不足で、その約10倍の周波数を持つHDMIクロックあたりが適当かもしれません。

コメント