Raspberry Pi ZeroのI2S DACとポップノイズの関係 その2 まっとうにMUTE制御

概要

  • NosPiDAC Zeroなどで音楽を楽しんでいるときに気になるポップノイズについて調べたこと・やったことをメモ。
  • その2はCodecドライバを修正し、外部MUTE制御との連動を試してみます。
  • 外部MUTE制御用のサンプルコード付。
  • MUTE機能つきのHPA IC(MAX9722とか)やオペアンプ(OPA1622とか)などで利用できます。

MUTE制御について

  • ALSAではCodecに対してポップ抑制用にMUTE Callbackを用意している。
  • MUTE関連のCallbackはdigital_muteとmute_streamの2種類
    • digital_muteはstream関係なくCallbackされる。mute_stream callbackを登録すると呼ばれない
    • mute_streamはstream番号指定でのMUTE制御。録再別とかチャネル別でMUTEできるとかかな?
    • とりあえずはdigital_muteを使えば良さそう。
  • このMute Callbackを利用してGPIOからHPAのMUTEを制御してポップノイズを抑制できるかを確認してみる。

仕込み

  • 改造ベースはNosPiDac Zero 1543 HPAを使用
  • HPA ICのMAX9722のShutdownピンにGPIO出力を接続
  • NosPiDACのMAX9722 ShutdownピンはVCCに接続されているため、あらかじめカッターなどでパターンをカットする必要があり
  • PCM5102Aドライバを改造してdigital_mute CallbackでGPIO出力を制御するように改造
    f:id:tkztkztkz:20180829213719j:plain
    NosPiDAC Zero 1543 HPAのMAX9722 SDピンに配線した例

結果

  • 曲間でプチる
    • I2Sドライバはそのままで、CodecドライバのMUTE制御だけでポップノイズを防ぐことはできない。
    • MUTE CallbackでMute解除通知後の処理に何かまずいのが居そう。
  • Mute Callbackの様子
    • 再生開始・停止でMute Callbackが飛んでくる
      • prepare時にMute CallbackでMute解除を通知
      • close(shutdownの前)時にMute CallbackでMuteを通知
    • 曲間ではMute解除通知しかこない(Mute通知は来ない)
      • trigger start/stop時にはMute Callbackは呼ばれない
      • 曲間では trigger(stop) - > prepare -> trigger(start)の順で動くため、prepare実行時のMute解除のみ通知される模様
  • 今度はCallシーケンスを洗って、どこでプチってるか確認します。

  • なお、曲再生中にMAX9722のShutdownピンを直接制御してみたところ、ゼロクロス付近ではノイズなし。ゼロクロスから離れていると少々プチノイズが出る感じとなりました。ゼロクロス検出無しのMute回路なので、ここはまあスペック通りかな。

外部MUTE制御サンプル

  • 今回テストに使用した、PCM5102Aドライバを改造してMUTE信号をGPIO出力するサンプルを乗っけておきます。
  • GPIO4にMUTE信号を出力します。Active Low出力なので、LでMUTE、Hでミュート解除になります。
    • init時にLを設定し、ALSAからのMUTE解除でHを出力します。
    • Active Highにする場合は、GPIOF_OUT_INIT_LOWをGPIOF_OUT_INIT_HIGHに変更し、gpio_set_valueの出力論理を反転させてください。
  • prepare時(MUTE解除)とclose時(MUTE)にMUTE制御が飛んできます。
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
index 8ba322a00363..960d7b83e6ea
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -14,11 +14,42 @@
  * General Public License for more details.
  */

 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>

 #include <sound/soc.h>
