やまちゃんのオーディオブログ

真空管アンプ、最近は資金調達のためのFX,MetaTrader4ネタもやっています。

FPGA ラズベリーパイB

ラズベリーパイのi2s外部クロック、その後8(2018年度版)

投稿日:2018年4月30日 更新日:

やっと、外部クロックで、ラズパイを動かすことができました!!!
ラズパイからは、GPIOでサンプリング周波数を指示し、これに基づいて、外部ボードであるde0-socが周波数を切り替え、マスタークロックを生成し、マスタークロックを分周したbckを、gpioを通じて、ラズパイに供給します。

de0-socの回路図は以下の通り。

(クリックすると拡大します)
pdfは、raspi_clock_slave_mode_schmatic.pdf
quartus 16.0用のプロジェクトは、以下の通り。例によってタイミングは警告が出ます。
clock_select _ras_slave.zip
de0-soc付属のDACは、32bit/96kまでです。

GPIOの様子は、3つのLEDで確認できるようにしました。
周波数系統の切り替えがLED0,分周比の切り替えが(LED2,LED1)です(LED1が下位のbit)。

改造済みbcm2835-i2s.cは、こちら。
modified bcm2835-i2s.c for informing external clocks by 3 gpios; gpio 5,6,13
(動作する暫定版、若干の検討の余地があります。なお、このファイルを利用された方に対し、私は何らの責任も負いません。無償での公開を停止する場合もあり得ます。gpio出力をサンプリング周波数に応じて出すというもので、de0-socの存在は必須ではありません。)

GPIOの出力は、バグ修正のため、このゴールデンウィーク丸2日とその他を費やし、4日ぐらい苦労させられました。
ラズベリーパイのi2s外部クロック、その後3-2(2018年度版)」(ブログの記事を分割しました。)で、gpioから、周波数を切り替え信号を出力するコードを公開しましたが、これを適用しても、一向にgpioが変化せず、困り果てていました。
結論として、gpioを開放する(gpio_free(x))の処理を、gpio設定直後にやってはいけなくて、曲が終わった後に開放する必要があるということでした。
gpio設定直後にやると、直ちにデフォルトに戻ってしまいます。
gpioを開放する処理は、具体的には、static void bcm2835_i2s_shutdown()のモジュール内で行います。
ラズベリーパイのgpioは、初期値が設定されていて、ピンによって異なります。
電圧のhが設定されているピンもあり、起動直後は、configファイルに書かれたとおりに動作するようです。
gpioを開放するとそのデフォルトに戻るので、どのようにやっても、演奏開始時にはgpioの値は変わりませんでした。

<デバッグ作業の効率化の方法>
ソースファイルの改造、デバッグは、nasを導入し/home/pi/nas_allをネットワークの受け渡しフォルダとしたので、
ラズパイとファイルを交換できる当該フォルダで行うことにしました。
その場所はもちろんながらウィンドウズからも見えるので、
programmers notepadというウィンドウズのソフトでファイルを改修し、所定のソースの部分へコピー(cpというコマンド)してデバッグします。

<コマンドのまとめ>
コマンドを打ち込むのが面倒なので、以下の通り改修用コマンドのまとめを置かせてもらいます。そのコマンドの意味については、以前の記事かネットで調べていただければと思います。

