コグノスケ


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

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

2018年12月14日

Tinker Boardでは不具合再現せず

目次: ROCK64/ROCKPro64

Tinker Boardでサウンド周りを有効にしてlinux-nextを動かしてみたものの、指摘された不具合(2018年12月5日の日記参照)が出ません。

メールではDMAドライバのどこかでクラッシュした、と言われました。サウンド周りのハードウェアはI2Sとコーデックが居ますが、DMAを使うのはI2Sだけです。コーデックmax98090はSoC外部に居ますから、SoC内部のDMAを使う術がありません。

I2Sが原因ならば、SoC内部のハードウェア起因ですから、Tinker BoardだろうがChromebook C201だろうが、ボードに関わらず現象が再現しても良さそうなのに。

Chromebookで使われているグルードライバrockchip-snd-max98090の影響も疑って、Chromebook C201のデバイスツリー(rk3288-veyron-speedy.dts)からデバイスノードの設定をパクってきて、max98090をspdif-transimtterに差し替えて(Tinker Boardにmax98090は搭載されていない)、無理やり動かしてみましたが、特に何事も無く動いてしまいました。

どうやってもChromebook C201じゃないと再現しないのかな?良くわからないバグだ……。

Tinker Boardのアナログオーディオ出力

ROCK64のときはアナログオーディオ出力でもHDMI出力でも、SoC内蔵のI2Sハードが動作しましたが、Tinker Boardはちょっと事情が違います。

Tinker Boardにもアナログオーディオ端子は付いていますが、接続先はRK3288ではなくオンボードのUSB Audio(Realtek ALC4040)です。アナログオーディオのためにわざわざ専用USBデバイスを載せるとは、豪華なボードだなあ〜。

というわけで、Tinker BoardでSoC内蔵のI2Sが動くかどうか試すには、アナログオーディオ端子ではダメで、HDMI出力じゃないと本当に動作しているかどうかわからないです。我が家にはデジタルテレビならありますが、ボードからケーブルが届かないですね。

できればHDMIが映せて、音も出せて、ボードの隣に置いても邪魔にならないくらい小さいモニタがあるとベストですが、我が家にそんなもんは無い……。

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

編集者:すずき(2023/05/15 04:02)

コメント一覧

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



2018年12月15日

ARMワンボードPCのネットワーク

Raspberry Pi対抗ボードの多くはRaspberry Pi 3のEthernetが遅いこと(USB接続らしい)を引き合いに出し、ネットワークが速いことを宣伝文句にしています。

宣伝文句自体は疑っていませんが、どの程度の差があるかは知らないので、測定してみました。ちょうどTinker Boardも購入しましたし、Rockchip同士の比較もしてみたいと思います。

測定方法

測定は簡単です。受信側のPCで下記を実行します。

$ iperf3 -s -p 11111

送信側の各種ボードで下記を実行します。

$ iperf3 -c (PCのIPアドレス) -p 11111

受信側のPCのCPUはRyzen 7 2700で、マザーボードはASUS B450-F GAMINGです。OSはDebian GNU/Linux amd64のTesting版です。測定時点でのカーネルは4.18.0-2-amd64というバージョンになっていました。

測定結果

結果だけ先に言うとTinker Board(RK3288)の方が速いです。ROCK64(RK3328)の方が後発のSoCなのですが、Ethernetは遅いみたいですね。

ちなみにRaspberry Pi 3は94Mbpsでした。そもそもGigabit Etherじゃないので、比べ物になりません。

  • Tinker Board: 942Mbits/sec
  • ROCK64: 805Mbits/sec
  • Raspberry Pi 3 Model B: 94Mbits/sec

念のため各ボードのEthernetケーブルを入れ替えてみましたが、結果は変わりませんでした。

参考までにファイルサーバとして使っているPentium Jのマシンから、同様の計測を行ったところ942Mbits/sec でした。

測定のログ

結果はこんな感じでした。

