コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2019年1月10日 >>> 2018年12月28日
link もっと後

2019年1月10日

スマートプラグ

Tinker Board上でlinux-nextを実行するとreboot時にハングしてしまい、その後ウンともスンとも言わなくなるので、外部からボードの電源ON/OFFする方法を探していました。考え付いた方法は3つです。

リセット信号を外部から送る
Tinker Boardはリセットスイッチが搭載されているので、リセットスイッチを物理的に外して、別のボードのGPIOなどを繋げばリセットできます。
USBの電源をON/OFFする
USB micro Bプラグでの給電のため、USBの電源をON/OFFすることができれば、コールドリセットできます。
AC ON/OFFする
当たり前ですがACアダプタ(AC 100V → USB)の電源をON/OFFすれば、コールドリセットできます。

1番目は下手なハンダ付けをして、失敗するとボードが壊れることと、制御用にもう1つボードが要るのは何だかダサいのでやりたくありません。

2番目の線で探していたのですが、USBの給電をON/OFFできる製品って、意外とないですね……。

仕方なく3番目の線で、TP-LinkのスマートプラグHS105を購入しました(メーカーの製品サイト)。Amazonで2,600円です。Wi-Fiが内蔵されている割に、ずいぶん値段が安いですね。

メモ: 技術系の話はFacebookから転記しておくことにした。少し加筆した。

編集者:すずき(2019/01/12 23:22)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年1月5日

ROCK64のアナログオーディオ - その7 - 32kHz → 44.1kHzの順でPCMを再生できない問題解決

目次: ROCK64/ROCKPro64

ROCK64で32kHz → 44.1kHzの順に再生するとエラーになる

年末に喰らったA型インフルエンザのダメージも回復したので、RK3328のI2S1のMCLK(マスタークロック)の設定がおかしくなる問題の追跡を再開しました。

思っていた以上に難しくて理解できず、かれこれ1週間以上費やしてしまいましたが、やっと見えてきました。

ざっくり言えばRockchipのSoCが持つクロック分周器の構成がかなり変わっていることが関係している、と言えるんじゃないでしょうか。良し悪しはさておいて、問題の原因になっています。

現象と再現方法

再現方法はとても簡単です。48kHz → 44kHzの順で再生すると正常に再生できますが、32kHz → 44kHzの順で再生するとエラーになって再生できません。これだけです。

Rockchipのクロックと分周器

早速、問題の原因を説明したいところですが、Rockchipのクロックがどのように繋がっているか説明しないと、全く何も意味が分からないと思いますので、軽く説明します。

RK3328やRockchipの 他のSoCは、1〜128分周まで可能なInteger Dividerと、有理数で分周(例えば7/500など、分子、分母は16ビット精度の整数で指定可能)が可能なFractional Dividerの2つを持っています。

RK3328のTRM(Technical Reference Manual)では、前者にi2s1_pll_div、後者にi2s1_frac_divという名前を付けており、Linuxのクロックドライバでは前者にclk_i2s1_div、後者にclk_i2s1_fracという名前を付けています。

媒体 Integer Divider Fractional Divider
TRM(Technical Reference Manual) i2s1_pll_div i2s1_frac_div
Linux Clockドライバ clk_i2s1_div clk_i2s1_frac

今後はLinuxの名前で表記しますが、接頭辞のclk_ は省きます。

RockchipのI2Sクロック

I2S系のクロックはInteger DividerとFractional Dividerの両方を利用可能です。他のハードウェアブロックはInteger Dividerしか使えませんが、UARTとI2SとS/PDIFは両方使えるようです。

PLLと分周器とI2S1の接続は下記のようになっています。