sudo su
sudo apt-get install raspberrypi-kernel-headers
export bcm=/root/linux-80a14a56dacb7cc2b40d5f37d00bedb0ceace130/sound/soc/bcm
export codec=/root/linux-80a14a56dacb7cc2b40d5f37d00bedb0ceace130/sound/soc/codecs
export nas=/home/pi/nas_all
cp $nas/bcm2835-i2s.c $bcm/bcm2835-i2s.c
cd $bcm
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules_install
rmmod $bcm/snd-soc-rpi-dac.ko
rmmod $codec/snd-soc-pcm1794a.ko
rmmod $bcm/snd-soc-bcm2835-i2s.ko
insmod $bcm/snd-soc-bcm2835-i2s.ko
insmod $codec/snd-soc-pcm1794a.ko
insmod $bcm/snd-soc-rpi-dac.ko
cp $bcm/snd-soc-bcm2835-i2s.ko /lib/modules/$(uname -r)/kernel/sound/soc/bcm/snd-soc-bcm2835-i2s.ko
cp $bcm/snd-soc-bcm2835-i2s.ko /lib/modules/$(uname -r)/extra/snd-soc-bcm2835-i2s.ko
cp $bcm/snd-soc-rpi-dac.ko /lib/modules/$(uname -r)/kernel/sound/soc/bcm/snd-soc-rpi-dac.ko
cp $bcm/snd-soc-rpi-dac.ko /lib/modules/$(uname -r)/extra/snd-soc-rpi-dac.ko
depmod
export nas=/home/pi/nas_all
cd $nas
aplay -D plughw:0,0 LessLoss-Mephisto-Listz-I-16_bit_44_1_kHz.wav
aplay -D plughw:0,0 LessLoss-Mephisto-Listz-I-24_bit_96_kHz.wav
dmesg

一番下の音楽ファイル名は、ネット上で無料でダウンロードできるお試しファイルのもので、/home/pi/nas_allに入れています。
1つ目のmakeまでを選択してctrl+cでコピーして、teratermで、右クリックして一括ペーストができます。
makeによるコンパイルが通れば、2つ目のmake以下をコピーし、/home/pi/nas_allへ移動して、再生します。
また、make -C /lib/modules/$(uname -r)/build M=$(pwd) modules_installは、上記のinsmdを使えば、やらなくてよいことがわかりました。<5月5日修正>やったほうが良いです。insmodは、電源を切ると忘れるので。。cpコマンドで、元の古いドライバーの位置に、コンパイルした新しいドライバーを直接上書きしてコピーします。そうすると、電源を切って再起動したときに新しいドライバーが読み込まれます。

<gpio部分改造の顛末記>
以下長くなりますが、デバッグの方法として参考になればと思い、記載しました。

上記の通り、gpioの動作が一向に変化せず、一定のままだったのでデバッグを行うことにしました。

当初は、bckの配線に誤りがあり、あっさり動いたと勘違いして、知らぬままラズパイマスターモードになっており、まずそこからスタートしました。
いろいろやっているうちに、24bit/96kの音声を再生したときにテンポが無茶苦茶遅かったので、これは、ラズパイではなくて、de0-socが出したbckに基づいて再生されていると分かり、感動を覚えました。後は、gpioの出力だけを直せばよいと思いました。

しかし、まずやっぱり、gpio.hがまともに動作するのか不安でした。
まず最初に行ったのはネット検索で、printkを使うというものでした。
ネット検索を行うとgpio.hやgpio_request_oneを調べると、printkというのが出てきます。
これは、メッセージをシステムログファイルに残すもので、

dmesg

により取得できます。
ファイル中にprintkでメッセージ出力されるようにしたので、
dmesgコマンドで確認すれば、サンプリング周波数や、gpioの状態をつかむことができます。

しかしながら、gpio以前に、そもそも、サンプリング周波数が入力されているのかが不安です。
いつも参考にさせていただいている「三日坊主な私がいつまでブログやれるか...( ̄~ ̄;) 」というブログの「Raspberry Pi i2s出力とPCM1716でノイズ対策 」という記事のbcm2708-i2s.cの改造位置を調べると、gpio設定の位置が、static int bcm2835_i2s_hw_params()内の、フォーマット設定の後、regmap_writeでストリームを入力?する前に挿入されているので、gpio設定の位置をその位置へ変更しました。

また、サンプリング周波数が入力されているのかをチェックするため、
printkで、サンプリング周波数やそれに基づく分岐を表示させ、これらが正しいのかチェックしました。

printk(“sampling rate=%u\n”,sampling_rate);
printk(“48k line – gpio13=0\n”);
printk(“rate high=0\n”);

そのdmesgの結果は、以下の通り。

