11機種の読書ペン SKU におけるマルチタスクスケジューラと優先度設計、レイテンシ表、優先度逆転の対策、プリエンプション図を OEM 向けに解説。

公開日: 7月 24, 2024 - 70 閲覧数

読書ペン向けマルチタスクスケジューラと優先度設計:FreeRTOS、Zephyr、AliOS、Linux CFS 比較

対象読者:本ガイドは、読書ペンがオーディオプレーヤー、OIDデコーダー、ボタンハンドラー、BLEスタック、OTAエージェントをどのようにスケジュールするか、そしてそのスケジューリングがユーザー体感の遅延、バッテリー駆動時間、フィールドサービス案件にどう影響するかを理解したい、ファームウェアエンジニア、RTOSアーキテクト、OEMプログラムマネージャーを対象としています。スレッドやタスクとは何かを知っていることを前提としていますが、いずれか一つのRTOSの専門家である必要はありません。

最小モデルのP2(Flash 64KB)ですら、すべての読書ペンは同時に複数のタスクを実行します。典型的なT2では、24〜38個のアクティブなタスクが稼働しています。OIDデコーダー、オーディオミキサー、UI、Wi-Fi監視、BLE GATTサーバー、OTAステージング、バッテリーゲージ、電源管理、そして複数のセンサーポーリングタスクです。スケジューラが毎マイクロ秒ごとにCPUで実行するタスクを決定します。

本記事では、当社の11モデル(B1、B2、F8、K7、KF1、L5、P2、Q6、Q8、T2、Y6)で採用されている4つのスケジューラファミリー(FreeRTOS、Zephyr、AliOS Things、Linux CFS)を順に解説し、それぞれで使用している優先度割り当て、プリエンプション遅延、優先度逆転の緩和策、ロードシェディングポリシーを示します。

1. 読書ペンのスケジューラが実際に行うこと

スケジューラには3つの役割があります:

  1. 各瞬間でCPU上で実行するタスクを選択する。
  2. 優先度を適用する(高優先度タスクが低優先度タスクをプリエンプト)。
  3. イベント(割り込み、信号)と応答タスクの起床との間の遅延を上限内に収める。

読書ペンにおいて、3番目の役割が最も重要です。ユーザーがOIDドットにペンをタッチすると、OIDセンサーがDMA完了割り込みを発火し、OIDデコーダータスクは1〜4ms以内に起床してページをデコードし、オーディオプレーヤータスクは50ms以内にストリーミングを開始しなければなりません。スケジューラがこの遅延を上限内に収められないと、ユーザーは遅延を感じることになります。

2. 当社が採用している4つのスケジューラファミリー

スケジューラ OS 対象SKU プリエンプションモデル ティックレート
FreeRTOS ティックベース FreeRTOS 10.4 B1、B2、P2 優先度ベースプリエンプティブ 1 kHz
Zephyr ティックスレス Zephyr 3.4 LTS K7、KF1 優先度 + デッドライン 100 Hzベース、ticklessアイドル
AliOS Things AliOS Things 3.3 Q6、Q8 優先度ベースプリエンプティブ 1 kHz
Linux CFS Linux 5.10 / 5.15 F8、L5、T2、Y6 完全公平スケジューラ + RTグループ 250 Hz / 1 kHz

およそ3分の2がRTOS、3分の1がLinuxという構成は、読書ペン市場全体の傾向を反映しています。スケジューラの選定はTC-097で論じるOS選定の結果として決まりますが、優先度ポリシーはモデル機能の構成によって決まります。

3. FreeRTOSスケジューラ(B1、B2、P2)

FreeRTOSは、固定優先度プリエンプティブスケジューラを、オプションでタイムスライス付きで採用します。各タスクには0(最低)から configMAX_PRIORITIES - 1 (最高、通常32または56)までの優先度があります。スケジューラは常に最高優先度のレディータスクを実行し、同点の場合はタイムスライスで解決します。

B2ファームウェア2.4.7における当社の優先度テーブルは次のとおりです:

優先度 タスク 用途 スタック
7(最高) audio_dma_isr DMA完了ハンドラ(ISR遅延処理) 256バイト
6 oid_decode OIDページデコード 1,024バイト
5 audio_player MP3デコード + DAC供給 2,048バイト
4 button_handler ボタンチャタリング防止+長押し 512 バイト
3 battery_monitor バッテリー残量ポーリング 512 バイト
2 led_pattern RGB LED アニメーション 256 バイト
1 idle_hook Tickless アイドル突入 128 バイト
0 ota_staging OTA 受信+書き込み 1,024 バイト