+static int null_set_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       pr_debug("%s mute = %d\n", __FUNCTION__, mute);
+
+       if (mute) {
+               gpio_set_value(4, 0);
+       } else {
+               gpio_set_value(4, 1);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops null_dai_ops = {
+       .digital_mute   = null_set_dai_mute,
+};

 static struct snd_soc_dai_driver pcm5102a_dai = {
        .name = "pcm5102a-hifi",
@@ -26,16 +57,20 @@ static struct snd_soc_dai_driver pcm5102a_dai = {
                .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 = &null_dai_ops,
 };

 static struct snd_soc_codec_driver soc_codec_dev_pcm5102a;

 static int pcm5102a_probe(struct platform_device *pdev)
 {
+       gpio_request_one(4, GPIOF_OUT_INIT_LOW, "CODEC MUTE");
+
        return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a,
                        &pcm5102a_dai, 1);
 }
  • サンプルドライバではGPIO決めうちにしているけど、device treeで外部から制御させるように作ると良いかもしれない。

Raspberry Pi ZeroでRJフォーマットDACを鳴らす方法のメモ

概要

  • TDA1545AやTDA1543AなどRJフォーマットを採用しているDACRaspberry Piで鳴らす方法のメモです。
  • NosPiDACでTDA1545Aを鳴らしたかったので、調査・検証してみました。

仕組み

  • 通常ALSAのSoCドライバではdai linkを設定するdriverでPCMフォーマットを設定しているのでそこを直す
  • Raspberry PiのI2S DAC出力を構成するドライバは下記の三種
    • sound/soc/bcm/bcm2835-i2s.c (dai driver)
    • sound/soc/bcm/hifiberry_dac.c (dai link driver)
    • sound/soc/codecs/pcm5102a.c (codec driver)
  • なので、hifiberry_dac.cを修正します。

注意事項

  • Raspberry PiのI2Sドライバは再生ストリームのbit depthと出力bit depthを調整する機能がありません。
    • 再生ストリームのbit depthが出力bit depthになってしまっているようです。
    • RJ16bitのDACを使う場合には、再生bit depthを16bitにしてください。
    • mpdなどで再生bit depthを16bit固定にしてあげるのが簡単です。
      • /etc/mpd.confを下記のように設定 audio_output_format "*:16:*"
  • RJ24bit / RJ32bitに関しては未確認です。
    • RJ32bitはLJ設定32bit固定でも鳴りそうですね。

ソースDiff

diff --git a/sound/soc/bcm/hifiberry_dac.c b/sound/soc/bcm/hifiberry_dac.c
index ee9f13395354..221a8dc820b4
--- a/sound/soc/bcm/hifiberry_dac.c
+++ b/sound/soc/bcm/hifiberry_dac.c
@@ -53,7 +53,8 @@ static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = {
        .codec_dai_name = "pcm5102a-hifi",
        .platform_name  = "bcm2708-i2s.0",
        .codec_name     = "pcm5102a-codec",
-       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+       .dai_fmt        = SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF |
                                SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &snd_rpi_hifiberry_dac_ops,
        .init           = snd_rpi_hifiberry_dac_init,

備考

  • hifiberry_dac.cでdevice treeを読んでPCMフォーマットを切り替えられるようになると便利だね。
  • 出力bit depthもDAC合わせて固定したいな。
  • ついでにcodecもdevice treeから読むようにすれば、電子ボリュームとかに簡単に対応できるようになりそう。
  • どっかで時間が取れたら作ってみようかな。

Raspberry Pi ZeroのI2S DACとポップノイズの関係 その1 力技でポップノイズを抑制

概要

  • NosPiDAC Zeroなどで音楽を楽しんでいるときに気になるポップノイズについて調べたこと・やったことをメモ。

  • ポップノイズは再生・停止・曲間で発生します。

  • 発生メカニズムが確定では無いですが、RPi ZeroのI2SドライバがI2Sのクロックを止めることから発生しているようです。
    • 2018/07/31追記 クロックだけではなくTXONも影響してそう
  • 本内容は暫定対処です。もっと良い対応方法が無いか引き続き研究中です。

I2Sクロック制御

ポップノイズ発生シーケンスおさらい

  • ALSAからのcallbackを追っていきます
    1. 再生開始
    2. startup PCMブロックのEnable
    3. hw_params サンプリングレートを設定・ここでPLLやLRCLKの分周比を設定
    4. prepare FIFOクリア
    5. trigger start 一曲目再生 クロックオン ★ここでプチ音
    6. ここで曲送り
    7. trigger stop 一曲目停止 クロックオフ
    8. prepare FIFOクリア
    9. trigger start 二曲目再生 クロックオン ★ここでプチ音
    10. ここで再生停止
    11. trigger stop 二曲目停止 クロックオフ
    12. shutdown PCMブロックのDisable/クロックオフ
    13. 再生再開
    14. trigger stop 空うち
    15. startup PCMブロックのEnable
    16. hw_params サンプリングレートを設定・ここでPLLやLRCLKの分周比を設定
    17. prepare FIFOクリア
    18. trigger start 二曲目再生再開 クロックオン ★ここでプチ音
    19. trigger stop 二曲目停止 クロックオフ
    20. shutdown PCMブロックのDisable/クロックオフ

クロックを止まらないようにしてみる

  • そんなわけで、I2Sがクロックを止めようとする制御を全部コメントアウトしてみる。
  • ポイントはbcm2835_i2s_hw_paramsでTXON時にはreturn 0する処理をつぶすこと。これをやらないと、サンプリングレートが変わってもクロックを変更してくれません。
  • デメリットは再生停止してもクロックを供給し続けるので、再生停止時の消費電力が上がります。
  • また、TXON状態のままになるので、途中で録音しようとしてもエラーになりそう。
  • 再生専用機なら問題は少ないかな?
  • 現在このコードがじんそんさんのNosPiDAC Zero用 Moode Audioに適用されています。
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index d5f73a8ab893..b2773fb1ce20 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -357,8 +357,8 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
         */
        regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);

-       if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
-               return 0;
+//     if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
+//             return 0;

        data_length = params_width(params);
        data_delay = 0;
@@ -652,17 +655,19 @@ static void bcm2835_i2s_stop(struct bcm2835_i2s_dev *dev,
 {
        uint32_t mask;

        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
                mask = BCM2835_I2S_RXON;
        else
                mask = BCM2835_I2S_TXON;

-       regmap_update_bits(dev->i2s_regmap,
-                       BCM2835_I2S_CS_A_REG, mask, 0);
+//     regmap_update_bits(dev->i2s_regmap,
+//                     BCM2835_I2S_CS_A_REG, mask, 0);

        /* Stop also the clock when not SND_SOC_DAIFMT_CONT */
-       if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT))
-               bcm2835_i2s_stop_clock(dev);
+//     if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT))
+//             bcm2835_i2s_stop_clock(dev);
 }