Tinker Board (RK3288) でのiperf3実行結果
katsuhiro@linaro-alip:~$ iperf3 -c 192.168.1.2 -p 11111
Connecting to host 192.168.1.2, port 11111
[  4] local 192.168.1.16 port 58608 connected to 192.168.1.2 port 11111
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec   113 MBytes   950 Mbits/sec    0    358 KBytes
[  4]   1.00-2.00   sec   112 MBytes   942 Mbits/sec    0    358 KBytes
[  4]   2.00-3.00   sec   112 MBytes   941 Mbits/sec    0    358 KBytes
[  4]   3.00-4.00   sec   112 MBytes   941 Mbits/sec    0    358 KBytes
[  4]   4.00-5.00   sec   112 MBytes   941 Mbits/sec    0    358 KBytes
[  4]   5.00-6.00   sec   112 MBytes   943 Mbits/sec    0    406 KBytes
[  4]   6.00-7.00   sec   112 MBytes   941 Mbits/sec    0    406 KBytes
[  4]   7.00-8.00   sec   112 MBytes   941 Mbits/sec    0    406 KBytes
[  4]   8.00-9.00   sec   112 MBytes   941 Mbits/sec    0    406 KBytes
[  4]   9.00-10.00  sec   112 MBytes   941 Mbits/sec    0    406 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  1.10 GBytes   942 Mbits/sec    0             sender
[  4]   0.00-10.00  sec  1.10 GBytes   942 Mbits/sec                  receiver

iperf Done.
ROCK64 (RK3328) でのiperf3実行結果
katsuhiro@rock64:~$ iperf3 -c 192.168.1.2 -p 11111
Connecting to host 192.168.1.2, port 11111
[  4] local 192.168.1.102 port 54768 connected to 192.168.1.2 port 11111
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  97.6 MBytes   819 Mbits/sec    0    356 KBytes
[  4]   1.00-2.00   sec  96.4 MBytes   808 Mbits/sec    0    395 KBytes
[  4]   2.00-3.00   sec  95.8 MBytes   804 Mbits/sec    0    395 KBytes
[  4]   3.00-4.00   sec  95.7 MBytes   803 Mbits/sec    0    395 KBytes
[  4]   4.00-5.00   sec  95.8 MBytes   803 Mbits/sec    0    395 KBytes
[  4]   5.00-6.00   sec  95.8 MBytes   804 Mbits/sec    0    395 KBytes
[  4]   6.00-7.00   sec  95.8 MBytes   804 Mbits/sec    0    395 KBytes
[  4]   7.00-8.00   sec  95.7 MBytes   803 Mbits/sec    0    395 KBytes
[  4]   8.00-9.00   sec  95.8 MBytes   804 Mbits/sec    0    395 KBytes
[  4]   9.00-10.00  sec  95.8 MBytes   803 Mbits/sec    0    395 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec   960 MBytes   805 Mbits/sec    0             sender
[  4]   0.00-10.00  sec   958 MBytes   804 Mbits/sec                  receiver

iperf Done.
Raspberry Pi 3 Model Bでのiperf3実行結果
katsuhiro@raspberrypi:~ $ iperf3 -c 192.168.1.2 -p 11111
Connecting to host 192.168.1.2, port 11111
[  4] local 192.168.1.105 port 46476 connected to 192.168.1.2 port 11111
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  11.3 MBytes  94.6 Mbits/sec    0   29.7 KBytes
[  4]   1.00-2.00   sec  11.2 MBytes  94.1 Mbits/sec    0   29.7 KBytes
[  4]   2.00-3.00   sec  11.2 MBytes  94.1 Mbits/sec    0   29.7 KBytes
[  4]   3.00-4.00   sec  11.2 MBytes  94.2 Mbits/sec    0   29.7 KBytes
[  4]   4.00-5.00   sec  11.2 MBytes  94.1 Mbits/sec    0   29.7 KBytes
[  4]   5.00-6.00   sec  11.2 MBytes  94.2 Mbits/sec    0   29.7 KBytes
[  4]   6.00-7.00   sec  11.2 MBytes  94.2 Mbits/sec    0   29.7 KBytes
[  4]   7.00-8.00   sec  11.2 MBytes  94.1 Mbits/sec    0   29.7 KBytes
[  4]   8.00-9.00   sec  11.2 MBytes  94.2 Mbits/sec    0   29.7 KBytes
[  4]   9.00-10.00  sec  11.2 MBytes  94.1 Mbits/sec    0   29.7 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec   112 MBytes  94.2 Mbits/sec    0             sender
[  4]   0.00-10.00  sec   112 MBytes  94.2 Mbits/sec                  receiver