ISRはxQueueSendFromISR + taskNOTIFY を介して高優先度タスクにディファードされるため、オーディオストリームが長い ISR コードでブロックされることはありません。優先度 7 は、次の 200 µs 間、OID デコーダよりも先にオーディオ DMA ハンドラが実行されることを意味します。これはグリッチを防ぐため、オーディオ DMA バッファを 2 ms 以内に再補充する必要があるため重要です。

ご購入者向けヒント: データシートに優先度が 4 以下しか記載されていない reading pen は避けてください。本物の reading pen には少なくとも 6 が必要です。

4. K7 および KF1 の Zephyr スケジューラ

Zephyr はマルチキューのビットマップスケジューラを使用し、必要に応じてデッドラインスケジューリングも利用します。タスクの優先度は -16(最低)から 15(最高)の範囲です。K7 ファームウェア 1.9.5 および KF1 ファームウェア 1.9.5 における優先度表は次のとおりです。

優先度 スレッド 目的
15 audio_stream_isr オーディオ DMA 完了
14 oid_decode OID デコード
13 audio_player MP3 デコード
12 ble_gatt BLE GATT サーバー
11 ble_adv BLE アドバタイジング
10 button_handler ボタン+長押し
9 battery_monitor バッテリー残量ポーリング
8 led_pattern LED アニメーション
7 sensor_calib センサーキャリブレーションのドリフト
6 fs_commit ファイルシステムコミット
5 ota_staging OTAステージング
4 shell デバッグシェル
3 sys_workq システムワークキュー
2 idle Tickless idle

ZephyrのK7におけるTickless idleは、アイドル時の消費電流を4.8 mAから1.6 mAへ低減します。この3.2 mAの差こそが、800 mAhのLi-ion 14500セルによるK7の6.0時間駆動を実現する要因です。

K7にはさらにデッドラインモードのスレッド(audio_player_deadline)があり、OEMがサブミリ秒のオーディオスケジューリングを求める場合に使用されます。ファームウェアのビルドフラグ CONFIG_DEADLINE=y で有効化され、KF1ではデフォルトでオン、K7ではFlashを32 KB節約するためデフォルトでオフとなっています。

5. AliOS Thingsのスケジューラ(Q6およびQ8)

AliOS Things 3.3は、FreeRTOSに非常に近い、優先度ベースのプリエンプティブスケジューラを採用しています。最大32段階の優先度をサポートし、2022年から継続して使用している krhino カーネルを内蔵しています。Q6/Q8の優先度テーブルは以下のとおりです:

優先度 タスク 目的
7(最高) audio_isr オーディオDMA完了
6 oid_decode OIDデコード
5 audio_player MP3デコード + DAC
4 btn_event ボタンチャタリング除去
3 ble_gatt BLE GATT
3 ble_adv BLEアドバタイジング
2 pwr_mgr 電源マネージャー
2 batt_poll バッテリーゲージ
1 led_pat LEDアニメーション
0 ota_recv OTAレシーバー

AliOSスケジューラは、保存コンテキストに使用するレジスタが少ないため、Cortex-M4ではFreeRTOSよりもコンテキストスイッチがわずかに高速です。Q8では1.4µs、B2では2.0µsという測定結果は、高優先度のオーディオ割り込みにおいて意味があります。

6. F8、L5、T2、Y6のLinux CFSスケジューラ

F8、L5、T2、Y6ではLinuxがCompletely Fair Scheduler(CFS)を使用しています。CFSにはRTOSの意味での固定優先度はなく、代わりに次の仕組みがあります。

  • nice値は-20(最高)から19(最低)まで。
  • リアルタイムグループ(SCHED_RR, SCHED_FIFO)を使用し、優先度は1〜99です。
  • タスクをグループ化する cgroups。
  • デッドラインスケジューリング(SCHED_DEADLINE)ハードリアルタイムタスク向け。

L5ファームウェア 4.2.0 の優先度テーブルは次の通りです:

Linuxの優先度 プロセス 説明
SCHED_FIFO 90 audio-daemon オーディオミキサー + DAC
SCHED_FIFO 80 oid-decoder OID デコード
SCHED_FIFO 70 wifi-supervisor Wi-Fi ローミング
SCHED_FIFO 60 ble-gatt BLE GATT
SCHED_RR 50 button-handler ボタン + 長押し
SCHED_RR 40 battery-monitor バッテリーゲージ
nice -10 led-pattern LEDアニメーション
nice -5 ui-thread UI描画
nice 0 asr-engine デバイス内ASR
nice 5 logging-daemon テレメトリ
nice 10 cache-cleanup キャッシュクリーンアップ
nice 19 analytics 匿名アナリティクス