・・・
[12846.314872] sampling rate=44100
[12846.322889] 44.1k line – gpio13=1
[12846.326906] rate low=1
[12846.330935] rate high=1
[ 6015.190904] sampling rate=96000
[ 6015.190945] set value myerror 13 =0
[ 6017.191106] 48k line – gpio13=0
[ 6018.191236] rate low=0
[ 6019.191370] rate high=1

サンプリング周波数の検出が動作していることがわかり、かなり安心しました。
しかし、全くgpioが変わりません。全部0ならまだしも、gpio5,6のみ1が点灯します。
なお、gpioの状態は、de0-soc側に入力して、3つのLEDを点灯するようにしていました。

次に、以下の gpio_request_oneは、gpioの取得、設定を行うもので、すでにビジー状態なら、エラーが出ます。

myerr2 = gpio_request_one(5, GPIOF_OUT_INIT_LOW, “MyTest3”);

このプログラムでは、エラーがない場合にだけgpioを設定するようプログラムを組んでいるので、エラーが出ないかチェックしました。
エラーがないようでした。しかし、gpioが変わらないので、gpioの番号が合っているのか不安でした。

gpioの設定は、ネットで調べるとレジスターの登録により行われるということだったのですが、次に、レジスターを設定する際のデレイ設定がないことに疑問を持ちました。
レジスターを利用する場合にその設定に時間がかかるのでデレイを入れるというのを、マイコンのstm32で学んでいたからです。
ちなみに、「ラズベリーパイでI/O」という本(名著)には、カーネルをいじる方法としてレジスター設定による方法のみ記載されていますが、レジスターの登録によりgpioをいじると、汎用性が失われてしまいます。具体的には、pi2、pi3のボードごとに、別の設定をする必要が生じるかもしれないということです。最悪、レジスター設定しか方法がないのかもしれないと思いつつ、その方法はできたら避けたいし最終手段です。

そこで、もしかするとgpioのレジスタ設定がされないまま、次のコマンドに進んでいるのかもと思い、このgpioの出どころである「三日坊主な私がいつまでブログやれるか...( ̄~ ̄;) 」さんの「Raspberry Pi i2s出力とPCM1716でノイズ対策 」という記事に、delayを用いて曲の開始を遅らせ、最初のポップノイズをミュートにしてノイズを消すということがされていたのを思い出し、mdelay()コマンドを挿入してみました。

それでも一向に、同じままです。
そこで、デレイの時間を一気に拡大し、1000?!(つまり1秒)という値を入力してみましたが、変わりません。
なお、デレイの時間を拡大したので、再生を開始するまで10秒?!ぐらいかかります。。

ところで、ピンの設定を上記の通りLEDで検出していましたが、原因がde0-socにまで拡大することを恐れ、ラズパイのgpioのピンをオシロで測定している自分がありました。(ラズパイにLEDを取り付ければよかったのかもしれない。反省。)

そこで、gpioの状態を簡単に調べる方法はないのか。。。と思い、調べてみると、カーネルではなくプログラム領域で動作するwiringPIという方法がありました。

gpio readall

で一覧表を作ってくれます。そのインストールにはgitを用いますが、ライト版のラズパイにはgitは入っておらず、ダウンロードしてインストールしました。
gpio readallで調べると、gpioの5,6,13はなぜか入力モードになっていました。ネットでいろいろ調べていくと、ラズパイを立ち上げたときに、gpioのピンはコンフィグファイル通りの初期状態になるとのことで、初期状態がまさに、gpioの5,6,13が入力モード、gpioの5,6が1、gpioの13が0ということがわかりました。
要するに、gpioが初期状態のままということだったのです。

また、echoを用いた方法で、プログラム領域でgpioをいじったりもしました。

echo 13 > /sys/class/gpio/unexport

でgpioの開放を行うと、”いつもの”の状態に戻ったことを思い出しました。
もしかして、閉じると初期状態に戻るのだろうかと思い、gpioを開放するコマンドであるgpio_free(5)などを削除しました
しかし、2度目に再生したときにdmesgを確認すると、myerr2 = gpio_request_oneでエラーがなければ出力されるはずのprintkが出力されておらず、gpio_request_oneで開いたgpioがオープンのまま閉じられていないことがわかり、直ちにgpio_free(x)を元に戻しました。