iperf Done.
編集者:すずき(2018/12/16 01:11)

コメント一覧

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



2018年12月19日

ROCK64のアナログオーディオ - 手ごわい44.1kHz系

目次: ROCK64/ROCKPro64

RK3328のI2S1で44.1kHz系を再生するとEINVALエラーになってしまう問題は、I2Sのマスタークロック周波数が11289600ではなく11289599などという変な値が渡されて、マスタークロックとビットクロックが整数比ではなくなることが原因でした。

エラーを無視して処理を流してみると、分周比がおかしくなります。本来11289600 / 2822400 = 4にならなければいけないのですが、11289599 / 2822400 = 3になって、周波数が高めに設定されてしまい、異常に音が高くなります。

Rockchip Linuxはどうやって解決しているのか見るとDIV_ROUND_CLOSESTというマクロで割り算の結果を4側に丸めていました。本当の原因は変な端数の値を返すクロックドライバだと思うので、この対応はちょっとイケてないですね……。

ACODECにも2つほど問題があって、完全には解決できていません。

44.1kHz系に切り替えるとACODECが動かなくなる問題

問題1つ目は、44.1kHz系を再生すると、全く音が出なくなる症状です。これはコアのリセットで直るようです

リセットを掛けないと、切り替え以降、何をしても全く音が出ません。しかしRockchip Linuxのコードは全くリセットを掛けておらず、なぜこれで動くのか理解できません……。

気になる点としては、リセットすることでdai_set_fmtで設定されたI2Sのマスタースレーブ設定が吹き飛んでしまうことです。しかしACODECはなぜかマスタースレーブ設定が間違っていても動いてしまいます。ハードが設定値を無視しているか、Rockchip Linuxのドライバが間違っているかどちらかでしょう。真相はわかりません。

44.1kHz系に切り替えると音が異常に小さくなる問題

問題2つ目は、48kHz系 → 44.1kHz系への切り替え時、たまに音が異常に小さくなる症状です。これは直せそうにないです。

  • おそらく影響しているのはDAC_PRECHARGE_CTRLレジスタの値だろう
  • 48kHzの再生終了から、44.1kHz系の再生まで、ある程度時間を空けると鳴る
  • 鳴らなかったときもう一度同じ設定で叩くと鳴る

これくらいまではわかりましたが、鳴るときor鳴らないときの法則が全くわからないので、これ以上追うのは厳しいです。

体感では、クロック系の切り替えが早すぎると(1秒くらい?)症状が出やすいです。何でだろう??

while :; do aplay -D hw:0,0 48k.wav ; aplay -D hw:0,0 44k.wav ; done

こんなスクリプトをグルグル回すと、44kHz系は全く音が出ません。待ち時間が足りないのかと思いPRECHARGEの後に500msのウェイトを入れましたが、結果は変わらず音が出ません。。。

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

コメント一覧

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



2018年12月22日

ROCK64のアナログオーディオ - RK3328のACODEC

目次: ROCK64/ROCKPro64

RK3328のACODECパッチをALSA MLに送ったところ、すんなり取り込まれました。やった。作者が自分ではないドライバを投稿したのは初めてかもしれません。それでも取り込まれるんですね。