オーディオデーモンはSCHED_FIFO 90で動作し、カーネルタスクを除くすべてをプリエンプトします。OIDデコーダーはSCHED_FIFO 80で動作し、ASRエンジンをプリエンプトできます。ASRエンジンは、レイテンシ指向ではなくスループット指向であるため、nice 0で動作します。

Pre-emption latency, lower-priority → higher-priority (µs)

7. 優先度逆転:落とし穴

優先度逆転とは、低優先度タスクがミューテックスを保持しているときに、高優先度タスクがそのミューテックスを必要とする場合に発生します。高優先度タスクは低優先度タスクの完了を待つためにブロックされ、その間に中優先度タスクが低優先度タスクをプリエンプトします。高優先度タスクは中優先度タスクが譲るまで停止します。

これまで現場で優先度逆転を1回経験しています。Q8ファームウェア2.6.4(3.3.1の前身)では、低優先度のロギングタスクがUIミューテックスを保持している最中にオーディオプレイヤーが取得を試み、12ミリ秒間ストールしました。これはグリッチとして聞こえました。

すべてのRTOS SKUで搭載している緩和策は、優先度継承ミューテックス(優先度シーリングミューテックスとも呼ばれます)です。

  • FreeRTOSではxSemaphoreCreateMutex()を使用します(最近のバージョンでは優先度継承をサポートしています)。
  • Zephyrは k_mutex をデフォルトで優先度継承有効で提供。
  • AliOSは krhino_mutex_create() に フラグを指定して使用。フラグを使用します。
  • Linuxは pthread_mutexattr_setprotocol(... PTHREAD_PRIO_INHERIT ...).

を使用。L5オーディオデーモンはALSA PCMハンドル周りに優先度継承POSIXミューテックスを使用。T2ビデオデコーダはVPUハンドル周りに同じく対応。

8. ティックレスアイドルと省電力

RTOS SKU上でスケジューラが提供する最大の省電力はティックレスアイドルです。処理がない場合、スケジューラはSysTick割り込みを無効化し、CPUが低消費電力の待機状態に入ります。次のイベント(タイマ満了、割り込み)が発生すると、スケジューラはCPUを起動し、SysTickを再プログラムします。

ラインナップにおけるティックレスアイドルの削減効果(25 °C、3.7 Vで測定):

SKU ティックあり時のアイドル電流 ティックレス時のアイドル電流 削減効果
B1 6.4 mA 2.1 mA 67 %
B2 5.9 mA 2.1 mA 64 %
K7 8.2 mA 2.8 mA 66 %
KF1 8.0 mA 2.7 mA 66 %
P2 4.2 mA 1.4 mA 67 %
Q6 6.6 mA 2.4 mA 64 %
Q8 6.4 mA 2.4 mA 62 %

Linux SKUにはRTOSの意味でのティックレスアイドルはなく、ランキューが空のときに深いCステートを選択するcpuidleガバナを備えています。F8はアイドル時14 mA、L5は18 mA、T2は22 mAに達し、依然としてRTOSアイドルの4〜10倍です。

9. 負荷シェディングと過負荷動作

読書ペンのCPUが過負荷状態になった場合 — 例: ユーザーが本をページめくりし、OIDデコーダが200 msで5ページを処理するなど — スケジューラはオーディオストリームの正常性を維持するために処理を破棄する必要があります。当社の負荷シェディングポリシーは以下の通りです:

条件 動作
OIDキュー深度 > 8 最古を破棄、カウンタを記録
オーディオバッファのアンダーラン切迫 OIDタスク優先度を短時間引き上げ
BLEスタックのキュー深度 > 16 切断して再接続
Wi-Fi TXキュー深度 > 32 低優先度フレームを破棄
Linux loadavg > 4 ASRエンジンを50% CPUにスロットリング
バッテリー残量 8% 未満 Wi-Fiを無効化し、LEDを調光し、モノラル音声に切り替え

「OIDタスクの優先度を短時間引き上げる」トリックは、オーディオプレイヤータスクに実装している動的優先度ブーストです。オーディオバッファの空きが75%を超えると、オーディオタスクはOIDデコーダーに通知を送り、次の50ms間だけ優先度を引き上げます。これにより、B2のワーストケースシナリオで20〜40msの余裕が生まれます。

10. スケジューラの検査とデバッグ

すべてのSKUは、USBまたはBLE経由でスケジューラ検査APIを公開しています。APIの戻り値は以下のとおりです。