では、コマンドプロンプトで、wiringPIを用いて、gpio5,6,13を変更してから、ファイルを演奏するとどうなるのか。
なんと、初期状態に戻りました。

ではいつ戻るのだろう?観測することにしました。
上記の通りデレイの時間を長くしていたので、曲の演奏開始がかなり遅くなっていました。
曲の開始で、LEDが目的通り点灯しますが、曲の開示時には、LEDの点灯が戻っていました。
デレイの時間を長くしたので、LEDの状態、つまり、GPIOの設定状態が分かったのです。
これで確信しました。gpioを直ちに閉じてはいけないということを

では、どこで、閉じたらいいのだろうか。
myerr2 = gpio_request_one(5, GPIOF_OUT_INIT_LOW, “MyTest3”);がファイルオープンに対応するから、ここと同じモジュールで閉じないと、後で閉じれないのではないか、と思い込んでいたのです。
しかし、よく見ると、「gpio_free(x)」には、オープンしたときの引数の入力は必要ではなく、端的にgpio番号を入力すれば足ります。
そうすると、終了処理をしている部分でも、閉じることができるのではないかと思い至りました。
ソースファイルを探すと・・・static void bcm2835_i2s_shutdown()で終了処理を行っているようです。
そこで、ここに、終了処理をまとめて記載しました。

gpio_free(5);gpio_free(6);gpio_free(13);

また、gpio_request_oneでエラーが出ないよう、static int bcm2835_i2s_hw_params()内で、gpio設定する最初にも、同様のコマンドを入力しました。また、デレイが原因ではないと分かり、デレイの長さを4m秒程度に修正しました。

以上の試行錯誤で分かったことは、以下の通り。

・gpioなどのプログラムのシーケンス動作を検証するには、デレイ+LEDなどを用いて、視覚化すると、原因がつかみやすい。
・gpioを設定した場合には、その設定を維持するには、直ちにgpioを開放してはならない。
・カーネルの動作を確認するには、printkを用いて、dmesgで情報を取得する。

<今後の展望>
1 PLLではなくて、de0-socの外部に高精度クロックを設けて、動作させる。
2 quartusの回路図を、標準ロジックのモジュールを使う形式に改めて、動作検証。
3 上記2を基に、回路図を起こす。

-FPGA, ラズベリーパイB

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

no image

ラズベリーパイBのi2s外部クロックでサンプリング周波数に応じたgpio出力

ラズベリーパイB(モデル1)です。すいません。 もはや中国のalliexpressなどでしか入手できないかもしれません。 <追記:ラズベリーパイ0へ応用できるかもしれません。> 以前の記事の通り、ラズ …

no image

ラズベリーパイのi2s外部クロック、その後6(2018年度版)

やっと動きました!!音が鳴りました!! まずは、カーネルを改造せず、ラズベリーパイから提供されるBCLK、LRCK、DATAに加え、de0-socのpllで作成したマスタークロックのxckで音を鳴らし …

no image

ラズベリーパイのi2s外部クロック、ついに動作確認

やりました! とうとうやりました。 PLLではなく、外部クロックでラズベリーパイを鳴らせることができました! bckも外部クロックで駆動しています。 使ったクロックは、キョーセラの7050k(22.5 …

no image

ラズベリーパイのi2s外部クロック、その後5(2018年度版)

とりあえず、デバイス:de0-soc、DAC:wm8731用のクロックジェネレータのプロジェクトを公開。de0-socの開発CDに含まれているmy first fpgaを参考にした。 (図をクリックす …

no image

ラズベリーパイ、volumioカーネル環境をmakeなしクロスコンパイルなしで2時間で立ち上げる。クロスLAN接続

私は、ラズベリーパイをリニア電源(スイッチング電源でなくノイズが少ない)で動作するノーマルBモデル、rev2(過去記事「ラズベリーパイモデルBの入手と設定1」)をaliexpressで入手し、あえてこ …

[最近の記事]
2018年4月
1234567
891011121314
15161718192021
22232425262728
2930