あと48kHz → 44.1kHz系に切り替えたときに音が出なくなってしまう病気の応急処置パッチも取り込まれました。素早く切り替えるとやっぱり音が鳴らなくなるんですが、これ以上追う手段が無いので(2018年12月19日の日記参照)諦めています。できればRockchipの中の人に直してほしいね…。

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

編集者:すずき(2020/10/30 02:00)

コメント一覧

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



2018年12月23日

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

目次: ROCK64/ROCKPro64

RK3328のGPLL

RK3288のGPLL系のクロック周波数が、49151999のようなおかしな値になってしまう問題も、追ってみたら意外と簡単だったのでパッチを作りました。取り込まれることを祈っておきましょう。

たぶん誰も興味が無いと思いますが、下記はRK3328 GPLL系のクロック周波数がおかしくなる問題の詳細です。

RK3328のPLL周波数の決め方

まずROCK64には24MHzの水晶が載っていて、RK3328のXIN24Mに入力されています。これがFREFになります。

PLL周波数は仕様書(RK3328 TRM)によると、
FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 224)
と書かれています。

しかしこれはおそらく誤記で正しくは、
FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
だと思われます。

クロックドライバの実装も後者でしたし、hdkさんに教えてもらった他のRockchipの仕様書でも2^24になっていましたから、RK3328の仕様書にある224は2^24の誤記とみて問題ないでしょう。

最終的なPLL周波数は、
FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
となります。

クロックドライバの実装

REFDIV, FBDIV, POSTDIV1, POSTDIV2, FRACに設定される値は、クロックドライバで下記のように定義されています。

RK3328のクロックドライバ

//drivers/clk/rockchip/clk-rk3328.c

static struct rockchip_pll_rate_table rk3328_pll_frac_rates[] = {
	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
	RK3036_PLL_RATE(1016064000, 3, 127, 1, 1, 0, 134217),
	/* vco = 1016064000 */
	RK3036_PLL_RATE(983040000, 24, 983, 1, 1, 0, 671088),
	/* vco = 983040000 */
	RK3036_PLL_RATE(491520000, 24, 983, 2, 1, 0, 671088),
	/* vco = 983040000 */
	RK3036_PLL_RATE(61440000, 6, 215, 7, 2, 0, 671088),
	/* vco = 860156000 */
	RK3036_PLL_RATE(56448000, 12, 451, 4, 4, 0, 9797894),
	/* vco = 903168000 */
	RK3036_PLL_RATE(40960000, 12, 409, 4, 5, 0, 10066329),
	/* vco = 819200000 */
	{ /* sentinel */ },
};

このコードの何がおかしいのかお見せするため、試しに先頭の行の値を使ってPLL周波数を計算してみます。PLL周波数の目標値であるrateは1016064000です。その他の設定値は、

  • refdiv : 3
  • fbdiv : 127
  • frac : 134217
  • postdiv1: 1
  • postdiv2: 1

です。この設定値に基づいて各設定値を計算してみると、

  • FREF * FBDIV / REFDIV = 24000000 * 127 / 3 = 1016000000
  • (FREF * FRAC / REFDIV) >> 24 = 24000000 * 134217 / 3 / 2^24 = 63999
  • FOUTVCO = 1016063999
  • FOUTPOSTDIV = 1016063999 / 1 / 1

となってしまい、1足りない変な値になります。1足りない原因は2項目の計算結果が63999になってしまうことですから、直すにはfracの値を1増せば良いです。fracを134218にすると、

  • (FREF * FRAC / REFDIV) >> 24 = 24000000 * 134218 / 3 / 2^24 = 64000

となって、めでたしめでたしです。

以上の解析結果に基づいてfracの値を1増やすパッチをLinux MLに送りました。英語がイマイチで、うまく説明できず、原始人のような「これ値違う、俺直す」になってしまっていますが……。