@@ -735,14 +742,14 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
                return;

        /* Disable the module */
-       regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
-                       BCM2835_I2S_EN, 0);
+//     regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+//                     BCM2835_I2S_EN, 0);

        /*
         * Stopping clock is necessary, because stop does
         * not stop the clock when SND_SOC_DAIFMT_CONT
         */
-       bcm2835_i2s_stop_clock(dev);
+//     bcm2835_i2s_stop_clock(dev);
 }

改造後シーケンスおさらい

  • クロック停止処理削除
    1. 再生開始
    2. startup
    3. hw_param
    4. prepare
    5. trigger start 一曲目再生 クロックオン ★ここでプチ音
    6. ここで曲送り
    7. trigger stop 一曲目停止 クロック止めない
    8. prepare
    9. trigger start 二曲目再生
    10. ここで再生停止
    11. trigger stop 二曲目停止 クロック止めない
    12. shutdown クロック止めない
    13. 再生再開
    14. trigger stop 空うち
    15. startup PCMブロックのEnable
    16. hw_params サンプリングレートを設定・ここでPLLやLRCLKの分周比を設定
    17. prepare FIFOクリア
    18. trigger start 二曲目再生再開
    19. trigger stop 二曲目停止 クロック止めない
    20. shutdown クロック止めない

改造後シーケンス+rc.localで無音再生

無音再生の追加

  • 最初の曲で出るポップノイズを抑制するため、起動中に無音再生することでI2Sのクロック出力を開始する試み
  • SoXのplayコマンドを使って、400HzのSine波を-100dB(無音までゲインを下げる)で再生する処理を追加してます。

  • 以下をRPi MoodeAudio上で実行する

sudo apt update
sudo apt install sox
  • エディタでrc.localを開く
sudo vi /etc/rc.local
  • exit 0の前あたりに下記を追加
/usr/bin/play -n synth 1 sine 400 gain -100 &
  • SHIFT + ZZなどで保存して終了

