0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OSで使うTickは、実際にはどのように使い、どのように実時間と変換していますか。

なるほど。「OSで使うTick」についてですね。リアルタイムOS(RTOS)や一般OSでのTickは、基本的にシステム内部での時間単位として使われます。順を追って説明します。

  1. Tickとは
    TickはOS内部でのクロックカウント単位です。
    ハードウェアタイマ(例えばマイクロコントローラのSysTickやチップ内タイマ)によって一定周期で発生します。
    OSはこのTickを基準にしてスケジューリングやタイマ管理、遅延処理を行います。
    例:
    Tick周期 = 1ms → 1秒 = 1000 Tick
    Tick周期 = 10ms → 1秒 = 100 Tick
  2. 実時間との関係
    Tickを実時間に変換するには Tick周期(1 Tickあたりの時間)を使います。
    実時間[秒]=Tick数×Tick周期[秒]
    例:
    Tick周期 = 1ms(0.001秒)
    500 Tick → 500 × 0.001 = 0.5秒
  3. Tickの使われ方
    タスクスケジューリング
    タスクの実行時間やスリープ時間の計算にTickを使用
    OSはTickが進むごとに「タスクの待ち時間」を減算し、0になったらタスクを起床
    タイマ処理
    ソフトウェアタイマ(Delay、Timeout)もTick単位で管理
    ハードウェアタイマがOS Tickを発生 → OS内部でソフトタイマをカウント
    時間計測
    OS Tickカウンタから経過時間を計算
    例: ミリ秒単位のタイムスタンプを取得する場合
  4. 実装例(擬似コード)
#define TICK_PERIOD_MS 1 // 1 Tick = 1ms
volatile uint32_t tick_count = 0;

// タイマ割込みハンドラ(ハードウェアタイマ)
void SysTick_Handler(void) {
    tick_count++; // OS Tickを進める
}

// 現在のTick取得
uint32_t OS_GetTick(void) {
    return tick_count;
}

// Tickを実時間(ms)に変換
uint32_t TickToMs(uint32_t tick) {
    return tick * TICK_PERIOD_MS;
}

// 500ms待つ関数
void DelayMs(uint32_t ms) {
    uint32_t start = OS_GetTick();
    while ((OS_GetTick() - start) < (ms / TICK_PERIOD_MS)) {
        // 待機
    }
}
  1. 注意点
    Tick周期が粗い場合(例えば10ms)、精密なタイミングは難しい
    高精度が必要ならハードウェアタイマを直接使うか、Tickとは別にカウンタを使う
    Tickは整数で管理されるため、オーバーフローに注意
    32bit Tickだと、1ms周期で約49日でオーバーフロー
    もし希望であれば、Tickを使ったリアルタイムOSのスケジューリングの具体例や、Tickとタイムスタンプを結びつける方法も図解付きで説明できます。
    図解付きで見たいですか?

OS側とTimer側とアプリ側の3種類のソースコードでご説明ください。

了解です。では OS側(Tick管理・スケジューラ)、ハードウェアタイマ側、アプリ側(タスク利用) の3層で、Tickの扱いを具体的に示します。例はC言語で、一般的なRTOS風にします。

  1. Timer側(ハードウェアタイマ)
    ハードウェアタイマは一定周期で割込みを発生させます。ここでは 1ms周期 を例にします。
// Timer側: ハードウェアタイマ設定と割込みハンドラ
#define TICK_PERIOD_MS 1

volatile uint32_t hw_tick = 0; // ハードウェアTickカウンタ

// タイマ割込みハンドラ(毎1ms)
void Timer_IRQHandler(void) {
    hw_tick++;              // ハードウェアTickを進める
    OS_TickUpdate();        // OSにTickを通知
}

// 初期化
void Timer_Init(void) {
    // ハードウェアタイマを1ms周期に設定
    // 実装はマイコン依存(例: SysTick, GPTなど)
    StartHardwareTimer(1);  
}
  1. OS側(Tick管理とスケジューリング)
    OSはハードウェアTickを受け取り、タスク管理やソフトタイマを更新します。
// OS側: Tick管理・スケジューラ
#define MAX_TASKS 10

typedef struct {
    void (*task_func)(void);
    uint32_t delay_tick; // 残り待ちTick
    uint8_t ready;       // 実行可能フラグ
} Task;

Task tasks[MAX_TASKS];
volatile uint32_t os_tick = 0;