RockchipのアーキメンテナのHeikoさんは、コミットメッセージがあまりにもひどいと直してくれる(昔も修正されたことがある)みたいなので、そこに甘えておきます。原始人英語がそのまま取り込まれても別に構いませんし。

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

コメント一覧

  • コメントはありません。
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 この記事にコメントする



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月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月11日

スマートプラグの利用規約

TP-Linkのスマートプラグを利用するにはKASA Smartというアプリをスマホに入れないと微塵も動きません。このアプリの利用規約には同意不可能な条項があって、

法的資格
(中略)お客様は利用にあたりお客様に適用するすべての法律を遵守しなければなりません。準拠法が利用を禁ずる場合はお客様は本サービスを利用することはできません。

ユーザーのコンテンツ
(中略)
2. 世界のあらゆる場所で享受できるユーザーコンテンツに対する全ての人格権を放棄し、そのような権利の主張ができないことを確認する。

と書いてあります。TP-Linkは、ユーザーがフォーラムに投稿した質問、レビュー、回答などを勝手に使うけど、文句言わないでね?と言いたいみたいです。

その主張については同意しますけど、、、

日本では著作者人格権は譲渡できません(著作権法59条)、放棄規定はありませんが、包括的に放棄はできないと考えられており、日本においてTP-Linkの利用規約にYesと答えることはできません。

規約内で矛盾がある場合に、利用者が同意してしまうと、この契約はどうなるんでしょう、無効になるの…?

TP-Linkは中国の会社ですから、この利用規約は中国でもほぼ同じなのではないかと思うんですが、中国って著作者人格権の放棄はできるんですかね?

スマートプラグを使ってみた

規約のことは忘れて、スマートプラグを使ってみました。

スマホから電源ON/OFFの指示を送ると、スマートプラグから「カッ!!」というかなり大きめのリレー音がしてうるさいです。今日も元気なことがわかって安心……?

使って初めて知ったのですが、スマホからスマートプラグへの電源ON/OFFの指示は必ずTP-Linkのサーバーに飛んで行くんですね。インターネット接続のできない場所ではスマホのアプリが起動しないため、電源ON/OFF指示ができません。

インターネット接続がなくても、スマートプラグ本体の電源ボタンを押せば電源ON/OFFできますが、そこまで行けるならTinker Boardを直接リセットした方が遥かに早いです。

昔のネットワーク対応電源タップとの違い

昔から、ネットワーク対応のACタップは売られていましたが(Pingを打つと電源が落ちる、WebインタフェースでON/OFFできるなど)、いずれも1万円〜数万円の製品です。

従来製品と比較して、サーバーの維持費も追加で必要なはずなのに、大抵のスマートプラグは2,000円〜5,000円で販売されています。機能の割に破格の値段だと思います。

単純に考えると、外出中(=インターネット側から)に、宅内の電源をON/OFFするため、何らかのサーバーを経由しているのでしょう。

嫌らしく考えると、スマートプラグはサーバーを経由させることで、ユーザーの生活情報を強制的に奪えますから、将来に情報が何かに使えることを見込んで、破格の値付けでばら撒いているのでしょう。

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

コメント一覧

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



2019年1月12日

Hello! Zephyr OS!!

目次: Zephyr

海外で最近話題らしいZephyr OSを動かしてみました。

Linuxに似ている、という説明をどこかで見ましたが、ビルドシステムに関して言えば全く似ていません……。コードは似ているのかもしれませんが、見ていません。

動かし方は Zephyr OSのGetting Started にあります。

事前準備

Zephyr OSをビルドするためには、いくつかPythonのパッケージをインストールする必要があります。pipを実行しても良いという方はpip3 install --user -r zephyr/scripts/requirements.txt で、依存するモジュールをインストールしてくれるそうです。

私は以前pipでPython環境が壊れて嫌な思いをしたので、apt-getで頑張りました。参考までに下記のパッケージをインストールしています。環境はDebian Testing amd64版です。