シーケンス

  • 事前に無音音声再生&クロック停止削除
    1. 無音再生開始
    2. startup
    3. hw_param
    4. prepare
    5. trigger start 無音再生 クロックオン ★ここでプチ音(無音再生なので軽微)
    6. trigger stop 無音再生停止
    7. shutdown クロック止めない
    8. 再生開始
    9. trigger stop 空うち
    10. startup PCMブロックのEnable
    11. hw_params サンプリングレートを設定・ここでPLLやLRCLKの分周比を設定
    12. prepare
    13. trigger start 一曲目再生
    14. trigger stop 一曲目停止 クロック止めない
    15. prepare
    16. trigger start 二曲目再生
    17. trigger stop 二曲目停止 クロック止めない
    18. shutdown クロック止めない
    19. 再生再開
    20. trigger stop 空うち
    21. startup PCMブロックのEnable
    22. hw_params サンプリングレートを設定・ここでPLLやLRCLKの分周比を設定
    23. prepare FIFOクリア
    24. trigger start 二曲目再生再開
    25. trigger stop 二曲目停止 クロック止めない
    26. shutdown クロック止めない

備考

  • SND_SOC_DAIFMT_CONTでtrigger stopのクロック停止を抑制できそう。
  • ただ、このフラグを立てるのはhifiberry_dac.cを直さなきゃいけないので、1ファイルの差し替えで済むので現行のままがお手軽かも。

NanoPi Neo2のビルド環境構築(公式サイトからToolchain取得)

概要

  • 過去記事でNEO2用のビルド環境構築を解説したけど、MediafireからToolchainを持ってきたりでちょっと怪しい感じだったので、Linaroから直接Toolchainをとってきてビルドする手順を確認したのでメモします。
  • Ubuntu 18.04LTS AMD64環境で確認しました。32bit環境は未確認

Build関連パッケージのインストール

  • ビルドするならまずはbuild-essentialを入れる。gcc, g++, make, libc-devあたりを纏めてインストールしてくれる仮想パッケージ。
$ sudo apt install build-essential

Toolchainの取得と展開

  • Linaroのサイトからツールチェインを取得。
  • ポイントは6.x系を選ぶこと。7.x系からはABIが変わる?とかで互換性が無いとか。
  • 取ってきて/opt以下にバラします。
$ wget https://releases.linaro.org/components/toolchain/binaries/6.4-2017.11/aarch64-linux-gnu/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz
$ sudo mkdir -p /opt/linaro/toolchain/
$ sudo tar xvf aarch64-linux-gnu/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu.tar.xz -C /opt/linaro/toolchain/
  • 未確認ですが、32bitだと下記をDLしてください。
https://releases.linaro.org/components/toolchain/binaries/6.4-2017.11/aarch64-linux-gnu/gcc-linaro-6.4.1-2017.11-i686_aarch64-linux-gnu.tar.xz

パスを通す

$ export PATH=/opt/linaro/toolchain/gcc-linaro-6.4.1-2017.11-x86_64_aarch64-linux-gnu/bin:$PATH

gitでカーネルを持ってきて、4.11ブランチをcheckout

$ git clone https://github.com/friendlyarm/linux.git
$ cd linux
$ git checkout sunxi-4.11.y
$ git clone https://github.com/tkztkztkz/linux.git
$ cd linux
$ git checkout npi-audio-4.11.y

ビルド

$ make sunxi_arm64_defconfig ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
$ make Image dtbs modules ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

モジュールを集める

$ make modules_install ARCH=arm64 INSTALL_MOD_PATH=./mod_root/
$ cd mod_root
$ tar cvfz ../modules.tar.gz ./

ターゲットにコピー

  • 出来上がったarch/arm64/boot/ImageをNanoPi NEO2の/bootにコピー
  • dtbはarch/arm64/boot/dts/allwinner/あたりに生成されます。これも必要なものをコピー
  • modules.tar.gzをターゲット(NEO2)のrootに展開。下記コマンドはNEO2上で実行すること。
$ sudo tar xvfz modules.tar.gz -C /

次回から

  • パスを通してビルドしてターゲットにコピーするだけです。
  • モジュールはカーネルのマイナーバージョンが同じなら2度目以降は全コピー不要。修正したものがあれば手動でコピーしてください。