// ハードウェアTimerから呼ばれる
void OS_TickUpdate(void) {
    os_tick++;

    // タスク遅延管理
    for (int i = 0; i < MAX_TASKS; i++) {
        if (tasks[i].delay_tick > 0) {
            tasks[i].delay_tick--;
            if (tasks[i].delay_tick == 0) {
                tasks[i].ready = 1; // タスク起床
            }
        }
    }

    // 簡易スケジューラ(ラウンドロビン)
    for (int i = 0; i < MAX_TASKS; i++) {
        if (tasks[i].ready) {
            tasks[i].task_func(); // タスク実行
            tasks[i].ready = 0;   // 実行済み
        }
    }
}

// タスク登録
void OS_CreateTask(void (*func)(void), uint32_t delay_ms) {
    for (int i = 0; i < MAX_TASKS; i++) {
        if (tasks[i].task_func == NULL) {
            tasks[i].task_func = func;
            tasks[i].delay_tick = delay_ms / TICK_PERIOD_MS;
            tasks[i].ready = 0;
            break;
        }
    }
}

// 現在Tick取得
uint32_t OS_GetTick(void) {
    return os_tick;
}
  1. アプリ側(Tickを使った処理)
    アプリはOSのTickを利用して遅延やタイムアウト処理を行います。
// アプリ側: タスク
#include <stdio.h>

void Task1(void) {
    printf("Task1 executed at tick %lu\n", OS_GetTick());
}

void Task2(void) {
    printf("Task2 executed at tick %lu\n", OS_GetTick());
}

int main(void) {
    Timer_Init();                   // ハードウェアタイマ初期化
    OS_CreateTask(Task1, 1000);     // 1000ms後に実行
    OS_CreateTask(Task2, 500);      // 500ms後に実行

    while (1) {
        // メインループはOSのTickで管理される
        // 遅延タスクはOSスケジューラが呼び出す
    }
}

✅ 動作イメージ
Tick タスク状態
500 Task2 起床 → 実行
1000 Task1 起床 → 実行
1500 Task2 再登録(必要なら)
Timer側:ハードウェア割込みで1msごとにTick発生
OS側:Tickを受け取りタスクの遅延カウント更新・スケジューリング
アプリ側:OSのTickに基づいてタイミング制御
必要であれば、ソフトタイマ(複数の時間イベントを管理) や Tickオーバーフロー対応 も加えた完全版サンプルを作ることもできます。
作ってほしいですか?

00MHzと200MHzのCPUの例で、ドライバ、OSの処理の違いを示してください。

了解です。では、CPUクロックが 100 MHz と 200 MHz の場合で、ハードウェアドライバ・OS・アプリケーション処理 がどう違うかを具体例で示します。Tickを使ったRTOS環境で考えます。

  1. 前提条件
    項目 100 MHz CPU 200 MHz CPU
    タイマ周波数 100 MHz 200 MHz
    Tick周期(1ms想定) 100,000クロック/1ms 200,000クロック/1ms
    OS処理時間(1 Tickあたり) 10 µs 5 µs
    ドライバ処理(Timer IRQ) 5 µs 2.5 µs
    アプリ処理(タスク) 50 µs 25 µs
    ※概算値です。CPUクロックが2倍になると、同じ命令数でも処理時間は半分になります。
  2. Timer側(ハードウェアタイマ)
    ポイント:
    Tick発生周期は同じ(1 ms)
    CPUが速くなると、割込み処理に使うCPU時間は減る
    ハードウェアタイマの設定は変わらない(Timerのカウント値が変わる)
    // Tick周期 = 1ms
    #define TICK_PERIOD_MS 1