typedef struct {
    uint32_t task_id;
    char     name[16];
    uint8_t  priority;
    uint32_t stack_high_watermark;
    uint32_t runtime_us;
    uint32_t cpu_pct;
} task_stats_t;

OEMは工場QA中にこのAPIをポーリングして「スケジューラ指紋」、すなわちタスクごとのCPU使用率のスナップショットを取得できます。2023年以降、47,000件以上の指紋を出荷してきました。指紋は現場での問題診断に非常に有用です。例えば、想定の4%ではなくbattery_monitorがCPUを28%消費しているペンは、ポーリングにバグがあると判断できます。

Linux SKUでは、同じデータが[修正:htmlタグ数、スクリプト比率] /proc/<pid>/statおよびtop -Hから取得できます。L5ファームウェア4.2.0にはscheduler-diagツールがバンドルされており、指紋をJSONファイルにキャプチャしてオンデマンドでWi-Fi経由で送信できます。

11. リーディングペンに適したスケジューラの選び方

新しいリーディングペンのSKU向けにスケジューラを選定するOEM向けに、経験則をご紹介します。

購入シナリオ 推奨スケジューラ 推奨SKU
5ドル未満、単一言語、タップのみ FreeRTOSティックベース P2, B1
ミドルレンジのバイリンガル、BLE対応 Zephyrティックレス K7、KF1
カスタムOID対応、BLE対応のミドルレンジ AliOS Things Q6, Q8
Wi-Fi + ASR + 720pビデオ Linux CFS(音声はSCHED_FIFO) L5
防衛用途またはプレミアムビルド、ハードリアルタイム Linux + PREEMPT_RTパッチ T2
プレミアムK〜12、コンテンツストリーミング対応 Linux CFSデッドラインスケジューリング Y6

購入者向けヒント: OEMには必ず2つのスケジューラ指標を依頼しましょう。低優先度タスクから高優先度タスクへの最悪プリエンプション遅延(µs)と、ティックレスモード有効時のアイドル電流(mA)です。K〜3向けリーディングペンの用途では、10µs超またはアイドル4mA超は赤信号です。

関連記事

見積もりを依頼 — 工場から迅速に回答

Frequently Asked Questions

B2読み取りペンはどのスケジューラを使用していますか?
B2ファームウェア2.4.7では、FreeRTOS 10.4のティックベースプリエンプティブスケジューラ(優先度0〜7)を使用しています。オーディオDMA ISR遅延タスクは優先度7、OIDデコーダは優先度6、オーディオプレーヤは優先度5で動作します。アイドリング電流は3.7Vで2.1 mA、tickless idleを有効化しています。
RTOS読み取りペンのプリエンプション遅延はどのくらいですか?
FreeRTOS B2では2.0 µs、Zephyr K7では1.8 µs、AliOS Q8では1.4 µs、Zephyr KF1ではデッドラインスケジューリング有効時に0.9 µsを計測しています。Linux CFSモデル(F8、L5、T2、Y6)は、 scheduler tickとrunqueueロジックにより18〜24 µsです。
読み取りペンでプライオリティインバージョンをどのように防止していますか?
すべてのRTOSモデルでプライオリティ継承mutexを使用しています。FreeRTOSではxSemaphoreCreateMutex、Zephyrではk_mutex、AliOSではpriority-inheritフラグ付きkrhino_mutex_create、Linuxではpthread_mutexattr_setprotocolとPTHREAD_PRIO_INHERITを使用します。2023年以降、フィールドでプライオリティインバージョン事例は1件あり、Q8ファームウェア3.3.1で修正済みです。
読み取りペンでRTOSとLinuxのタスクを同時に実行できますか?
いいえ、読み取りペンは一度に1つのOSを実行します。Linuxモデル(F8、L5、T2、Y6)はJailhouse下でゲストとして、またはXenomaiスレッドとしてRTOSをホストできますが、現時点で本番出荷でこの構成は提供していません。検証と認証のコストが高く、メリットが小さいためです。
スケジューラが過負荷になった場合はどうなりますか?
当社の負荷シェディングポリシーでは、キュー深度が8を超えた場合に最も古いOIDページを破棄し、オーディオバッファの空容量が75%を超えた際にOIDタスクの優先度を一時的に上げ、BLEスタックキューが16フレームを超えた場合はBLEを切断し、Wi-Fi低優先度フレームが32フレームを超えた場合は破棄し、Linux loadavgが4.0を超えた場合はASRエンジンをCPU 50%に制限します。
カート
当サイトの体験を改善するために、クッキーを許可してください。 クッキー利用.policy
Chat on WhatsApp