AUTOSARのRTEのSchemをソースコード付きで説明してください。
もちろんです。まずはAUTOSARのRTE(Runtime Environment)の概要を押さえてから、具体的な構造(スキーマ)とソースコード例を示します。わかりやすくCコード中心で説明します。
- AUTOSAR RTEの概要
RTEは、AUTOSARアーキテクチャにおけるアプリケーションソフトウェア(SWC: Software Component)と基盤ソフトウェア(BSW: Basic Software)間の仲介層です。
RTEの主な役割は以下です:
SWC間通信の抽象化(コンポーネント間のポート通信)
SWCとハードウェア・OSの依存性の分離
タスク管理(スケジューリング)やイベント管理の提供 - RTEのスキーマ(構造)
RTEは、AUTOSAR仕様に基づき各SWCに対して専用のRTEヘッダ・ソースが生成されます。
典型的なRTEスキーマは以下の要素で構成されます:
SWC1 SWC2
| |
Port Port
| |
+-----RTE-----+
|
RTE API Layer
|
BSW Services
|
ECU Drivers
Port: SWCが外部とやり取りするインターフェース
RTE API: SWCから呼ばれる関数群(読み取り・書き込み・呼び出し)
BSW Services: OSや通信サービスなど
ECU Drivers: 実際のハードウェア制御 - RTE APIの例
たとえば、EngineControlというSWCがあり、EngineSpeedというデータを別SWCに送信する場合:
a) RTEヘッダ(Rte_EngineControl.h)
#ifndef RTE_ENGINECONTROL_H
#define RTE_ENGINECONTROL_H
#include "Rte_Type.h"
/* SWCからポートを通じてデータ送信 */
Std_ReturnType Rte_Write_EngineSpeed(uint16 data);
/* SWCが受信する場合 /
Std_ReturnType Rte_Read_ThrottlePosition(uint16 data);
#endif
b) RTEソース(Rte_EngineControl.c)
#include "Rte_EngineControl.h"
#include "Rte_Internal.h"
Std_ReturnType Rte_Write_EngineSpeed(uint16 data)
{
/* 実際にはRTE内部のバッファや通信サービスを通じて転送 */
Rte_Internal_EngineSpeed = data;
return E_OK;
}
Std_ReturnType Rte_Read_ThrottlePosition(uint16* data)
{
if(data == NULL) return E_NOT_OK;
*data = Rte_Internal_ThrottlePosition;
return E_OK;
}
4. RTEの生成と使用
Arxml定義: SWCのポート、データ型、通信関係をARXMLで定義
RTE生成ツール: AUTOSARツール(Vector DaVinci, EB tresosなど)がARXMLからRTEソースを生成
アプリケーション実装:
#include "Rte_EngineControl.h"
void EngineControl_MainFunction(void)
{
uint16 throttle;
if(Rte_Read_ThrottlePosition(&throttle) == E_OK)
{
uint16 engineSpeed = throttle * 10; // 単純制御例
Rte_Write_EngineSpeed(engineSpeed);
}
}
5. ポイントまとめ
RTEはSWC間通信の抽象化レイヤ
RTE APIは自動生成されるため、SWCはハードウェアやOS依存なしで動作可能
RTE内部はバッファ管理・イベント通知・タスク起動などを行う
実際の通信はCOMモジュールやECUドライバに委譲
もしよければ、次のステップとしてRTEとOSタスク・イベントの関係を図にしたPlantUMLも作れます。
作ってほしいですか?
はい。
了解です。では、AUTOSAR RTEとOSタスク・イベントの関係をPlantUMLで図にします。RTEがどのようにタスクやイベントと連携してSWCを呼び出すかを表現します。
@startuml
title AUTOSAR RTEとOSタスク・イベントの関係
package "ECU" {
package "OS" {
[Task_EngineControl] as TaskEC
[Task_ThrottleMonitor] as TaskTM
[Event_EngineUpdate] as EventEU
}
package "RTE" {
[Rte_EngineControl] as RTEEC
[Rte_ThrottleMonitor] as RTETM
}
package "SWC" {
[SWC_EngineControl] as SWCEC
[SWC_ThrottleMonitor] as SWCTM
}
package "BSW" {
[COM Module] as COM
[ECU Drivers] as ECU
}
' タスク → RTE → SWC
TaskEC --> RTEEC : call
TaskTM --> RTETM : call
' RTE → SWC
RTEEC --> SWCEC : invoke Runnable
RTETM --> SWCTM : invoke Runnable
' SWC → RTE → COM → ECU
SWCEC --> RTEEC : Rte_Write()
RTEEC --> COM : send signal
COM --> ECU : send to HW
SWCTM --> RTEEC : Rte_Write() (EngineSpeed)
RTEEC --> EventEU : set event
' イベント → タスク
EventEU --> TaskEC : activate
@enduml
図の解説
OSタスク
Task_EngineControl、Task_ThrottleMonitor は周期的/イベント駆動で実行される。
RTE
各SWC専用RTE(Rte_EngineControlなど)がタスクから呼ばれる。
SWCのRunnable呼び出し、データの読み書きを仲介。
SWC
実際のアプリケーションロジックを実行。
RTE APIで他のSWCやCOMモジュールにデータ送信。
COM/ECU
CANやLINなどの通信モジュール、ハードウェア制御を行う。
イベント
SWCの状態変化やデータ更新に応じてOSタスクを起動。
この図をもとに、RTEはOSのタスク・イベントと密接に連携しつつ、SWC間通信を抽象化する層であることがわかります。
希望であれば、このPlantUMLにRTE内部のバッファ構造やデータフローも追加して、より詳細なRTEの動作図も作れます。作りますか?
Schmをソースコード付きで説明してください。
なるほど。「RTEのSchema(構造・スキーマ)をソースコード付きで」という意味ですね。では、AUTOSAR RTEの**SWC側のSchema(Runnable、Port、Data Elementの構造)**をCコード例と一緒に詳しく示します。
- RTE Schemaの概念
RTEのスキーマ(Schema)とは、各SWCが利用するRTE APIの構造です。
主な構成要素は:
Ports
SWCが外部とやり取りするインターフェース
Sender/Receiver Port: データ送受信
Client/Server Port: サービス呼び出し
Data Elements
Portでやり取りされるデータ
Runnable
OSから呼ばれるSWCの関数(処理単位)
Events
Runnableの起動条件(周期、データ更新など) - Schema例(Cコード)
例えば、EngineControl SWCでスロットル位置を読み、エンジン回転数を出力するケースを考えます。
a) データ型定義(Rte_Type.h)
#ifndef RTE_TYPE_H
#define RTE_TYPE_H
typedef unsigned short uint16;
typedef unsigned char Std_ReturnType;
#define E_OK 0
#define E_NOT_OK 1
#endif
b) RTEヘッダ(Rte_EngineControl.h)
#ifndef RTE_ENGINECONTROL_H
#define RTE_ENGINECONTROL_H
#include "Rte_Type.h"
/* Sender/Receiver Port: EngineSpeed送信 */
Std_ReturnType Rte_Write_EngineSpeed(uint16 data);
/* Receiver Port: ThrottlePosition受信 /
Std_ReturnType Rte_Read_ThrottlePosition(uint16 data);
/* Runnable宣言 */
void EngineControl_MainFunction(void);
#endif
c) RTEソース(Rte_EngineControl.c)
#include "Rte_EngineControl.h"
/* RTE内部バッファ */
static uint16 Rte_Internal_ThrottlePosition = 0;
static uint16 Rte_Internal_EngineSpeed = 0;
Std_ReturnType Rte_Write_EngineSpeed(uint16 data)
{
Rte_Internal_EngineSpeed = data;
return E_OK;
}
Std_ReturnType Rte_Read_ThrottlePosition(uint16* data)
{
if(data == NULL) return E_NOT_OK;
*data = Rte_Internal_ThrottlePosition;
return E_OK;
}
d) SWC Runnable(SWC側の実装)
#include "Rte_EngineControl.h"
void EngineControl_MainFunction(void)
{
uint16 throttle;
/* Receiver Portからデータ取得 */
if(Rte_Read_ThrottlePosition(&throttle) == E_OK)
{
/* 単純制御: エンジン回転数計算 */
uint16 engineSpeed = throttle * 10;
/* Sender Portを通じてデータ送信 */
Rte_Write_EngineSpeed(engineSpeed);
}
}
3. Schemaのまとめ
Schema要素 説明
Port SWCの外部インターフェース。Sender/Receiver, Client/Serverがある
Data Element Portでやり取りされる変数(例:ThrottlePosition, EngineSpeed)
Runnable OSから呼び出される処理単位(例:EngineControl_MainFunction)
Event Runnableを起動する条件(周期、データ受信など)
RTE API Portを通じてデータアクセス・サービス呼び出しを提供する関数群
この構造を理解すると、RTEの自動生成コードの中身がどうなっているか、SWCはどのようにRTEを通じて通信しているかが明確になります。
もしよければ、次のステップとしてこのSchemaをPlantUMLで図解して、Runnable・Port・RTEの関係を可視化することもできます。
作りますか?
ごめんなさい。Scheduler Module (SchM) をソースコード付きでお願いします。
なるほど、「SchM(Scheduler Module)」ですね。AUTOSARのBSWの一部で、タスク排他制御やクリティカルセクションの管理を行うモジュールです。RTEとは異なり、OSタスクや割り込みとの調整を行います。では、ソースコード例と共に詳しく説明します。
- SchMの概要
SchM (Scheduler Module) は、主に以下の役割を持ちます:
Exclusive Areaの制御
複数タスクや割り込みからの排他制御
CPU依存の実装で、OSのSuspend/Resume機能などを使う
クリティカルセクション管理
SWCやBSWモジュールが安全に共有リソースにアクセスできるようにする
タスク保護
タイミング依存の処理が割り込みで中断されないようにする - SchMの基本的な構造
典型的には以下のようなAPIがあります。
API名 役割
SchM_Enter_(Area) クリティカルセクション開始
SchM_Exit_(Area) クリティカルセクション終了
: 対象BSWモジュール名(例:RTE, Can, Adcなど)
Area: Exclusive Area番号(複数管理可能) - ソースコード例
a) ヘッダ(SchM_Rte.h)
#ifndef SCHM_RTE_H
#define SCHM_RTE_H
#include "Std_Types.h"
/* Exclusive Area定義 */
typedef enum {
RTE_EXCLUSIVE_AREA_0 = 0,
RTE_EXCLUSIVE_AREA_1
} SchM_ExclusiveAreaType;
/* API */
void SchM_Enter_Rte(SchM_ExclusiveAreaType area);
void SchM_Exit_Rte(SchM_ExclusiveAreaType area);
#endif
b) ソース(SchM_Rte.c)
#include "SchM_Rte.h"
#include "Os.h" /* OSのSuspend/Resume APIを仮定 */
static uint8 Rte_ExclusiveCounter[2] = {0, 0};
/* クリティカルセクション開始 /
void SchM_Enter_Rte(SchM_ExclusiveAreaType area)
{
/ 再入可能カウンタを使用 /
if(Rte_ExclusiveCounter[area] == 0) {
SuspendAllInterrupts(); / OS割り込み停止 */
}
Rte_ExclusiveCounter[area]++;
}
/* クリティカルセクション終了 /
void SchM_Exit_Rte(SchM_ExclusiveAreaType area)
{
if(Rte_ExclusiveCounter[area] > 0) {
Rte_ExclusiveCounter[area]--;
if(Rte_ExclusiveCounter[area] == 0) {
ResumeAllInterrupts(); / OS割り込み再開 */
}
}
}
4. 使用例(RTE内での呼び出し)
#include "SchM_Rte.h"
#include "Rte_EngineControl.h"
void EngineControl_MainFunction(void)
{
uint16 throttle;
/* クリティカルセクション開始 */
SchM_Enter_Rte(RTE_EXCLUSIVE_AREA_0);
if(Rte_Read_ThrottlePosition(&throttle) == E_OK)
{
uint16 engineSpeed = throttle * 10;
Rte_Write_EngineSpeed(engineSpeed);
}
/* クリティカルセクション終了 */
SchM_Exit_Rte(RTE_EXCLUSIVE_AREA_0);
}
5. ポイントまとめ
SchMは排他制御専用モジュール
OSのSuspend/Resume APIと連携
再入可能(ネスト可能)クリティカルセクションをサポート
モジュール単位で生成
SchM_ の形式でBSWやRTEごとに生成される
BSWやRTE内で使用
SWCは直接使わないことが多い
RTE内部やBswモジュールが共有リソースを安全に扱うために利用
希望であれば、このSchMのRTEやOSタスクとの関係をPlantUMLで図解して、Exclusive Areaがどのように保護されるか可視化することもできます。
作りますか?
SchM_を具体例でお願いします。
わかりました。では、AUTOSARの SchM_ の具体例 を示します。ここでは典型的な RTE用 SchM_Rte と CANドライバ用 SchM_Can を例に、Cコードで具体的なExclusive Area管理を示します。
- SchM_Rte の例
a) ヘッダ(SchM_Rte.h)
#ifndef SCHM_RTE_H
#define SCHM_RTE_H
#include "Std_Types.h"
/* Exclusive Area定義 */
typedef enum {
RTE_EXCLUSIVE_AREA_0 = 0,
RTE_EXCLUSIVE_AREA_1
} SchM_ExclusiveAreaType;
/* API */
void SchM_Enter_Rte(SchM_ExclusiveAreaType area);
void SchM_Exit_Rte(SchM_ExclusiveAreaType area);
#endif
b) ソース(SchM_Rte.c)
#include "SchM_Rte.h"
#include "Os.h" /* OSのSuspend/Resume APIを仮定 */
static uint8 Rte_ExclusiveCounter[2] = {0, 0};
void SchM_Enter_Rte(SchM_ExclusiveAreaType area)
{
if(Rte_ExclusiveCounter[area] == 0) {
SuspendAllInterrupts(); /* 割り込み停止 */
}
Rte_ExclusiveCounter[area]++;
}
void SchM_Exit_Rte(SchM_ExclusiveAreaType area)
{
if(Rte_ExclusiveCounter[area] > 0) {
Rte_ExclusiveCounter[area]--;
if(Rte_ExclusiveCounter[area] == 0) {
ResumeAllInterrupts(); /* 割り込み再開 */
}
}
}
c) 使用例
#include "SchM_Rte.h"
#include "Rte_EngineControl.h"
void EngineControl_MainFunction(void)
{
uint16 throttle;
SchM_Enter_Rte(RTE_EXCLUSIVE_AREA_0);
if(Rte_Read_ThrottlePosition(&throttle) == E_OK) {
Rte_Write_EngineSpeed(throttle * 10);
}
SchM_Exit_Rte(RTE_EXCLUSIVE_AREA_0);
}
2. SchM_Can の例(CANドライバ用)
AUTOSARのCANモジュールでも同様の構造を持ちます。
a) ヘッダ(SchM_Can.h)
#ifndef SCHM_CAN_H
#define SCHM_CAN_H
#include "Std_Types.h"
typedef enum {
CAN_EXCLUSIVE_AREA_0 = 0
} SchM_CanExclusiveAreaType;
void SchM_Enter_Can(SchM_CanExclusiveAreaType area);
void SchM_Exit_Can(SchM_CanExclusiveAreaType area);
#endif
b) ソース(SchM_Can.c)
#include "SchM_Can.h"
#include "Os.h"
static uint8 Can_ExclusiveCounter[1] = {0};
void SchM_Enter_Can(SchM_CanExclusiveAreaType area)
{
if(Can_ExclusiveCounter[area] == 0) {
SuspendAllInterrupts(); /* 割り込み停止 */
}
Can_ExclusiveCounter[area]++;
}
void SchM_Exit_Can(SchM_CanExclusiveAreaType area)
{
if(Can_ExclusiveCounter[area] > 0) {
Can_ExclusiveCounter[area]--;
if(Can_ExclusiveCounter[area] == 0) {
ResumeAllInterrupts(); /* 割り込み再開 */
}
}
}
c) 使用例(CAN送信処理内)
#include "SchM_Can.h"
#include "Can.h"
void Can_SendMessage(uint8 channel, uint8 data)
{
SchM_Enter_Can(CAN_EXCLUSIVE_AREA_0);
/* CAN送信処理 */
Can_Write(channel, data);
SchM_Exit_Can(CAN_EXCLUSIVE_AREA_0);
}
3. ポイントまとめ
SchM_ はモジュール単位の排他制御API
Exclusive Areaごとにネスト可能なクリティカルセクションを実現
RTEやCANなど、BSWモジュール内部で共有リソース保護に使用
実装は通常 SuspendAllInterrupts / ResumeAllInterrupts で割り込み管理する
希望であれば、これら SchM_ のRTEやタスクとの関係をPlantUMLで図解して、Exclusive Areaがどのように保護されるか可視化することもできます。
作りますか?
schm_enter, schm_exit, rte_enter, rte_exit, rte_start, rte_stopの関係がくわかりません。ありがちな例をソースコードでお示しください。
なるほど、AUTOSAR BSW/RTEの SchM_Enter / SchM_Exit と Rte_Enter / Rte_Exit、さらに Rte_Start / Rte_Stop の関係 がわかりにくいということですね。
典型的な使用例をCコードで示して整理します。
- 役割の整理
関数 役割
SchM_Enter_(Area) モジュール単位のExclusive Area(クリティカルセクション)開始。CPUの割り込み制御などを行う。
SchM_Exit_(Area) モジュール単位のExclusive Area終了。
Rte_Enter_(Area) RTE内部でExclusive Areaを開始。内部的にSchMを呼ぶことが多い。
Rte_Exit_(Area) RTE内部でExclusive Area終了。
Rte_Start / Rte_Stop RTEの初期化・開始・停止を行う。OSタスク・タイマーなどを起動・終了させる。
ポイント:
SchM_ は BSW内部の低レベル排他制御
Rte_ は SWCとRTEの間の排他・バッファ保護
Rte_Start/Stop は システム起動/終了 に使う - ありがちな例(EngineControl SWC)
a) RTEの初期化と開始
#include "Rte.h"
int main(void)
{
/* OS初期化など後にRTE初期化 */
Rte_Init();
/* RTEスタート: タスクやタイマーの起動 */
Rte_Start();
/* メインループ */
while(1)
{
/* OSスケジューラにより周期タスクが起動 */
}
/* RTE停止(システム終了時) */
Rte_Stop();
return 0;
}
b) SWC Runnable内でのRTE/SchM利用例
#include "Rte_EngineControl.h"
#include "SchM_Rte.h"
void EngineControl_MainFunction(void)
{
uint16 throttle;
uint16 engineSpeed;
/* ---------------------------
1. RTE Exclusive Area開始
--------------------------- */
Rte_Enter_Rte(RTE_EXCLUSIVE_AREA_0);
/* ---------------------------
2. SchM Exclusive Area開始(内部リソース保護)
--------------------------- */
SchM_Enter_Rte(RTE_EXCLUSIVE_AREA_0);
/* Throttleデータを読む */
if(Rte_Read_ThrottlePosition(&throttle) == E_OK)
{
engineSpeed = throttle * 10;
/* EngineSpeedを書き込む */
Rte_Write_EngineSpeed(engineSpeed);
}
/* ---------------------------
3. SchM Exclusive Area終了
--------------------------- */
SchM_Exit_Rte(RTE_EXCLUSIVE_AREA_0);
/* ---------------------------
4. RTE Exclusive Area終了
--------------------------- */
Rte_Exit_Rte(RTE_EXCLUSIVE_AREA_0);
}
c) 補足: 関数の呼び出し関係
Rte_Enter_Rte() → 内部で SchM_Enter_Rte()
Rte_Exit_Rte() → 内部で SchM_Exit_Rte()
つまり、SWCがRTEのバッファや共有リソースにアクセスする際は RTEレベルでEnter/Exitを呼ぶ。
さらに、RTE内部でOS保護が必要な場合は SchMで低レベル排他制御 を行う構造です。
Rte_Start() はタスクやタイマーを起動してRunnableを実行可能にする
Rte_Stop() はタスク・タイマーを停止してRTEを停止
d) 図で表すと
main()
└─> Rte_Start()
└─> OSタスク起動
└─> EngineControl_MainFunction()
├─> Rte_Enter_Rte()
│ └─> SchM_Enter_Rte()
├─> データ読み書き
├─> SchM_Exit_Rte()
└─> Rte_Exit_Rte()
💡 まとめ
Rte_Start / Rte_Stop → RTE全体の起動・停止
Rte_Enter / Rte_Exit → SWCから見たRTEの排他制御
SchM_Enter / SchM_Exit → RTE内部やBSWモジュールの低レベル排他制御
SWCのRunnableは Rte_Enter/Exitで囲み、必要に応じて内部でSchMも使う
希望であれば、この関係を PlantUMLでタスク・RTE・SchMの排他フロー図 にして可視化することもできます。
作りますか?
はい。
了解です。では、AUTOSARの タスク → RTE → SchM → SWC → BSW の排他制御フローをPlantUMLで図解します。Rte_Enter / Rte_Exit と SchM_Enter / SchM_Exit の関係も可視化します。
@startuml
title AUTOSAR RTE / SchM 排他制御フロー
actor "Main Function" as Main
participant "RTE_Start()" as RTEStart
participant "OS Task" as OSTask
participant "SWC Runnable" as SWCRunnable
participant "RTE_Enter / Exit" as RTEEnterExit
participant "SchM_Enter / Exit" as SchMEnterExit
participant "BSW Module / Shared Resource" as BSW
== システム起動 ==
Main -> RTEStart : Rte_Start()
RTEStart -> OSTask : タスク・タイマー起動
== タスク実行 ==
OSTask -> SWCRunnable : Runnable起動
== RTE排他開始 ==
SWCRunnable -> RTEEnterExit : Rte_Enter_Rte()
RTEEnterExit -> SchMEnterExit : SchM_Enter_Rte() (低レベル排他)
== データアクセス ==
SWCRunnable -> BSW : 共有リソースアクセス
BSW --> SWCRunnable : データ返却
== 排他終了 ==
SWCRunnable -> SchMEnterExit : SchM_Exit_Rte()
SWCRunnable -> RTEEnterExit : Rte_Exit_Rte()
== 次の周期・イベント ==
OSTask --> SWCRunnable : Runnable再呼び出し
@enduml
図の解説
Rte_Start()
OSタスクやタイマーを起動してSWC Runnableの実行を可能にする
OS Task
周期タスクやイベント駆動タスクとしてRunnableを呼び出す
Rte_Enter / Rte_Exit
SWCがRTEバッファや内部データを安全に扱うための排他制御
SchM_Enter / SchM_Exit
RTE内部やBSWモジュールの低レベル共有リソース排他
OS割り込み停止やネスト可能カウンタで管理
BSW Module / Shared Resource
CANバッファやADCデータなど、共有ハードウェアリソース
この図を見ると、SWCはRTEを通してSchMの排他制御を使い、共有リソースへの安全なアクセスが保証されることが一目でわかります。
必要であれば、次のステップとして Rte_Stop() まで含めた完全ライフサイクル図 も作れます。作りますか?
rte_start, rte_stopがなくてもビルドできるとお聞きしました。本当でしょうか。
はい、それは 本当です。ただし条件があります。順を追って整理します。
-
Rte_Start / Rte_Stop の役割
Rte_Start()
RTE内部でOSタスクやタイマーを起動
Runnableを周期的・イベント駆動で呼ぶための準備
Rte_Stop()
RTEのタスクやタイマーを停止
システムシャットダウンやリソース解放用 -
ビルド可能かどうか
ビルド(コンパイル/リンク)自体は可能
Rte_Start / Rte_Stop は単なる関数なので、呼ばなくてもCコードはコンパイルできます
実際にビルドエラーになるわけではありません
ただし実行時には影響がある
Rte_Start を呼ばない場合、OSタスクやタイマーが起動しないため、Runnableが自動で呼ばれません
手動でRunnableを呼ぶ場合は問題なく動作可能 -
典型的な例
a) Rte_Start を呼ぶ場合
int main(void)
{
Rte_Init();
Rte_Start(); // OSタスクやタイマーを起動
while(1) { /* OSスケジューラがRunnableを周期実行 */ }
}
b) Rte_Start を呼ばない場合(手動呼び出し)
int main(void)
{
Rte_Init();/* Runnableを手動で呼ぶ */
while(1) {
EngineControl_MainFunction();
ThrottleMonitor_MainFunction();
}
}
この場合、OSタスクやタイマーは不要
ビルドも問題なし
しかし、AUTOSAR標準のタスクスケジューリング機能は使えない -
まとめ
ビルドは可能:Rte_Start / Rte_Stop を呼ばなくてもCコードはコンパイル可能
実行上の違い:
Rte_Start を呼ぶ → OSタスク・タイマーで自動呼び出し
呼ばない → Runnableは手動で呼ぶ必要がある
通常は自動スケジューリングのために呼ぶのが標準的
💡 要点:Rte_Start / Rte_Stop は必須ではないが、AUTOSAR準拠の自動スケジューリングには必須というイメージです。
もしよければ、Rte_Start なしで手動呼び出しした場合の RTE / SchM の排他フロー図もPlantUMLで示せます。作りますか?
rte_start以外の関数からOSタスク・タイマーを自動呼び出しできませんか?
結論から言うと、標準のAUTOSAR RTEでは、Rte_Start() を呼ばない限り OSタスク・タイマーは自動的に起動されません。
ただし、工夫すれば「Rte_Start 以外の関数」から間接的に起動することは可能です。順を追って説明します。
- なぜ Rte_Start() が必要か
Rte_Start() は、RTEが管理する周期タスクやイベント駆動タスクの登録・起動を行う関数です。
AUTOSAR RTEの生成コードでは、OSタスクやOSカウンタ、OSアラームなどを Rte_Start() 内で初期化・起動 します。
そのため、Rte_Start() を呼ばなければ、RunnableはOSのスケジューラから自動的には呼ばれません。 - 代替手段
a) 手動でOSタスクやタイマーを起動する
Rte_Start() が内部で呼んでいる処理を自分で呼び出すことが可能
例: OSの ActivateTask や SetRelAlarm を直接呼ぶ
#include "Os.h"
/* Rte_Start() と同等の処理 /
void My_Rte_Start_Alternative(void)
{
/ OSアラーム設定で周期タスクを起動 */
SetRelAlarm(EngineControlTaskAlarm, 10, 10); // 10ms周期
SetRelAlarm(ThrottleMonitorTaskAlarm, 5, 5); // 5ms周期
}
この関数を main() などから呼べば、Rte_Start() を使わずにOSタスクを起動可能
b) Runnableを直接OSタスクに登録する(コード生成時の調整)
AUTOSARツールの生成設定で、RTE_TaskActivationをカスタマイズ
タスク開始関数を独自関数に差し替えることで、Rte_Start() を不要にする
c) 完全手動呼び出し
OSやタイマーを使わず、mainループでRunnableを直接呼ぶ
int main(void)
{
Rte_Init();
while(1)
{
EngineControl_MainFunction();
ThrottleMonitor_MainFunction();
}
}
実行は可能だが、周期精度やスケジューリングは自分で管理する必要がある
3. 注意点
AUTOSAR標準準拠では推奨されない
Rte_Start() を呼ばないと、OSのタイマーイベントやアラームなどの機能が正しく使えない
代替方法は「軽量RTE」や「単体テスト用」として使うケースが多い
💡 まとめ
方法 メリット デメリット
Rte_Start() を使う 標準準拠、OSタスク/アラーム自動起動 なし
OS APIを直接呼ぶ Rte_Start不要で自動起動可能 AUTOSAR準拠でない、保守性低
Runnableを手動呼び出し 最も単純 スケジューリング管理が必要、周期精度が保証されない
希望であれば、Rte_StartなしでOSタスクやタイマーを自動呼び出す場合のPlantUMLフロー図も作れます。
作りますか?
なるべくモジュールを小さくして速くするために、省略していい関数の例を16個示してくだし。
わかりました。AUTOSAR RTE / BSW を最小化・高速化する目的で、省略可能(使わない場合でもビルド可能)な関数・APIの例を、代表的なものを 16個 挙げます。
※「省略可能」はシステム構成や使用モジュールによります。必ずしも全てのプロジェクトで省略可能ではありません。
- RTE関連
No 関数 省略理由 / 補足
1 Rte_Start() OSタスク・タイマーを使わず、手動呼び出しでRunnableを実行する場合
2 Rte_Stop() システム終了をRTEが管理しない場合
3 Rte_Enter_() クリティカルセクション不要な単純SWCの場合
4 Rte_Exit_() 同上
5 Rte_Init() SWCが内部データ初期化不要で直接値を設定する場合
6 Rte_IrvRead_() Inter-Runnable Variable を使わない場合
7 Rte_IrvWrite_() 同上
8 Rte_Call_() Client/Server通信を使わないSWCの場合 - SchM関連(Exclusive Area管理)
No 関数 省略理由 / 補足
9 SchM_Enter_() 共有リソースや割り込み保護が不要な場合
10 SchM_Exit_() 同上
11 SchM_Enter_Nested() ネスト可能なクリティカルセクションを使わない場合
12 SchM_Exit_Nested() 同上 - BSW / COM / CAN など
No 関数 省略理由 / 補足
13 Com_SendSignal() 信号送信機能を使わない場合
14 Com_ReceiveSignal() 信号受信機能を使わない場合
15 Can_Write() CAN送信を使用しない場合
16 Can_Read() CAN受信を使用しない場合
💡 ポイント
排他制御や通信APIは不要なら省略可能
シンプルなSWCやテスト用RTEで有効
Rte_Start / Stop を省略するとOSの周期タスク管理は自分で行う必要あり
ビルド可能かどうかは、実際に生成されたRTE/BSWコードの依存関係に左右される
最適化の基本: 使わないモジュール・ポート・Runnable・通信・排他制御を生成しない設定にする
希望であれば、この「省略可能関数16個」を RTE/SchM/BSWフローのPlantUML図上で省略部分を赤字で示す 形で可視化することもできます。
作りますか?
zero copyの考え方にしたがい、なるべくバッファを持たないようにするには、どういう関数が不要ですか。
なるほど。「Zero Copy」の考え方で、なるべく バッファを持たずにデータを直接渡す 方式にするときに 不要になる関数・API を整理します。AUTOSAR RTE / BSWを前提に考えます。
- Zero Copy の基本
データを RTE内部やCOMバッファにコピーせず、参照で渡す
バッファコピーを伴う API は不要になる
目的: メモリ使用量削減・レイテンシ短縮・高速化 - 不要になる典型的関数
a) RTE バッファ関連
No 関数 理由
1 Rte_IrvWrite_() Inter-Runnable Variable にコピーする必要がなくなる
2 Rte_IrvRead_() コピーせず参照で取得できれば不要
3 Rte_Write_() Sender Port バッファにコピーせず直接参照渡しが可能
4 Rte_Read_() Receiver Port のコピー読み出しは不要
5 Rte_Send_() イベントに伴う内部バッファやキューを使わない場合
6 Rte_Receive_() 同上
b) BSW / COM バッファ関連
No 関数 理由
7 Com_SendSignal() バッファにコピーして送信する場合は不要、直接参照送信可能
8 Com_ReceiveSignal() バッファコピー不要、受信データを参照で渡せば不要
9 Can_Write() CANデータコピー不要なら直接送信
10 Can_Read() 受信バッファコピー不要、参照渡しのみ
c) SchM / クリティカルセクション関連
バッファアクセスを伴う排他制御は不要になることがある
No 関数 理由
11 SchM_Enter_() バッファ保護不要なら省略可能
12 SchM_Exit_() 同上
d) RTE タイマー/キュー関連
No 関数 理由
13 Rte_SetEvent() キューにデータをコピーするイベント通知不要
14 Rte_WaitEvent() コピー不要なら、参照で直接Runnable起動
15 Rte_QueueWrite() 内部キューにコピー不要
16 Rte_QueueRead() 内部キューコピー不要 - まとめ
Zero Copy 化の基本方針: 「コピーを伴う関数・バッファを使わない」
省略可能関数は主に RTEバッファ操作系、COM/CANバッファ操作系、イベントキュー系
SchMの排他も、バッファ保護が不要なら省略可能
メリット: メモリ消費減、処理遅延減
デメリット: データ整合性や競合に注意が必要(参照で共有するため)
💡 もし希望なら、この Zero Copy化で不要になる関数16個 を RTE / SchM / BSWフロー図に赤で省略表示 してPlantUMLで可視化することもできます。
作りますか?
はい。
わかりました。では、Zero Copy化の考え方に基づき、バッファを持たずに直接参照でデータを渡す場合に不要になる関数を、RTE / SchM / BSWフロー図としてPlantUMLで可視化します。
@startuml
title Zero Copy時に不要となるRTE/SchM/BSW関数
actor "Main Function" as Main
participant "RTE_Start()" as RTEStart
participant "OS Task" as OSTask
participant "SWC Runnable" as SWCRunnable
participant "RTE (バッファ)" as RTEBuffer
participant "SchM (排他)" as SchM
participant "BSW/COM/CAN" as BSW
== システム起動 ==
Main -> RTEStart : Rte_Start() (必要)
== タスク実行 ==
OSTask -> SWCRunnable : Runnable起動
== バッファコピー不要(Zero Copy) ==
SWCRunnable -> RTEBuffer : ~Rte_Write_()~
SWCRunnable -> RTEBuffer : ~Rte_Read_()~
SWCRunnable -> RTEBuffer : ~Rte_IrvWrite_()~
SWCRunnable -> RTEBuffer : ~Rte_IrvRead_()~
SWCRunnable -> RTEBuffer : ~Rte_Send_()~
SWCRunnable -> RTEBuffer : ~Rte_Receive_()~
SWCRunnable -> BSW : ~Com_SendSignal()~
SWCRunnable -> BSW : ~Com_ReceiveSignal()~
SWCRunnable -> BSW : ~Can_Write()~
SWCRunnable -> BSW : ~Can_Read()~
SWCRunnable -> SchM : ~SchM_Enter_()~
SWCRunnable -> SchM : ~SchM_Exit_()~
SWCRunnable -> RTEBuffer : ~Rte_SetEvent()~
SWCRunnable -> RTEBuffer : ~Rte_WaitEvent()~
SWCRunnable -> RTEBuffer : ~Rte_QueueWrite()~
SWCRunnable -> RTEBuffer : ~Rte_QueueRead()~
== 実データアクセス(参照渡し) ==
SWCRunnable -> BSW : データ参照で直接アクセス
@enduml
図の解説
赤字/取り消し線 (~ ~) で示した関数は Zero Copy化により不要
SWC Runnable は 参照で直接データにアクセスする
SchMの排他も、共有バッファがない場合は不要
Rte_Start() は依然として OSタスクやタイマーを起動するために必要
💡 この図をもとに、Zero Copy設計では コピー用APIやバッファ・キュー・イベント処理の大半を省略できることが視覚的に理解できます。
必要であれば、Zero Copy化前後でのメモリ使用量・コピー回数の比較図 も作ることが可能です。作りますか?
はい。
了解です。では、Zero Copy化の前後で メモリ使用量とコピー回数 を比較したPlantUMLフロー図を作ります。
@startuml
title Zero Copy 前後の比較(メモリ使用量・コピー回数)
actor "SWC Runnable" as SWC
package "従来方式 (コピーあり)" {
participant "RTE バッファ" as RTEBuffer
participant "BSW/COM/CAN" as BSW
SWC -> RTEBuffer : データを書き込み(コピー1回)
SWC <- RTEBuffer : データを読み込み(コピー2回)
SWC -> BSW : 信号送信(コピー3回)
SWC <- BSW : 信号受信(コピー4回)
}
note right of RTEBuffer
メモリ使用量:
- ポートバッファ
- IRVバッファ
- イベント/キュー
コピー回数: 4回
end note
package "Zero Copy 方式" {
participant "直接参照" as DirectRef
participant "BSW/COM/CAN" as BSW2
SWC -> DirectRef : データ参照渡し(コピー0回)
SWC -> BSW2 : データ参照渡し(コピー0回)
}
note right of DirectRef
メモリ使用量:
- バッファ不要
コピー回数: 0回
end note
@enduml
図の解説
従来方式 (コピーあり)
RTEバッファやIRV(Inter-Runnable Variable)、COM/CANバッファにコピー
コピー回数が増える → メモリ使用量増、処理遅延増
Zero Copy方式
データは参照で直接アクセス
バッファ不要 → メモリ削減
コピー回数 0 → 高速化
💡 この図で Zero Copy化のメリット が一目でわかります:
メモリ消費削減
コピー回数ゼロ → レイテンシ低減
SchMやRTEのバッファ関連関数を省略可能
希望であれば、次に Zero Copy設計時に残す必要のある最低限のRTE/SchM関数のみを赤字で表示したフロー図 も作れます。作りますか?