void Timer_IRQHandler(void) {
hw_tick++; // Tickを進める
OS_TickUpdate(); // OSに通知
// CPU速度によって処理時間が変わる
// 100MHz: 約5µs, 200MHz: 約2.5µs
}
3. OS側(Tick処理・スケジューラ)
ポイント:
Tickカウントやタスクスケジューリングは同じ
CPU速度が速いと、タスク管理や遅延処理の計算がより短時間で終わる
Tick周期を変えずに精度を上げることも可能
void OS_TickUpdate(void) {
os_tick++; // Tick進める
// 遅延タスクのカウント更新
for (int i=0; i<MAX_TASKS; i++) {
if (tasks[i].delay_tick > 0) {
tasks[i].delay_tick--;
if (tasks[i].delay_tick == 0)
tasks[i].ready = 1;
}
}
// CPU速度が2倍なら、OS処理は半分の時間で完了
}
4. アプリ側(タスク)
ポイント:
アプリ処理はCPUクロック依存
同じタスクでも、処理時間はCPU速度に応じて短縮される
Tickを基準にして待機時間や周期処理を制御できる
void TaskExample(void) {
printf("Task executed at tick %lu\n", OS_GetTick());
// 100MHz: 約50µsで終了
// 200MHz: 約25µsで終了
}
5. CPUクロックの影響まとめ
処理 100 MHz CPU 200 MHz CPU 備考
Timer IRQ処理時間 5 µs 2.5 µs CPUに依存
OS Tick更新 10 µs 5 µs タスク管理も高速化
アプリタスク実行時間 50 µs 25 µs Tickの精度は変わらない
Tick周期 1 ms 1 ms タイマ設定で固定
最大Tick数/秒 1000 Tick 1000 Tick OS観点では変わらない
タスクレスポンス時間 少し遅め 高速 CPU速度に依存
🔹 解説
Tick周期自体はハードウェアタイマで固定されるので、CPUが速くなっても1ms Tickは変わらない
CPU速度が速くなると、割込み・OS処理・タスク処理がより短時間で終わる → 高負荷環境でも余裕が出る
タスクスケジューリング精度を上げることも可能
例えばTickを0.5msに設定しても、CPUが速いと負荷が許容範囲内
希望であれば、100MHz CPUと200MHz CPUのTick処理時間を比較したタイムチャート図も作れます。
作りますか?

AUTOSARでは、tickと実時間の対応はドライバで行わないとのことです。追加説明ください。

なるほどです。AUTOSAR(Classic Platform)におけるTickと実時間の関係について、ドライバでは行わない理由や仕組みを整理して説明します。

  1. AUTOSARにおけるTickの位置づけ
    AUTOSARのRTOS(OSモジュール)では、TickはOS内部の論理的な時間単位として扱われます。
    ドライバ(MCAL層)
    ハードウェアタイマや割込みを提供
    Tick発生を通知するだけで、時間の計算やスケジューリングは行わない
    OS(ECU抽象層)
    Tickを受け取り、タスクの起床、遅延、周期処理などを管理
    Tickと実時間の対応(ms単位やus単位)はOSが行う
    つまり、ハードウェアタイマは単なる「Tick発生源」であり、Tickを実時間に変換する処理はOS側の責任になります。
  2. 典型的な構造(AUTOSAR層別)
    層 役割 Tick処理
    MCAL(ドライバ) タイマハードウェア制御 Tick発生割込み通知のみ
    BSW/OS タスクスケジューラ、時間管理 Tickカウント、Delay/Timeout管理、Tick→ms換算
    アプリ/アプリケーションソフトウェア アプリケーションタスク OS API経由で時間・遅延処理を要求
  3. AUTOSAR OSでのTick→実時間変換
    OSのAPIを使ってタスクがDelayや周期実行を指定する場合:
    // 例: 100ms遅延
    void Task(void) {
    WaitEvent(...); // イベント待ち
    SetRelAlarm(MyAlarm, 100, 0); // 100ms後にアラーム
    }
    Tick単位で管理:OS内部ではTickカウントでDelayや周期を管理
    Tick→ms変換はOS側:Tick周期はOS設定(OS tick period)で定義
    ハードウェアタイマはTick発生のトリガのみ
  4. なぜドライバでは行わないのか
    CPU依存性の排除
    Tick周期やOS処理はCPUクロックやOS構成に依存
    ドライバで変換すると再利用性が低くなる
    モジュールの責務分離
    MCAL:ハードウェア抽象化のみ
    OS:時間管理、タスクスケジューリング、Tick→実時間対応
    精度の統一
    Tick→ms換算をOSで一元管理することで、アプリや複数ドライバ間で時間の整合性が保たれる
  5. 図解イメージ
    [Timer HW] --(Tick IRQ)--> [MCAL Timer Driver] --(Tick notify)--> [OS] --(Tick→ms換算)--> [Task/Alarm]
    MCAL: Tick通知のみ
    OS: Tickカウントと実時間換算
    Task/Alarm: OS API経由で実時間指定
    もし希望であれば、100MHz CPUと200MHz CPUでのAUTOSAR OS Tickのタイムチャートを作り、Tick発生からタスク起床までの時間を比較することもできます。
    作りますか?

はい

