moraでKalafinaのハイレゾ音源(24bit、96kHz)を購入したのでRPiのI2S出力で再生してみようと思います。
PCM1716を使用するにはシステムクロックが必要になるので
Raspberry Pi I2S 出力で外部クロック使用 その2
のようにPLL1707で外部クロックを生成するのですが、当時は16bit、48kHzまでしか想定していないのと768fsを使いたかったせいで、そのままでは使えませんでした。
そんなわけでシンプルにしてみました。
PLL1707は96kHzだと384fsまでしか出せないっぽいので、システムクロックにはPLL1707のSCKO3の384fsを。
RPiの入力に必要なビットクロック64fsはSCKO2の256fsを74AC163で4分周しました。
次にI2Sドライバー側です。過去の記事とほぼ一緒ですが...
以下、GPIOのピン番号は
RPi B+用になってます。
sound/soc/bcm/bcm2708-i2s.c
53行目辺り
#include <linux/gpio.h>
#include <linux/delay.h>
539行目辺り
gpio_request_one(26, GPIOF_OUT_INIT_LOW, "MyTest");
if (sampling_rate == 48000 || sampling_rate == 96000) {
gpio_set_value(26, 0);
} else {
gpio_set_value(26, 1);
}
gpio_free(26);
gpio_request_one(13, GPIOF_OUT_INIT_LOW, "MyTest");
if (sampling_rate == 96000) {
gpio_set_value(13, 1);
} else {
gpio_set_value(13, 0);
}
gpio_free(13);
gpio_request_one(16, GPIOF_OUT_INIT_LOW, "MyTest");
if (data_length == 16) {
gpio_set_value(16, 0);
} else {
gpio_set_value(16, 1);
}
gpio_free(16);
GPIO26をPLL1707のFS1に繋いで44.1kHzか48kHzかを設定。
GPIO13をPLL1707のSRに繋いで上記周波数を2倍にするか否かを設定。
GPIO16をPCM1716のIWOに繋いで16bitか24bitかを設定しています。
694行目辺り
struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
uint32_t mask;
int myerr;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
myerr = gpio_request_one(12, GPIOF_OUT_INIT_LOW, "MyTest");
if (myerr == 0) {
gpio_set_value(12, 1);
gpio_free(12);
mdelay(100);
}
bcm2708_i2s_start_clock(dev);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
mask = BCM2708_I2S_RXON;
else
mask = BCM2708_I2S_TXON;
regmap_update_bits(dev->i2s_regmap,
BCM2708_I2S_CS_A_REG, mask, mask);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
myerr = gpio_request_one(12, GPIOF_OUT_INIT_LOW, "MyTest");
if (myerr == 0) {
gpio_set_value(12, 0);
gpio_free(12);
mdelay(100);
}
bcm2708_i2s_stop(dev, substream, dai);
break;
GPIO12をPCM1716のMUTEに繋いでます。
791行目辺り
static struct snd_soc_dai_driver bcm2708_i2s_dai = {
.name = "bcm2708-i2s",
.probe = bcm2708_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
// : disable for now, it causes white noise with xbmc
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S32_LE
},
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S32_LE
},
.ops = &bcm2708_i2s_dai_ops,
.symmetric_rates = 1
};
24bitの所がコメントアウトされていたので外しました。しかし、最新のソースコードだと元々上記のようになってますね。
sound/soc/codecs/pcm1794a.c
24行目辺り
static struct snd_soc_dai_driver pcm1794a_dai = {
.name = "pcm1794a-hifi",
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE
},
};
一応、SNDRV_PCM_FMTBIT_S32_LEを追加。
sound/soc/bcm/rpi-dac.c
45行目辺り
static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = {
{
.name = "HifiBerry Mini",
.stream_name = "HifiBerry Mini HiFi",
.cpu_dai_name = "bcm2708-i2s.0",
.codec_dai_name = "pcm1794a-hifi",
.platform_name = "bcm2708-i2s.0",
.codec_name = "pcm1794a-codec",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
//SND_SOC_DAIFMT_CBS_CFS,
SND_SOC_DAIFMT_CBM_CFS,
.ops = &snd_rpi_rpi_dac_ops,
.init = snd_rpi_rpi_dac_init,
},
};
外部クロックを使うように設定しています。
あとはドライバーをコンパイルして適当な場所にコピーして組み込めばOK。
sudo insmod snd-soc-bcm2708-i2s.ko
sudo insmod snd-soc-pcm1794a.ko
sudo insmod snd-soc-rpi-dac.ko
MPDで再生してみるとみごと鳴ってくれました。ヽ(´▽`)ノ