PLL, 分周器, I2S1のクロック接続関係
CPLL --> | selector |-----> i2s1_div --+--> | selector |--> I2S1 MCLK
GPLL --> |          |  ,---------------'    |          |
                       `--> i2s1_frac ----> |          |

図からもわかる通り、必要に応じてi2s1_fracは使ったり、使わなかったりします。

例えば48kHz, 32kHzで再生する場合は、GPLL -> i2s1_div -> I2S1の経路が使われます。i2s1_fracは使いません。44kHzで再生する場合は、GPLL -> i2s1_div -> i2s1_frac -> I2S1の経路が使われます。

サンプリング周波数Fsと、正しく再生できているときの各分周器の出力周波数、分周比は下記のとおりです。

Fs i2s1_div出力 i2s1_div分周比 i2s1_frac出力 i2s1_frac分周比
32kHz 8.192MHz 1/60 未使用 未使用
44.1kHz 491.52MHz 1/1 11.2896MHz 147/6400
48kHz 12.288MHz 1/40 未使用 未使用

ちなみにi2s1_divの入力はGPLLが選択されることが多く、周波数は491.52MHzで固定のようです。CPLL/GPLLの周波数は可変のはずですが、切り替わったところを見たことがありません。まあ、GPLLは今回の話に関係ないから、どうでも良いですけど……。

クロックドライバの動作

Linuxのクロックドライバは、セレクタで選択可能なクロック系統(この場合だとi2s1_divとi2s1_frac)全てに対して、同じ目標周波数で設定して、目標に一番近い周波数を出力できるクロック系統を選択する仕組みになっています。

例えば先ほど44.1kHzの再生のときはi2s1_fracが選ばれると言いましたが、実はこのときクロックドライバの裏側では、

  • i2s1_div: CPLL 1.2GHz / 107 = 11.214954MHz
  • i2s1_frac: i2s1_div 491.52MHz * 147/6400 = 11.2896MHz

この2つの選択肢(※)が提示されており、i2s1_fracの方が目標値に近い(誤差0)ため、i2s1_fracが選択されています。

(※)正確に言うと12MHz clkinもあるので3つの選択肢から選びますが、ここでは説明を省いています。12MHz clkinが選ばれることはほぼありません。

問題の原因

先ほど示した表のとおり、32kHzの再生後はi2s1_divの出力が8.192MHzになります。この状態で44.1kHzを再生しようとすると、クロックドライバはi2s1_fracの出力を11.2896MHzにしようと試みます、しかし…。

今のクロックドライバはi2s1_fracの親にあたるクロック、つまりi2s1_divの周波数が目標の出力周波数11.2896MHzより低いと、設定を諦めてしまう実装になっています。

コードで言うとこの部分です。

Fractional Dividerのドライバ(一部)

//drivers/clk/clk-fractional-divider.c

static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
			      unsigned long *parent_rate)
{
	struct clk_fractional_divider *fd = to_clk_fd(hw);
	unsigned long m, n;
	u64 ret;

	if (!rate || rate >= *parent_rate)  //★★この部分★★
		return *parent_rate;

	if (fd->approximation)
		fd->approximation(hw, rate, parent_rate, &m, &n);
	else
		clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);

	//...

32kHz → 44.1kHzの再生時はrate = 11.2896MHz, *parent_rate = 8.192MHzとなり、★の部分のif文が発動します。これは「i2s1_fracは8.192MHzしか設定できません」という結果を返すことと等しいです。

この結果を受けたクロックドライバの選択肢は下記のようになります。

  • i2s1_div: CPLL 1.2GHz / 107 = 11.214954MHz
  • i2s1_frac: i2s1_div 8.192MHz

いずれも目標の11.2896MHzと合いませんが、目標に近いのはi2s1_divと言えます。このためクロックドライバはi2s1_divが最適と判断し、I2S1のマスタークロックが11.214954MHzというおかしな値に設定されてしまいます。

このマスタークロック周波数は、サンプリング周波数44.1kHzの整数倍ではないため、サウンドドライバがエラーと判断してPCM再生を止めてしまいます。

48kHz → 44.1kHzの再生で問題が起こらない理由

48kHz → 44.1kHzの再生時はrate = 11.2896MHz, *parent_rate = 12.288MHzとなるため、★のif文を突破してfd->approximationの呼び出しに到達します。RockchipのFractional dividerの場合、この関数ポインタはrockchip_fractional_approximation() 関数を指しています。

この関数は変わった処理で、ある条件を満たすと、親のクロックを使うのを諦めて、親の親のクロックを使う処理になっています。

RockchipのFractional Dividerドライバ(一部)

static void rockchip_fractional_approximation(struct clk_hw *hw,
		unsigned long rate, unsigned long *parent_rate,
		unsigned long *m, unsigned long *n)
{
	struct clk_fractional_divider *fd = to_clk_fd(hw);
	unsigned long p_rate, p_parent_rate;
	struct clk_hw *p_parent;
	unsigned long scale;

	p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
	if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {  //★★目標値が親クロックの20倍より大きく、割り切れないとき★★
		p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));  //★★親の親(CPLLかGPLL)を使う★★
		p_parent_rate = clk_hw_get_rate(p_parent);
		*parent_rate = p_parent_rate;
	}

通常ならば、存在するかどうかわからない「親の親のクロック」の存在を仮定しており、Rockchipのクロックトポロジー(PLL -> i2s1_div -> i2s1_frac)と、ハードウェア制約に強く依存した特殊な処理になっていることが伺えます。

しかし、この特殊処理のおかげでi2s1_divの周波数がi2s1_fracにとって扱いづらい変な値に設定されていたとしても、親の親(CPLLかGPLL)の周波数に戻すことができます。

48kHz → 44.1kHzの再生時にi2s1_fracだけでなく、i2s1_divの周波数まで変わってしまっているのは、なんだか不思議だなあと思った方も居るかもしれません。その理由は、この関数が親クロックの周波数目標値を書き換えてしまうから、だったんです。

参考

ここまで読んでいただいている方はほぼゼロだと思いますが……、分周器i2s1_divとi2s1_fracの設定が可能かどうか?どちらを選ぶべきか?を判定する部分は、こんな感じの呼び出し経路になっています。

クロック周波数設定時のコールツリー

rockchip_i2s_set_sysclk
  clk_set_rate
    clk_core_set_rate_nolock
      clk_core_req_round_rate_nolock
        clk_core_get_boundaries
        clk_core_round_rate_nolock // I2S1クロックの設定
          clk_core_determine_round_nolock
            clk_mux_determine_rate
              clk_mux_determine_rate_flags // I2S1手前のセレクタの設定
                __clk_determine_rate
                  clk_core_round_rate_nolock       // i2s1_divの設定
                    clk_core_determine_round_nolock
                      clk_composite_determine_rate // i2s1_divのセレクタの設定
                        clk_divider_round_rate // Integer dividerの設定
                __clk_determine_rate
                  clk_core_round_rate_nolock   // i2s1_fracの設定
                    clk_core_determine_round_nolock
                      clk_composite_round_rate // i2s1_fracのセレクタの設定
                        clk_fd_round_rate      // Fractional dividerの設定
                          rockchip_fractional_approximation // RockchipのFractional divider固有の設定

何度も同じ関数名が出てきて奇妙に見えると思いますが、目標となるクロック周波数の設定を1ブロックだけで解決できないとき、親クロックに対して再帰呼び出しを行い、親の設定を変更しようとする仕組みになっています。

良くできている素晴らしい仕組みだとは思うのですが…、関数ポインタを使って高度に抽象化されているため、コードを見てもどの関数が呼ばれるのか、もう全く全然わかりません。動作もかなり追いづらいし、デバッグが辛いです……。

編集者:すずき(2020/10/30 01:35)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年1月4日

gitプロトコルの社内プロキシ越え

Yoctoを使ったプロジェクトをビルドする際に、Gitプロトコルを使わないとアクセスできないリポジトリがあります。

Gitプロトコル(git:// から始まるURLのリポジトリ)は無害なんですけど、大抵の社内プロキシを越えられなくて苦労するので、越え方をメモしておきます。

まずGitのプロキシ設定を行います。この例ではgit-proxyというコマンドを使ってくれと指示しています。

Git側の設定

git config --global --add core.gitProxy git-proxy

そんなコマンドはないので、自分で作ります。パスの通った場所、例えば ~/bin/git-proxyのようなファイルを作成して、下記のシェルスクリプトを書いておきます。

自作Gitプロキシコマンド

#!/bin/sh

exec socat STDIO PROXY:192.168.x.x:$1:$2,proxyport=8080

もちろん別途socatコマンドのインストールが必要です。Debianならapt-get install socatでインストールできます。

最初はnetcatでやってみたんですがダメでした。何でだろ?

編集者:すずき(2019/01/06 20:12)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2019年1月10日 >>> 2018年12月28日
link もっと後

管理用メニュー

link 記事を新規作成

<2019>
<<<01>>>
--12345
6789101112
13141516171819
20212223242526
2728293031--

最近のコメント5件

  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」
  • link 24年10月1日
    hdkさん (10/03 08:30)
    「おー、面白いですね。xrdpはすでに立ち...」
  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」

最近の記事20件

  • link 24年10月28日
    すずき (10/30 23:49)
    「[Linuxからリモートデスクトップ] 目次: Linux開発用のLinuxマシンの画面を見るにはいろいろな手段がありますが、...」
  • link 23年4月10日
    すずき (10/30 23:46)
    「[Linux - まとめリンク] 目次: Linux関係の深いまとめリンク。目次: RISC-V目次: ROCK64/ROCK...」
  • link 24年10月24日
    すずき (10/25 02:35)
    「[ONKYOからM-AUDIOのUSB DACへ] 目次: PCかれこれ10年以上(2013年3月16日の日記参照)活躍してく...」
  • link 24年7月25日
    すずき (10/25 02:24)
    「[OpenSBIを調べる - デバイスツリーの扱い(別方法)] 目次: LinuxOpenSBIのブート部分を調べます。Ope...」
  • link 24年8月7日
    すずき (10/25 02:23)
    「[Debian独自の挙動をするQEMUとbinfmt_misc] 目次: Linux前回はbinfmt_miscの使い方や動作...」
  • link 24年9月9日
    すずき (10/25 02:22)
    「[GDBの便利コマンド] 目次: LinuxGDBは便利ですが、少し使わないでいるとあっという間にコマンドを忘れます。便利&使...」
  • link 24年10月20日
    すずき (10/25 02:22)
    「[ゲームを買ったら遊びましょう2] 目次: ゲーム前回の振り返り(2022年5月13日の日記参照)から2年半経ちました。所持し...」
  • link 24年8月2日
    すずき (10/25 02:21)
    「[Debian on RISC-V] 目次: LinuxOpenSBI + Linuxの環境まで動いたので、次はLinuxのデ...」
  • link 24年8月6日
    すずき (10/25 02:21)
    「[他アーキテクチャ向けバイナリを実行する仕組みbinfmt_misc] 目次: LinuxRISC-V 64bit用の実行ファ...」
  • link 24年8月27日
    すずき (10/25 02:20)
    「[Milk-V Jupiterが届いた] 目次: RISC-VMilk-V Jupiterが届きました。お値段が非常に安かった...」
  • link 24年9月13日
    すずき (10/25 02:20)
    「[OpenSBIを調べる - OpenSBIとRISC-V ISA extensions] 目次: Linux今回はOpenS...」
  • link 24年10月11日
    すずき (10/25 02:19)
    「[企業のドメイン] 今の企業は公式サイトを持っていなほうが珍しいと思いますが、ドメイン名の使い方は各社でバラバラで面白いです。...」
  • link 24年10月21日
    すずき (10/25 02:18)
    「[OpenPilotを調べる - プロセス間通信msgqの仕組み] 目次: OpenPilot最近はOSSの運転支援ソフトウェ...」
  • link 24年10月6日
    すずき (10/25 02:11)
    「[OpenPilotを調べる - ビルドと実行] 目次: OpenPilot最近はOSSの運転支援ソフトウェアOpenPilo...」
  • link 24年7月13日
    すずき (10/25 02:10)
    「[RISC-V 64向けLinuxブートローダー(OpenSBI)の構築] 目次: Linux以前、Berkeley Boot...」
  • link 24年7月19日
    すずき (10/25 02:09)
    「[OpenSBIを調べる - ブート処理とペイロード] 目次: LinuxOpenSBIのブート部分を調べます。OpenSBI...」
  • link 24年7月23日
    すずき (10/25 02:08)
    「[OpenSBIを調べる - QEMUのデバイスツリー] 目次: LinuxOpenSBIのブート部分を調べます。OpenSB...」
  • link 24年7月24日
    すずき (10/25 02:08)
    「[OpenSBIを調べる - デバイスツリーの扱い(genericプラットフォーム)] 目次: LinuxOpenSBIのブー...」
  • link 24年6月27日
    すずき (10/25 02:07)
    「[何もない組み込み環境でDOOMを動かす - その4 - 自作OSの組み込み環境へ移植] 目次: RISC-V目次: 独自OS...」
  • link 24年6月24日
    すずき (10/25 02:06)
    「[何もない組み込み環境でDOOMを動かす - その1 - 準備編] 目次: RISC-VみなさまはDOOMをご存じでしょうか?...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www2.katsuster.net
RDFファイル RSS 1.0

最終更新: 10/30 23:49