moode audioのカーネルをクロスビルドする手順メモ

  • moode audioで使用しているRaspbianのカーネルイメージをクロスビルドするにあたっていろいろハマったのでメモして置きます。
  • Ubuntu 18.04LTS AMD64環境で確認
  • ターゲットはRaspberry Pi Zero用。RPi3とか64bitの奴はツールチェインやビルドオプションが変わるはず。

1. toolchainとkernelをとってくる

git clone https://github.com/raspberrypi/tools
git clone https://github.com/raspberrypi/linux

2. toolchainにパスを通す

$ vim rpisetup
export PATH=`pwd`/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

って感じで環境変数を書いたファイルを作成して

source ./rpisetup

とかして読み込む。毎回コマンドラインでexportしても良いです。お好きな方法で。

3. kernel hashを探す

  • まずはmoode audioのプロパティを見て使用しているカーネルを探す。
  • https://github.com/moode-player/mosbuild
  • modbuild.properties ファイルの中身を見る

  • ここにKERNEL_HASHがある

    • KERNEL_HASHという名前だが、raspberrypi/linuxリポジトリのHashではなく、
    • rpi-updateが使ってるHexxeh/rpi-firmwareリポジトリのHashであることに注意
    • 例えば 171c962793f7a39a6798ce374d9d63ab0cbecf8c って感じの文字列がKERNEL_HASHです。

4. kernel git hashを探す

5. rpi kernelを指定のバージョンでチェックアウトする

  • git_hashのハッシュでcheckoutする。これでやっとmoode audioで使ってるバージョンのkernelが取得できる。
cd linux
git checkout b6e99accda7519a48dfd38992d31baefb56b0e10

6. configを実機から持ってくる場合(任意)

  • RPi実機でconfigsをロードしてconfig.gzをクロスビルド環境に持ってきておく
modprobe configs
scp /proc/config.gz hoge とかで実機からビルドマシンに吸い上げる。
zcat config.gz > .config でlinuxディレクトリ配下に展開しておく

7. buildする

  • あとはビルドするだけ
  • .configを実機から持ってきてる場合はoldconfigで。デフォルト設定でビルドするならbcmrpi_defconfigで。
KERNEL=kernel
make oldconfig or make bcmrpi_defconfig
make -j8 zImage modules dtbs

編集履歴

NanoPi Neo2用 Volumio2

NanoPi Neo2 Volumio2 release

  • NanoPi Neo2 I2S Audio Kernelを適用したVolumio2です。
  • バージョンはv2.413を採用しています。

特徴

  • I2S + MCLK出力可能
  • I2S 16bit長(32fs固定)出力対応
  • RJ 24bit(64fs)/ RJ 16bit(64fs)/ RJ 16bit(32fs)出力対応
  • HiFiBerry DAC+ PRO or compatible対応
  • AK4490/4495/4497/4493対応
  • DACが対応していれば、768kHzや1536kHzの再生が可能
  • 詳しくはNanoPi Neo2 I2S Audio Kernelを参照ください

既知の問題

  • DSD to PCM変換でサンプリングレートが上がりすぎる
    • I2Sの再生サンプリングレート上限が1536kHzとなっているため、DSD to PCM変換時の再生レートが高くなります。
      • DSD64 352.8kHz
      • DSD128 705.6kHz
      • DSD256 1411.2kHz
    • I2S Driver or Codec Driver側にて上限設定する方法を検討中です。
  • 高負荷時にカーネルクラッシュ
  • 再起動(reboot)でこける時がある
    • Linux Kernel 4.14へのアップデート時に解消予定
    • sdのレギュレータ制御不正
  • 標準でsshdが有効になっていません
    • http://volumio.local/dev or http://ipaddress/devで開発者モードに入り有効化してください。

制約など

  • 本Volumio2はNanoPi Neo2 I2S Audio Kernel評価用に作成したものです。
    • Volumio2の使い方については他のサイトを参照ください。
    • Volumio2への機能追加などをリクエストを頂いても基本的には対応できません。
  • ビルド手順を下の方に書いてますので、ぜひいろいろカスタムしてみてください。