apt-getでインストールしたパッケージ(参考)
python3-colorama python3-yaml python3-pyelftools
python3-sphinx-rtd-theme sphinx-rtd-theme-common python3-breathe
ninja-build sphinx-common

パッケージが足りない場合の探し方ですけども、パッケージが足りないときはPythonのエラーメッセージにModuleNotFoundError: No module named 'aaaa' こんなメッセージが出ることが多いです。apt-file search aaaaを実行すると、パッケージ名がずらーっと出てきますので、その中からpython3- で始まるパッケージを探してください(Python3モジュールのパッケージはpython3-xxxxという名前が多い)。

コードの取得

Getting Startedの通り
git clone https://github.com/zephyrproject-rtos/zephyr
です。

クロスコンパイラの準備

Getting StartedにはZephyr SDKとやらをインストールせよと書いてありますが、色々大切な部分が全部ぶっ飛んでいてわからなくなっている感じがします。幸いcrosstool-NGにも対応していると書いてあったので、crosstool-NGを使ってみました。

基本的には以前紹介した(2018年7月15日の日記参照)、AArch64 Linux用の環境と同じ手順ですが、./ct-ng menuconfigで設定する項目が多少違います。

crosstool-NGビルド
$ ./ct-ng menuconfig

Target options --->
  Target Architecture   --->
    armにする
  Bitness:   --->
    32-bitにする

Toolchain options  --->
  Tuple's vendor string
    zephyrにする

Operating System  --->
  Target OS   --->
    bare-metalにする


$ ./ct-ng build
[00:34] /

しばらく待つとarm-zephyr-eabiというプレフィクスを持つクロスコンパイラが生成されるはずです。

クロスコンパイラの指定

Zephyr OSのビルドに使用するクロスコンパイラを、~/.zephyrrcに環境変数を定義して指定します。変な作りだなあ……。

クロスコンパイラの指定

export ZEPHYR_TOOLCHAIN_VARIANT=xtools
export XTOOLS_TOOLCHAIN_PATH=/home/katsuhiro/x-tools

注意点としてはXTOOLS_TOOLCHAIN_PATHのx-toolsの後のパスは勝手にarm-zephyr-eabiが使われ、自由に指定できないことです。この点についてはLinuxのCROSS_COMPILE環境変数とは異なるうえ、Zephyrの方が後発にも関わらず退化しています。どうしてこうなった……。

ビルド準備

ビルドする前に2手ほど準備が必要です。1手目は環境変数のセットアップです。

環境変数のセットアップ
cd zephyr
source zephyr-env.sh

2手目はcmakeの実行です。

cmakeの実行
$ cd sample/hello_world
$ mkdir build

$ cd build
$ cmake -GNinja -DBOARD=qemu_cortex_m3 ../

Zephyr version: 1.13.99
-- Found PythonInterp: /usr/bin/python3 (found suitable version "3.7.2", minimum required is "3.4")
-- Selected BOARD qemu_cortex_m3
Parsing Kconfig tree in /home/katsuhiro/share/projects/oss/zephyr/Kconfig
Loading /home/katsuhiro/share/projects/oss/zephyr/boards/arm/qemu_cortex_m3/qemu_cortex_m3_defconfig as base
Merging /home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/prj.conf
Configuration written to '/home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/build/zephyr/.config'
-- Loading /home/katsuhiro/share/projects/oss/zephyr/boards/arm/qemu_cortex_m3/qemu_cortex_m3.dts as base
-- Overlaying /home/katsuhiro/share/projects/oss/zephyr/dts/common/common.dts
-- Cache files will be written to: /home/katsuhiro/.cache/zephyr
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /home/katsuhiro/x-tools/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
-- Performing Test toolchain_is_ok
-- Performing Test toolchain_is_ok - Success
-- Configuring done
-- Generating done
-- Build files have been written to: /home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/build

