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

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

FPGA ラズベリーパイB

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

投稿日:2018年3月25日 更新日:

11 カーネルソースの編集
編集すべきは、以下の3つ。
(1) rpi-dac.c  (snd_soc_rpi_dac)
(2) bcm2835-i2s.c (snd_soc_bcm2835_i2s)
(3) pcm1794a.c (snd_soc_pcm1794a)

(1),(2)は、
cd $bcm
dir
により、ディレクトリの一覧を見ることができる。

(3)は、
cd $codec
dir
により、ディレクトリの一覧を見ることができる。

(1)は、以下により編集可能。
nano $bcm/rpi-dac.c

「static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = {」のところ、以下のように修正。
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
//SND_SOC_DAIFMT_CBS_CFS,
SND_SOC_DAIFMT_CBM_CFS,

(「三日坊私が主ないつまでブログやれるか...( ̄~ ̄;) 」さんのラズベリーパイの分類の「Raspberry Pi i2s出力とPCM1716でノイズ対策」という記事のbcm2708-i2s.cという部分の修正を参考にした。)
これにより、外部クロックを使用できる。

(2)は、以下により編集可能。
nano $bcm/bcm2835-i2s.c

(3)は、以下により編集可能。
nano $codec/pcm1794a.c
もっとも、(3)は従前、以下を追加すべきであったが、すでに修正されている。
SNDRV_PCM_FMTBIT_S32_LE

編集すべき事項は、「ラズベリーパイDAC、I2S完全外部クロック、スレーブ入力のめどが立ちました!」の4(2)の①~④だが、③、④は最近のものはすでに反映されており、必要がない。

これらの修正により、ラズパイは32ビットのデータを受け付けるとともに、64倍fsのクロックが外部クロックからラズベリーパイへ供給されるモードとなる。LRクロック(LRの信号の伝送の開始タイミングを知らせる)がラズベリーパイから出力される。fsは、サンプリング周波数で、44.1kとか、96kとかである。pcmでは、44.1kの音声データを出力する際に、各サンプリングごとに音の大きさを定義しているから、その搬送の間に、左右(LR)32ビットずつ交互にDACへデータを送り付ける。そのタイミングは、LRクロックの立ち上がりの後、1クロック後に、32ビットのデータの送信を開始する。したがって、64倍のfsが必要になる。16ビット、24ビットの場合、32ビットに足りない分につき、後ろないし前を0で穴埋めすることになる(32ビットにフォーマット変更をする場合、16ビットの場合、32倍fsとなる)。
もっとも、外部からはどの周波数のどの系列(28.224、24.576)のクロックに乗せてよいかわからないので、ラズパイからgpioで、信号を送る。3ビット必要であり、1つは、2系列あるクロックの切り替え、1つは、周波数の切り替え。
周波数の切り替えでは、192k、96k、48kで、3通りあるとすれば、2ビット必要。
176.4k、88.2k、44.1kで、3通りあるとすれば、2ビット必要。

ここでも、「三日坊私が主ないつまでブログやれるか...( ̄~ ̄;) 」さんのラズベリーパイの分類の「Raspberry Pi i2s出力とPCM1716でノイズ対策」という記事のbcm2708-i2s.cという部分の修正が参考になる。

そこで、bcm2835-i2s.cを編集する。
nano $bcm/bcm2835-i2s.c

4行目に以下を追加。
(上記「三日坊私が主ないつまでブログやれるか...( ̄~ ̄;) 」さんの記事から引用。)

#include <linux/gpio.h>
#include <linux/delay.h>

gpio.hは、カーネル領域で、gpioを操作するのに使う。

以下のファンクションを修正

static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)

bcm2708-i2s.cでは存在したsampling_rateは、bcm2835-i2s.cではなくなっているので、
374行を参考に、関数の2行目に、以下を追加。

unsigned int sampling_rate = params_rate(params);

そのうえで、サンプリング周波数に応じて、gpioを変える。

(上記「三日坊私が主ないつまでブログやれるか...( ̄~ ̄;) 」さんの記事から引用。)
int myerr = gpio_request_one(4, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr == 0) {
if (sampling_rate == 48000) {
gpio_set_value(4, 0);
} else {
gpio_set_value(4, 1);
}
gpio_free(4);
}