使い方

バイナリダウンロード

書き込みと起動

  • windowsならrufuslinuxならddなどでSDカードにイメージを書き込んでください。
  • 初回起動はSDカードのresizeが走るため2-10分程度かかります。途中で電源を落とさないようしてください。

動作モードの切り替え方

  • デフォルトではI2S genericとなっています。
  • その他のモードで使う場合には、dtbファイルを差し替えて機能の切り替えを行ってください。
  • NanoPi Neo2のbootスクリプトは、defaultではsun50i-h5-nanopi-neo2.dtbで起動するので、sun50i-h5-nanopi-neo2.dtbへ上書きしてやるのが簡単です。
$ cp sun50i-h5-nanopi-neo2-i2s-generic.dtb sun50i-h5-nanopi-neo2.dtb

ソースコード

ビルド手順メモ

$ git clone https://github.com/tkztkztkz/Build.git
$ cd Build
$ sudo ./build.sh -b armv7 -d nanopineo2 -v 2.413
  • Ubuntu 16.04LTSにてビルドを確認済みです。18.04LTSではビルドに失敗することを確認しています。
    • ビルドに必要なパッケージはVolumioのドキュメントを参照ください。参考までにこちらでは下記を実行しました。
sudo apt install git squashfs-tools kpartx multistrap qemu-user-static samba debootstrap parted dosfstools qemu binfmt-support qemu-utils build-essential

NanoPi Neo2 I2S Audio Kernel alpha1 release

これは何?

  • NanoPi Neo2用のカーネルにI2Sオーディオ関連のパッチを当てたものになります。
  • カーネルのみのリリースとなります。音を出すにはSoXやmpdなどを自力で導入する必要があります。
  • 手軽に音を出したい方は、本カーネルを適用したVolumio2を作成予定ですので、それまでお待ちください。

  • 標準のカーネルに加えて下記の修正が施してあります

    • 特定sampling resolutionで音が出ない問題の修正(24bitでノイズになるなど)
    • MCLK出力の有効化
    • 768/1536kHzのサンプリングレートに対応
    • HifiBerry DAC+ PRO or 互換ボードに対応
    • PCM Right Justified16/24bit出力に対応
    • BCLK外部クロック駆動など特殊動作に対応
  • baseは4.11になります。

ダウンロード・使い方

バイナリダウンロード

メーカ提供 UbuntuCoreの場合

  • FriendlyArm提供のUbuntuCore ImageをSDに書き込む
  • PC上でもターゲット上でも構わないので、/bootのImageを上記からダウンロードしたもので上書きする
  • ターゲット上でmodulesを展開する
# tar xvfz npi_audio_modules_1803_alpha1.tgz -C /
or
$ sudo tar xvfz npi_audio_modules_1803_alpha1.tgz -C /
  • 再起動でAudio Kernelに差し替わります

動作モードの切り替え方

  • dtbファイルを差し替えて機能の切り替えを行ってください。
  • NanoPi Neo2のbootスクリプトは、defaultではsun50i-h5-nanopi-neo2.dtbで起動するので、sun50i-h5-nanopi-neo2.dtbへ上書きしてやるのが簡単です。
$ cp sun50i-h5-nanopi-neo2-i2s-generic.dtb sun50i-h5-nanopi-neo2.dtb
  • dtbの種類と動作モードは下の方で説明していますのでご確認ください。

ソースコード

制約など

dtbファイルと動作モードの紹介

通常利用向けdtb

  • I2S Generic
    • I2S出力に対応します。MCLKは出力しません。
    • デフォルトは64fsは32bit長固定とします。16/24bit再生時、LSBは0パディングします。
    • 32fsは16bit長固定とします。Philipsなどの16bit長DACに最適です。
    • PCM5102AやES9023PなどMCLKが不要なDACの接続に利用します。
sun50i-h5-nanopi-neo2-i2s-generic.dtb
sun50i-h5-nanopi-neo2-i2s-generic_32fs.dtb
  • I2S Generic + MCLK
    • MCLK出力に対応します。MCLKはPA6に出力します。
    • デフォルトは64fsは32bit長固定とします。16/24bit再生時、LSBは0パディングします。
    • 32fsは16bit長固定とします。
    • PCM179X/AK449XなどのMCLKが必要なI2S DACの接続に利用します。
    • 出力されるMCLKの周波数とサンプリングレートの対応は以下の通りです。