CMakeを採用しているプロジェクトは大抵、ソースコードのトップディレクトリにあるCMakeLists.txtを指定しますが、Zephyr OSの場合、sample/* の下にあるCMakeLists.txtを使わなければなりません。わからんわ、そんなの。変な作りだな……。

間違ってZephyr OSのトップディレクトリにあるCMakeLists.txtを指定すると、こんなエラーメッセージで怒られます。

cmakeを間違ってトップディレクトリのCMakeLists.txtに対して実行したとき
$ cmake -GNinja -DBOARD=qemu_cortex_m3 ../
CMake Error at CMakeLists.txt:13 (message):
  A user error has occured.

  cmake was invoked with '/home/katsuhiro/share/projects/oss/zephyr'
  specified as the source directory,

  but it must be invoked with an application source directory,

  such as '/home/katsuhiro/share/projects/oss/zephyr/samples/hello_world'.

  Debug variables:

  CMAKE_CACHEFILE_DIR:



CMake Warning (dev) in CMakeLists.txt:
  No cmake_minimum_required command is present.  A line of code such as

    cmake_minimum_required(VERSION 3.13)

  should be added at the top of the file.  The version specified may be lower
  if you wish to support older CMake versions for this project.  For more
  information run "cmake --help-policy CMP0000".
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring incomplete, errors occurred!

エラーメッセージからは、何が悪いのか全く分かりません……。

ビルドと実行

ビルドと実行は難しくありません。どちらかというとここまでたどり着くのがかなり面倒くさいです。

ビルドと実行
$ cd sample/hello_world/build
$ ninja
[1/103] Preparing syscall dependency handling
 
[98/103] Linking C executable zephyr/zephyr_prebuilt.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:        8604 B       256 KB      3.28%
            SRAM:        4160 B        64 KB      6.35%
        IDT_LIST:         120 B         2 KB      5.86%
[103/103] Linking C executable zephyr/zephyr.elf


$ ninja run
[0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-m3
qemu-system-arm: warning: nic stellaris_enet.0 has no peer
***** Booting Zephyr OS zephyr-v1.13.0-3162-g73956a398e *****
Hello World! qemu_cortex_m3

何をしているのか全然わかりません。仕方ないのでbuild.ninjaファイルからqemuを実行しているところを発掘してみたら、下記のコマンドを実行しているようです。

実際に実行しているコマンド
$ /usr/bin/qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -vga none -net none -pidfile qemu.pid -serial mon:stdio -kernel /home/katsuhiro/share/projects/oss/zephyr/samples/hello_world/build/zephyr/zephyr.elf

qemu-system-arm: warning: nic stellaris_enet.0 has no peer
***** Booting Zephyr OS zephyr-v1.13.0-3162-g73956a398e *****
Hello World! qemu_cortex_m3

期待される結果が良くわからないんですが、これで動いたと言って良いんだろうか…??

編集者:すずき(2023/09/24 12:01)

コメント一覧

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



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

管理用メニュー

link 記事を新規作成

<2018>
<<<12>>>
------1
2345678
9101112131415
16171819202122
23242526272829
3031-----

最近のコメント5件

  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」
  • link 24年5月17日
    すずきさん (05/20 13:16)
    「そうですねえ、普通はStandardなの...」

最近の記事3件

  • link 24年6月27日
    すずき (06/30 15:39)
    「[何もない組み込み環境でDOOMを動かす - その4 - 自作OSの組み込み環境へ移植] 目次: RISC-V目次: 独自OS...」
  • link 22年12月13日
    すずき (06/30 15:38)
    「[独自OS - まとめリンク] 目次: 独自OS一覧が欲しくなったので作りました。自作OSの紹介その1 - 概要自作OSの紹介...」
  • link 21年6月18日
    すずき (06/29 22:28)
    「[RISC-V - まとめリンク] 目次: RISC-VSiFive社ボードの話、CoreMarkの話のまとめ。RISC-V ...」
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 www.katsuster.net
RDFファイル RSS 1.0

最終更新: 06/30 15:39