了解です。それでは AUTOSAR OSでのTick処理を100MHz CPUと200MHz CPUで比較したタイムチャート を作ってみます。Tick発生からタスク起床までの流れを示します。

  1. 前提条件
    項目100 MHz CPU200 MHz CPUタイマ周期1 ms1 msTimer IRQ処理時間5 µs2.5 µsOS Tick処理時間10 µs5 µsタスク起床準備時間50 µs25 µsタスク実行開始までの合計時間65 µs32.5 µs
    Tick周期自体は1 msで固定
    CPUが速いと、割込み処理やOS処理の消費時間は半分になる
    タスク実行開始のタイミングもCPU速度に応じて早くなる
  2. タイムチャート(Tick発生からタスク起床まで)
    Time(ms) ─────────────►
    Tick 0

    ├─ Timer IRQ
    │ ├─ 100MHz: 5µs
    │ └─ 200MHz: 2.5µs

    ├─ OS TickUpdate
    │ ├─ 100MHz: 10µs
    │ └─ 200MHz: 5µs

    └─ タスク準備完了
    ├─ 100MHz: 50µs
    └─ 200MHz: 25µs

    Task実行開始
    100 MHz CPUの場合:Tick発生から 65µs後 にタスク実行開始
    200 MHz CPUの場合:Tick発生から 32.5µs後 にタスク実行開始
  3. ポイント
    Tick→実時間換算はOS側
    タスクのDelayや周期処理はOSがTickをカウントして実時間に変換
    MCAL(Timerドライバ)はTick発生通知のみ
    CPU速度が2倍でもTick周期は同じ
    1 ms Tickは変わらない
    処理時間が半分になるだけ
    タスクレスポンス改善
    CPUが速くなるとTick IRQからタスク実行までの遅延が短縮される
    もし希望であれば、このタイムチャートを 図として矢印付きでビジュアル化 して、Tick発生からタスク起床までの流れを直感的に見えるようにすることもできます。
    作りますか?

plantUMLでお願い

了解です。それでは AUTOSAR OSのTick処理フロー(Timer → OS → Task) を、100MHz と 200MHz CPU の処理時間の違いを反映して PlantUMLのシーケンス図 にします。

🔹 説明
TimerHW → MCAL
ハードウェアタイマがTickを発生させ、MCALに通知
MCAL → OS
MCALはTick通知のみを行い、Tick→実時間の変換はOSで行う
OS → Task
OSはTickカウントを更新し、タスクの起床準備(Delay/Timeout管理)
Task実行
OSがタスク実行準備完了後、アプリタスクが開始
CPU速度が速いと、OS処理やタスク準備時間が短縮される
Tick周期自体は変わらないため、タイミング精度は保持される
希望であれば、このPlantUMLを タイムライン形式でミリ秒単位の数値も表示した図 にして、100MHzと200MHzの差がより直感的に分かるようにできます。
作りますか?

はい。

解です。では タイムライン形式でTick処理時間をミリ秒単位で表示 し、100 MHzと200 MHzの差が直感的に分かるようにPlantUMLシーケンス図を作ります。

🔹 ポイント
タイムライン表示
各処理の開始時間と経過時間をミリ秒単位で表示
CPU速度が速くなると、割込み・OS処理・タスク準備時間が短縮される
Tick→実時間の変換はOS側
MCALはTick通知のみ
OSがTickカウントを更新してタスクの起床タイミングを管理
Tick周期は一定
1 ms周期で固定
CPUが速くてもTick間隔自体は変わらない
必要であれば、この図をさらに 複数Tickの連続処理 で描画して、タスク周期の安定性やTickオーバーフローの影響も可視化することも可能です。
作りますか?

はい。

素晴らしいです。では、**複数Tickの連続処理(3 ms分)**を含む、AUTOSAR OSのTick処理のタイムラインをPlantUMLで示します。
100 MHzと200 MHzのCPUで、Tick発生からタスク実行までの流れと安定性を比較できる構成です。

🔹 説明ポイント
Tick周期(1 ms) はハードウェアタイマで固定される。
→ CPU速度に依存しない安定した時間基準。
CPU速度の違い は、OS・タスク処理の完了時刻の遅延に影響。
100 MHz: 約 65 µs遅延
200 MHz: 約 32.5 µs遅延
Tickオーバーフロー はOS内部で監視し、時間計算に影響しないように設計。
AUTOSAR OSではCounterとAlarmで時間管理を抽象化。
ドライバは時間変換を行わない。
MCAL_Timerは割込み通知のみを行い、実時間対応はOs_Counterが担う。
希望があれば、このPlantUML図にさらに
CounterとAlarmモジュール(AUTOSAR OSの時間管理機構)
ScheduleTable(周期タスク制御構造)
を追加した AUTOSAR OS全体のTick伝播モデル図 も描けます。
追加しますか?

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?