NanoPi NEO2用Volumio2の機能切り替え(dtb差し替え)について

大まかな仕組み

  • NEO2用Volumio2に採用しているLinuxカーネルはdevice treeという方法でドライバのパラメータなどを変更し実際の動作を切り替えています
  • device treeの実行時バイナリはdtbとdtboの2種あります。
  • NanoPi NEO2の場合、現時点ではdtbのみを使用しています。
  • 使用するdtbは/boot/boot.scrで指定されている /boot/sun50i-h5-nanopi-neo2.dtb となります。
  • そんなわけで、/boot/sun50i-h5-nanopi-neo2.dtbを差し替えることで動作を変えることができるわけです。

変更方法

  • /boot/sun50i-h5-nanopi-neo2.dtbを任意のdtbで上書きすることで動作が変わります。
  • ここではsun50i-h5-nanopi-neo2-i2s-generic.dtbに変更する例を書いておきます。
  • SSHでログインして変更する方法と、Windows上で変更する方法を紹介します。どちらかお好みの方法で変更してください。

その1 NanoPi NEO2にログインして変更

  • TeraTermputtysshコマンドでログインしdtbを変更する方法
  • まずはWEB UIに接続してみます。ブラウザで接続してみましょう。volumio.local(mDNS経由)での接続ができない場合は、直接IPアドレスを指定して接続してください。
  • http://volumio.local
  • 無事繋がったらSSHを有効化します。ブラウザで開発者メニューを開きsshをEnableにします。イメージを書き込んだ後に一度だけやればOKです。
  • http://volumio.local/dev
  • sshクライアントでvolumio2が動作しているNanoPi NEO2に接続します。
ssh volumio.local
  • ログインできたらコピーコマンドでdtbファイルを差し替えます
cp /boot/sun50i-h5-nanopi-neo2-i2s-generic.dtb /boot/sun50i-h5-nanopi-neo2.dtb
  • あとはリブートして反映します
reboot
  • 再起動したらWEB UIから「プレイバックオプション」を開き、出力デバイスを選択し直してください。

その2 MicroSDをカードリーダでWindows PCに接続し書き換え

  • イメージ書き込み済みのMicroSDをカードリーダでPCに接続してください。
  • イメージを書き込んだ直後は認識できていないことがあるので、一度カードリーダを外して付け直してください。
  • ボリューム名BOOTというドライブを認識するはずです。ドライブを認識しない場合は、ドライブ文字の割り当てがされていない可能性があります。ドライブ文字を変更したいのですが?|Q&A | IODATA アイ・オー・データ機器などを参考にBOOTパーティションのドライブ文字を設定してください。
  • まずはsun50i-h5-nanopi-neo2.dtbを削除
  • sun50i-h5-nanopi-neo2-i2s-generic.dtbを複製
  • 複製したファイルをsun50i-h5-nanopi-neo2.dtbにリネームしてください。
  • 「安全な取り外し」を行なったらNEO2にSDカードを差し込み起動してください。
  • 起動したらWEB UIから「プレイバックオプション」を開き、出力デバイスを選択し直してください。

dtbの簡単な説明

  1. sun50i-h5-nanopi-neo2-i2s-generic.dtb

    • もっとも基本的にI2Sドライバです。
    • PCM5102A/ES9023/TDA1387T/TDA1543などのMCLKが不要なDACを鳴らす場合にはこれを選択してください。
  2. sun50i-h5-nanopi-neo2-i2s-generic_32fs.dtb

    • 基本的なI2Sドライバですが、32fs固定となっています。
    • 16bit固定出力になります。上記dtbに比べるとBCLKの周波数が低くなります。
    • TDA1387T/TDA1543などの16bitが上限のDACで384kHz再生する場合にオススメです。
  3. sun50i-h5-nanopi-neo2-i2s-generic_mclk.dtb

    • 基本的なI2Sドライバですが、BCLK/LRCLKに加えPA6ピンからMCLKを出力します。
    • MCLKが必要なFN1242A/PCM1794などの再生に利用します。
  4. sun50i-h5-nanopi-neo2-pcm_rj16_32fs_mclk.dtb

    • PCM RJ 16bit固定出力とするドライバです。
    • TDA1545A/TDA1543Aなど、RJフォーマットで16bitが上限のDACで再生する場合に利用します。
  5. sun50i-h5-nanopi-neo2-i2s-generic_mclk_ak449x.dtb

    • I2S MCLK有りでAK4490/AK4493/AK4495/AK4497を利用する場合に使用します。
    • I2CでAK449xを制御することができ、mixerから電子ボリュームやデジフィルの変更を行えます。
    • デフォルトのI2Cアドレスは0x10、制御デバイスはAK4495となっています。
    • 他のデバイスを使用する場合にはdtbファイルをdtsに変換し編集の後、dtbに再変換してください。
  6. sun50i-h5-nanopi-neo2-i2s-dacpluspro.dtb

    • I2SでPCM5122+外部クロック対応のDACを利用する場合に使用します。
    • HifiBerry DAC+ PROもしくは互換DACで動作します。
    • 外部回路はHifiBerry DAC+ PRO互換としてください。
  7. sun50i-h5-nanopi-neo2-spdif.dtb

その他情報・メモなど

  • device tree関係

  • mDNS関係

    • volumio.localでのアクセスですが、LinuxMacであれば問題なくアクセスできると思います。
    • 同じネットワーク内に複数Volumio2を動かしているときどうなるかは不明。
    • Volumio2のWEB UIでホスト名を変えるとvolumioの部分が変わりますのでご注意を。
    • WindowsでのmDNSの動作はよくわかりません。Windows10で実装されたようですが完璧では無いようで。
    • Windows利用者でもiTunesを導入している環境だとBonjourサービスがインストールされるため動くことがあるようです。
    • 繋がらない場合はIPアドレスでアクセスしてください。
    • arpコマンドで調べるか、ルータのDHCP振り出し情報を見るか。
    • mDNSを使ってローカルDNSサーバーを廃止する - Qiitaに情報あります。
  • Volumio2でsshの有効化関連

    • /boot/sshがあればsshが動くのでそれでもOK
    • イメージ書き込み後にgui設定と一緒に書いておくのも良いかも
    • ユーザ・パスワード固定かつrootパスも同じなので、パスワードを変えておくなどの配慮は必要です。踏み台にされちゃうぞ!
  • WindowsでUSBドライブが見えない問題

    • 複数のドライブが見えるタイプのカードリーダでガチャガチャやってると発生する模様
    • Windowsのシステム上は認識しているが、ドライブ文字が割り当てられていないだけのようです。
    • 手動でドライブ文字を割り当てれば見えるはず。

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を採用しています。
  • 2018/1012追記
    • ロット変更なのか、ブートローダを更新しないと起動しないNEO2があるようです。
    • もし、動作しないようであれば、下記ツイートの暫定版をお試しください。

特徴

  • 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へ上書きしてやるのが簡単です。
  • 下記はNEO2にSSHで接続orシリアルコンソール時の差し替え例で、sun50i-h5-nanopi-neo2-i2s-generic.dtbを使う場合の設定方法です。
$cd /boot
$ 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