サンプリングレート MCLK周波数
48/96/192/384kHz 24.576MHz
44.1/88.2/176.4/352.8kHz 22.5792MHz
768kHz 49.152MHz
1536kHz 98.304MHz
sun50i-h5-nanopi-neo2-i2s-generic_mclk.dtb
sun50i-h5-nanopi-neo2-i2s-generic_mclk_32fs.dtb
  • HiFiBerry DAC+ Pro or compatible
    • HiFiBerry DAC+/DAC+ PROの両方に対応
    • BCLKは16bit時は32fs。24/32bit時は64fsで出力します。
    • DAC+ PRO使用時には外部クロックで動作します。
    • DAC+ PRO使用時においても強制的にDAC+モードの利用(slaveモード)も可能
    • 必要な接続はI2S(BCLK/LRCLK/DATA)とI2C(SDA/SCK)、3.3V、5V、GNDとなります。
    • NanoPi Neo2ではボード上にI2C PullUpが無いため、必ず外部にて3.3VにPullUpしてください。
sun50i-h5-nanopi-neo2-i2s-dacpluspro.dtb
sun50i-h5-nanopi-neo2-i2s-dacpluspro_slave.dtb
  • PCM RJ16/RJ24bit
    • 古いDACに多いRight Justifiedフォーマット出力に対応します。
    • MCLK出力に対応します。MCLKはPA6に出力します。
    • Right Juistifiedではbit長が自動認識できませんので、ターゲットのDACに合ったbit長を選択してください。
    • 32fsは16bit長固定とします。Philipsなどの16bit長DACに最適です。
    • FN1242Aにて動作確認済みです。
sun50i-h5-nanopi-neo2-pcm_rj16_32fs_mclk.dtb
sun50i-h5-nanopi-neo2-pcm_rj16_64fs_mclk.dtb
sun50i-h5-nanopi-neo2-pcm_rj24_64fs_mclk.dtb

実験向けdtb

  • I2S CBM_CFS fixed clock mode 実験用
    • 外部から固定BCLKを入力するモードです。
    • 水晶発振器などを利用して、NanoPi Neo2及びDACのBCLKにクロックを入力してください。
    • LRCLKはNanoPi NEO2にて生成します。
    • MCLKは出力できません。
    • 64fs固定です。(dtsを編集すれば32fs/48fsも設定可)
      • 24.576MHz入力で32bit 384kHz固定
      • 12.288MHz入力で32bit 192kHz固定
    • mpdなどでリサンプリングを有効にして利用することを想定しています。
    • クロックに合ったサンプリングレートで再生しない場合、音程が正しく出力されません。
sun50i-h5-nanopi-neo2-i2s-cbmcfs_bclkin.dtb
  • I2S Generic + MCLK less than 100MHz 実験用
    • MCLKに100MHz未満で設定可能な最大周波数を設定
    • ES9018SでMCLKをNanoPi Neo2から入力する場合に使用します。
    • I2C制御はしませんので、ES9018Sはデフォルト動作とさせるか外部マイコンで制御または、i2c-toolsなどで制御が必要です。
 sun50i-h5-nanopi-neo2-i2s-generic_mclk_lt100m.dtb
  • I2S Generic + MCLK less than 50MHz 実験用
    • MCLKに50MHz未満で設定可能な最大周波数を設定
    • PCM5102A/ES9023Pなどで、MCLKをNanoPi Neo2から入力する場合に使用します。
    • MCLKのクロックによって音が変化するか実験するときにどうぞ
 sun50i-h5-nanopi-neo2-i2s-generic_mclk_lt50m.dtb

今後の予定(あくまで予定です)

  • Volumio2のNanoPi Neo2版提供(本カーネル導入済み)
  • beta版ではbaseバージョンを最新の4.14にアップデート
  • rt patchの取り込み
  • オーディオフォーマット対応のリファクタリング

もしかしたらやるかも

  • 外部I2S Master基板の製作とドライバ作成