s0911
2024年7月12日 19時16分
Armadillo610上に以下の環境を配置しています。
・ABOS 3.19.1-at.4
・コンテナ内OS Debian GNU/Linux 11 (bullseye)
コンテナ内のアプリより、ioctlにて連続的にSPI通信を実施しています。
通信自体は成功しているのですが、ABOS内の他のプロセスが原因でSPIドライバの処理時間が揺れます。
1ms以上ioctlの処理を停止(または中断)する可能性のある周期的なプロセスをご教示いただけないでしょうか。
コメント
at_ohsawa
s0911
> ちなみに、具体的に何のioctlを発行してどういう処理をしているのか
> 説明は可能でしょうか。
> 内容によっては、本質的に異なる手段で解決できるかもしれません。
>
ご教授ありがとうございます。niceの調整を実施してみます。
他の信号をトリガに、SPI_IOC_MESSAGE(N)にて通信処理を回しています。
常時SPI通信にてデータを受信・中身を確認し、その他の作業を実施する際にのみSPI通信停止、を繰り返す処理を考えていますので、
常時SPI通信実施時のみ、他のカーネル関連プロセスやEtherなどのI/FにCPUを占拠されないように設計したいと考えています。
at_ohsawa
> 他の信号をトリガに、SPI_IOC_MESSAGE(N)にて通信処理を回しています。
SPI_IOC_MESSAGE(N)の場合トランザクション完了まで必ずブロッキングするので
プロトコル上可能であればノンブロッキングでopenして個別にread/writeを発行したら
selectでデータ入った場合だけ中身の確認等の処理を動かすようにした方が単位時間あたりで
プロセスに回ってきた時間を効率的に使え結果として時間のブレが減る可能性があります。
(Nが1なら意味が無いですが)
これは読みと処理で2スレッド動かしても同じ理屈です。キモはノンブロッキングの
read/writeであればspi信号の駆動を呼び出すコードの実行を自分のアプリのプロセス
としては待たずに、前回入ったデータの処理が空き時間可能になります。
(毎回ブロッキングすると、タイミングによって自分のプロセスに回ってきた時間を
単に待つだけに使って、本来ならできるread/write以外の処理をしないうちに他のプロセス
にCPUを渡します。)
>常時SPI通信実施時のみ、他のカーネル関連プロセスやEtherなどのI/FにCPUを占拠されないように設計したいと考えています。
これは当然ですが”通信は他のプロセスに邪魔されているわけではない”です。
他の処理でCPUを占拠されているわけではなく、その処理自体がいつ実行
されるのかというタイミングの話です。
(当然ですがCPUの計算クロックはSPIデバイス自体とタイミングが”同期”
しているわけじゃないので、SPIの信号をいつ出すと最も効率よく
システム全体が動くのか予測することはできません。)
極力OSの全機能に問題を起こさないようにマルチプロセスするOSである以上、
前述のとおり、動く時期自体を完全にSPI優先にすると他のドライバが壊れるので
ドライバ内に”できる限り”期待の周期で動くことを想定したバッファを作るくらいで
あればやっても壊れないとは思いますが(iioでそういう実装をしているドライバも
一部あります)単一コアの場合はどうしても100%にはなりません。
やはり100%精度を求める方の場合は、外部にマイコンをつけると聞き及んでいます。
at_ohsawa
2024年7月12日 19時59分
> Armadillo610上に以下の環境を配置しています。
> ・ABOS 3.19.1-at.4
> ・コンテナ内OS Debian GNU/Linux 11 (bullseye)
>
> コンテナ内のアプリより、ioctlにて連続的にSPI通信を実施しています。
> 通信自体は成功しているのですが、ABOS内の他のプロセスが原因でSPIドライバの処理時間が揺れます。
>
> 1ms以上ioctlの処理を停止(または中断)する可能性のある周期的なプロセスをご教示いただけないでしょうか。
niceを最低にして実行してみたら、改善しますか?
(nice -n -20 myappのように起動します。niceの最低値は-20ですが
この値はシステム全体にとってCPUを使わずにniceであるかどうか、
なので最低の-20にすると優先して使うということです)
もし改善するなら、それはプロセススケジューラーそのものによる遅れで、
Linuxを使う限り逃れることはできません。
ioctlを含むシステムコールは、そのシステムコールを呼んでいる
プロセスコンテキストで動くため、当然ですがCPUがそのプロセス
(=そのioctlを呼んでるアプリ)の実行に切り替わる必要があります。
一方、LinuxはRTOSではないので、プロセスのスケジュール周期を
保証できないため、単一のコアしかないA610では尚更他のプロセスが
動くタイミングの変動があれば、時間は一定しません。
(例えば、ボード全体で同じような処理しかしていなくても、あるときに
Etherパケットの到達が有って割り込みが起きたり、ファイルシステムの
バッファが容量や時間要因でフラッシュされたりすると、あるプロセスに
回ってくるタイミングがズレます)
なので、支配的な単独の要因があるわけではないです。
(というより、マルチタスクOSであるということが原因です。)
解決方法としては100%ジッタ無しを保証したい場合は、
デバイスドライバを書いてkernelモードでタイマ割り込みを掛けて
割り込み禁止状態で(A610はシングルコアなのでkernelとしての
すべての機能を止めて)データを読む実装にするという方法がありますが、
これは当然ですが他のkernel内部の”時間を守らないといけないハードウェア
I/F等の時間制約”を破壊する可能性があります。
とくにシングルコアのCPUを搭載したA610の上では、慎重なテストと
よく理解した実装が必要になりますし、処理時間によっては
OSとしての機能が破綻するため実装できない場合もあります。
2つ目に、100%ジッタ無しでもいいのである程度周期を優先したい場合は
前述の通りniceを下げ、それでも不足の場合にプロセススケジューラを
変更してみると良いのですが、
まずもって、ms単位の周期のリアルタイム性を求める場合はRTOSではない
Linuxでの直接処理はせず、マイコン等を前段に入れる場合や、単純な
信号の割り込みでトリガしてドライバで刈り取れるような設計にすること
が多いと思います。