if 以降がサンプリング周波数(ここでは、48k)に応じて、GPIO4を、0、1に変える処理ができるので、ほかの周波数でも定義すればよい。

GPIO13をクロック系列の切り替えに使うなら、以下の通り。
<2018.4.30 追記 ただし、以下の修正そのままでは、gpioが動作しない。。。 本記事連載のその8参照。>

int myerr = gpio_request_one(13, GPIOF_OUT_INIT_LOW,”MyTest” );
if (myerr == 0) {
if (sampling_rate == 48000||sampling_rate == 96000||sampling_rate == 192000||sampling_rate == 384000) {
gpio_set_value(13, 0);
} else {
gpio_set_value(13, 1);
}
gpio_free(13);

<2018.4.22修正 検証の結果、上記をgpio4ではなく、gpio13を使うことにしたので、修正。>

GPIO5,GPIO6(GPIO6を上の桁とする)をクロック系列の切り替えに使うなら、以下の通り。

int myerr,myerr2;
myerr = gpio_request_one(13, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr == 0) {
if (sampling_rate == 48000||sampling_rate == 96000||sampling_rate == 192000||sampling_rate == 384000) {
gpio_set_value(13, 0);
}
gpio_free(13);
}
myerr = gpio_request_one(5, GPIOF_OUT_INIT_LOW, “MyTest”);

if (myerr == 0) {
if (sampling_rate == 48000||sampling_rate == 44100) {
gpio_set_value(5, 1);
}
gpio_free(5);
}
myerr2 = gpio_request_one(6, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr2 == 0) {
if (sampling_rate == 48000||sampling_rate == 44100) {
gpio_set_value(6, 1);
}
gpio_free(6);
}

myerr = gpio_request_one(5, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr == 0) {
if (sampling_rate == 96000||sampling_rate == 88200) {
gpio_set_value(5, 0);
}
gpio_free(5);
}
myerr2 = gpio_request_one(6, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr2 == 0) {
if (sampling_rate == 96000||sampling_rate == 88200) {
gpio_set_value(6, 1);
}
gpio_free(6);
}

myerr = gpio_request_one(5, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr == 0) {
if (sampling_rate == 192000||sampling_rate == 176400) {
gpio_set_value(5, 1);
}
gpio_free(5);
}
myerr2 = gpio_request_one(6, GPIOF_OUT_INIT_LOW,”MyTest”);
if (myerr2 == 0) {
if (sampling_rate == 19200||sampling_rate == 176400) {
gpio_set_value(6, 0);
}
gpio_free(6);
}

myerr = gpio_request_one(5, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr == 0) {
if (sampling_rate == 384000||sampling_rate == 352800) {
gpio_set_value(5, 0);
}
gpio_free(5);
}

myerr2 = gpio_request_one(6, GPIOF_OUT_INIT_LOW, “MyTest”);
if (myerr2 == 0) {
if (sampling_rate == 384000||sampling_rate == 352800) {
gpio_set_value(6, 0);
}
gpio_free(6);
}

….

<2018.4.22 追加> ”|sampling_rate == 352800″を追加しました。
<2018.4.28 myerror2==0のところmyerror==0となっていたので、修正。>

-FPGA, ラズベリーパイB

執筆者:


comment

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

CAPTCHA


関連記事

no image

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

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

no image

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

13 ラズパイの信号に応じて、クロックを切り替えるボード  この点をどのようにするか、基板を起こす方法もあるけれど、試行錯誤が多いと思えるので、 FPGAを用いて、プログラム的に、信号切り替え、分周な …

no image

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

前回の続きです。過去の記事にも同じようなことを書いているので、そちらも参照願います。 今回は、カーネルをいじることについて触れます。 <2018.4.30 修正:ファイルが大きくなりすぎたので、3つに …

no image

ラズベリーパイ nanoでの行番号の表示の仕方

find / -name “nano*”で、nanorcを探す。 私のラズベリーパイの場合、 /etc/nanorcで発見できた。 nano /etc/nanorcで、設定ファ …

no image

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

ラズベリーパイの24ピンの初代Bは、市場からほとんど消えている状況なので、今までの記事は独りよがりになっている可能性が高く、そこで、入手性の高いラズベリーパイ2を購入し、誰でも、外部クロックを追試でき …

[最近の記事]
2018年3月
 123
45678910
11121314151617
18192021222324
25262728293031