Main Content

C Caller ブロックを使用した C コードの統合

C Caller ブロックを使用して Simulink® に新規または既存の C コードを統合できます。Simulink モデルでカスタム ブロックを作成するには、C Caller ブロックによって、外部のソース コードおよびライブラリで指定された外部 C 関数を呼び出すことができます。C Caller ブロックのメリットには次のものがあります。

  • 名前空間の下に定義されている関数を含む単純な C 関数の自動化された統合

  • Simulink Coverage™Simulink Test™、および Simulink Design Verifier™ との統合

  • Simulink Coder™ との統合

C Caller ブロックと C Function ブロックにより C アルゴリズムを Simulink に持ち込むことができます。動的システムをモデル化するには、代わりに S-Function Builder を使用します。次のステップでは、C Caller ブロックを使用して Simulink に C コードを統合するワークフローを説明します。

メモ

Simulink へのカスタム C コード統合でサポートされる C 言語の標準バージョンは C99 です。

ソース コードと依存関係の指定

C 関数を含む外部ソース コード ファイルを指定します。

  1. Simulink ツールストリップから [コンフィギュレーション パラメーター] を開きます。

  2. 左側のペインで [シミュレーション ターゲット] を選択します。

  3. [インクルード ヘッダー] を選択して、ヘッダー ファイルの名前を #include タグと共に入力します。

    ディレクトリとファイル パスは、絶対パスでもモデル ディレクトリまたは現在の作業ディレクトリへの相対パスでもかまいません。カスタム コードへの相対パスの指定 (Stateflow)を参照してください。

    ヒント

    次の手順で [ソース ファイル] の情報を入力した後、[ソース ファイルからのオートフィル] をクリックすると、ソース ファイルに含まれる情報を使用してヘッダー ファイルの名前を自動で入力できます。

  4. [ソース ファイル] を選択し、ソース ファイルのパスと名前を入力します。モデルとソース ファイルが異なるディレクトリにある場合、ファイル名の前にソース ファイルが含まれているディレクトリを入力します。

  5. [インクルード ディレクトリ] を選択し、ヘッダー ファイルなどの追加のビルド情報が格納されているフォルダーを入力します。

    カスタム コードを正常に解析してビルドできることを確認するには、[検証] をクリックします。

メモ

ヘッダー ファイルで宣言されている関数のうち、ソース ファイルで定義されていない関数は、既定では C Caller ブロックのダイアログに表示されません。[コンフィギュレーション パラメーター] の [未定義の関数の処理] パラメーターを設定することで、エラーをスローする、スタブ関数を生成する、条件を無視するなど、この状況における動作として別の処理を指定できます。

メモ

C Caller ブロックを For Each Subsystem 内で使用する、または連続サンプル時間を指定して使用する、あるいは条件付き入力分岐実行でブロックの使用を最適化するには、ブロックによって呼び出されるカスタム コード関数が確定的、つまり同じ入力に対して常に同じ出力を生成しなければなりません。[シミュレーション ターゲット] ペインで [確定的な関数] および [関数別に指定] パラメーターを使用して、確定的なカスタム コード関数を特定します。条件付き入力分岐実行の例については、Use C Caller Block with Conditional Executionを参照してください。

N 次元配列の処理

Simulink では、N 次元配列データを C Caller ブロックのカスタム コード関数に渡し、それらのブロックからデータを受け取ることができます。この場合、意図した結果を得るには、正しい配列レイアウトを指定する必要があります。[既定の関数配列のレイアウト] および [関数による例外] を参照してください。C Caller ブロックで配列データを使用する例については、カスタム イメージ フィルター アルゴリズムを Simulink で再利用可能なブロックとして使用およびC Caller ブロックを使用したレガシ ルックアップ テーブル関数を参照してください。

C 関数で行列データを処理する順序を指定できます。C 関数との間で受け渡される行列データは、必要に応じて指定した配列レイアウトに変換されます。配列レイアウトが指定されていない場合、行列データは C 関数を通じて Simulink データと同じ順序で渡され、行優先と列優先の不一致により計算エラーが発生することがあります。すべての Simulink データについて同じ既定の関数配列レイアウトに従うようにしてください。

  • 列優先 — C 関数で入力配列データを列優先の順序で処理します。3 行 3 列の行列があるとします。C 関数では、この行列に 1 列目、2 列目、3 列目の順にアクセスします。

  • 行優先 — C 関数で入力配列データを行優先の順序で処理します。3 行 3 列の行列があるとします。C 関数では、この行列に 1 行目、2 行目、3 行目の順にアクセスします。

  • 任意 — C 関数で入力配列データのレイアウトを考慮しません。たとえば、データに対して要素単位の演算しか実行しない関数などが該当します。

  • 指定なし — C 関数で入力配列データのレイアウトに関する仮定を行いません。[任意] 設定と異なるのは、列優先設定でしかコードを生成できないことです。行優先設定でコードを生成しようとするとエラーになります。[配列のレイアウト] (Simulink Coder) を参照してください。このオプションは、古いモデルとの互換性のために必要な場合にのみ選択します。

Simulink での行優先および列優先の配列レイアウトの詳細については、既定の関数配列のレイアウトを参照してください。

  1. [既定の関数配列のレイアウト] で配列レイアウト オプションを選択します。

  2. 特定の配列レイアウトをコードの関数のいくつかに適用する必要がある場合、[関数による例外] をクリックしてこれらの関数を選択します。

  3. [適用] をクリックして変更を受け入れます。

C 関数がスカラー、ベクトル、またはその両方の入力しか受け入れない場合、[既定の関数配列のレイアウト] を設定しても効果はありません。

C Caller ブロックの呼び出しと端子の指定

Simulink キャンバスで C Caller を入力するだけで、Simulink へのカスタム C コード統合を開始できます。または、C Caller ブロックを User-Defined Functions ライブラリからキャンバスにドラッグします。ブロックをダブルクリックして [ブロック パラメーター] ダイアログ ボックスを開いて、関数の名前と端子の指定を確認します。

  1. [更新] ボタン をクリックしてソース コードとその依存関係をインポートします。

  2. C 関数が [関数名] の下に表示されます。関数の完全なリストが表示されない場合は、Refresh button をクリックしてソース コードを再インポートします。

  3. ソース ファイル内の関数定義を表示するには、View function definitions button をクリックします。選択した関数のソース コードは、MATLAB® エディターに表示されます。ソース コードが利用できない場合、ヘッダー ファイル内の関数宣言が表示されます。

  4. ソース ファイルとその依存関係を変更する、または関数配列レイアウトを定義して選択するには、カスタム コード設定ボタン をクリックして、[モデル コンフィギュレーション パラメーター] の [シミュレーション ターゲット] ペインを開きます。

C 関数の引数の Simulink 端子へのマッピング

C Caller ブロックの [端子仕様] テーブルを使用するか、コマンド ラインで FunctionPortSpecification オブジェクトを作成することで、C 関数の引数をソース コードから Simulink 端子にマッピングできます。ソース コードで、ヘッダー ファイルには Simulink 端子に接続される C 関数の引数が含まれています。

extern void mean_filter(const unsigned char* src,
                           unsigned char* dst,
                           unsigned int width, unsigned int height,
                           unsigned int filterSize);

[端子仕様] テーブルによって、引数の詳細とそれらが Simulink で C Caller ブロックにどのように接続されるかが表示されます。

テーブルには次の列があります。

名前

入力および出力引数の名前を指定します。[名前] は、ソース コードからの C 関数で定義されている、関数の引数またはパラメーターの名前です。この列は参照目的でのみ使用されます。

スコープ

C 関数の引数が Simulink のスコープにどのようにマッピングされるかを指定します。引数には関数の定義により既定のスコープがあり、そのスコープをソース コードの関数定義によって変更できます。

Simulink スコープスコープからブロックへのマッピング
Inputブロック入力端子
Outputブロック出力端子
InputOutputブロックの入力端子と出力端子
Global該当なし
Parameterブロックの調整可能なパラメーター
Constant定数値

ポインターで渡される引数では、その引数が const double *u のような定数の修飾子定義をもつ場合、その引数は Input または Parameter のみです。定数の修飾子がない場合、引数は既定で InputOutput であり、それを InputOutput、または Parameter スコープに変更できます。Input または Parameter スコープの場合、ポインターが指しているメモリが C 関数によって変更されないようにしてください。引数が Output スコープである場合、このポインターで示される各要素はこの関数の呼び出しのたびに再割り当てされます。

C 引数

Simulink スコープ

関数の戻り

Output

double u

InputParameterConstant

double *u

double u[]

double u[][2]

double u[2][3]

InputOutput (既定)、OutputInputParameter

const double *u

const double u[]

const double u[][2]

const double u[2][3]

Input (既定)、Parameter

[InputOutput] スコープを使用して、C 関数のポインターで渡された入力をマッピングします。[InputOutput] スコープを使用して作成された端子の名前は、入力端子と出力端子で同じです。[InputOutput] スコープを使用すると、入力端子と出力端子のバッファーの再利用が有効になります。これにより、信号のサイズとブロック レイアウトに応じてメモリの使用量が最適化されます。

C 関数の引数を [InputOutput] スコープにマッピングするには、関数において変数をポインターとして定義します。

extern void mean_filter(unsigned char* src,
                           unsigned int width, unsigned int height,
                           unsigned int filterSize);

次に、[端子仕様] テーブルでスコープを [InputOutput] に設定し、結果として生じる関数出力をカスタム関数の入力変数に代入します。

カスタム コードのグローバル変数を使用して、それらの変数を適切な Simulink スコープにマッピングできます。モデルでのグローバル変数の使用を有効にするには、[モデル設定][コンフィギュレーション パラメーター][シミュレーション ターゲット]からグローバル変数を関数インターフェイスとして有効にするを選択します。グローバル変数を C Caller ブロックの [Input][Output][InputOutput] または [Global] スコープにマッピングできます。これらのスコープの可用性は、カスタム コードのグローバル変数の仕様によって異なります。

[Global] スコープでは、カスタム コードと C Caller ブロック間でデータを転送でき、ブロックで計算中にグローバル変数を使用できます。[Global] スコープを使用して転送された値はブロック インターフェイスで表示できません。次の表は、コード例の抜粋とその既定端子および使用可能な端子を示しています。

コード例Simulink スコープ

double data;

void foo(void)
    {
        int temp = data;  
    }

グローバル変数では変数 data のみ読み取ります。次のスコープが使用できます。

Input (既定)

Global

double data;

void bar(void)
    {
        data = 0;
    }

データはグローバル変数に書き込まれます。次のスコープが使用できます。

Output (既定)

Global

InputOutput

double data;

void foo2(void)
    {
        data = data + 1;
    }

データはグローバル変数で読み取りと書き込みの両方が実行されます。次のスコープが使用できます。

Global (既定)

InputOutput

Output

ラベル

Simulink ブロックの対応する引数のラベルを示します。既定では、引数のラベルは、変更しない限り引数名と同じです。[スコープ] を変更して、端子ラベルのオプションを設定します。

スコープSimulink 端子のラベル

InputOutput

端子の名前
InputOutput入力端子と出力端子両方の端子の名
Global端子名とグローバル変数名

Parameter

パラメーター名

Constant

定数値の式。

入力引数の名前のサイズ式。例: size(in1,1)

引数のデータ型を指定します。C 関数のデータ型は、Simulink の等価なデータ型と一致する必要があります。次の表は、C Caller ブロックで使用できるサポートされている C データ型と、等価な Simulink データ型を示しています。

C 引数のデータ型Simulink データ型
符号付き char/符号なし charint8/uint8
charint8 または uint8 (コンパイラによる)
int/符号なし int*int32/uint32
short/符号なし short*int16/uint16
long/符号なし long*int32/uint32 または int64/uint64 (オペレーティング システムによる)
long long/符号なし long long*int64/uint64
floatsingle
doubledouble
int8_t/uint8_t*int8/uint8
int16_t/uint16_t*int16/uint16
int32_t/uint32_t*int32/uint32
int64_t/uint64_t*int64/uint64
boolboolean
typedef struct {…} AStruct**Bus:AStruct
typedef enum {..} AnEnum**Enum:AnEnum

* C Caller が整数型を取る場合 (例: int16_t)、一致する基本データ型の固定小数点型 (例: fixdt(1, 16, 3)) に変更できます。

** C Caller 同期ボタンによって、C 関数によって使用される struct または列挙型を Simulink バスおよび列挙型としてインポートできます。

サイズ

引数のデータの次元を指定します。

C 引数の次元Simulink 端子の次元

double u

スカラー (1)

double u[]

double u[][2]

継承 (-1) (既定)

引数が出力端子用の場合、そのサイズを指定する必要があり、その引数が [InputOutput] スコープにマッピングされているか、モデル コンフィギュレーション パラメーターの [カスタム コードのシミュレーションを別のプロセスで行う] が選択されていない限り、サイズが継承されることはありません。

double *u

継承 (-1) (既定)

引数が出力端子用の場合、そのサイズを指定する必要があり、その引数が [InputOutput] スコープにマッピングされているか、モデル コンフィギュレーション パラメーターの [カスタム コードのシミュレーションを別のプロセスで行う] が選択されていない限り、サイズが継承されることはありません。

グローバル変数の場合、サイズはスカラー (1) です。

double u[2][3]

サイズは [2, 3] です。

メモ

ポインター タイプを出力端子として使用する場合は、C 関数内で基となるバッファーの各要素に書き込む必要があります。たとえば、5 行 6 列の行列へのポインターを出力として使用する場合、30 個の要素すべてに書き込む必要があります。そうしないと、配列内に予期しない値が含まれることがあります。

FunctionPortSpecification オブジェクトの作成と C Caller ブロック プロパティの編集

[端子仕様] テーブル プロパティをプログラムで変更するには、FunctionPortSpecification オブジェクトを作成して、そのプロパティを変更します。モデル内の選択された C Caller ブロック用に FunctionPortSpecification オブジェクトを作成するには、コマンド ラインに次を入力します。

myCCallerConfigObj = get_param(gcb, 'FunctionPortSpecification')
myCCallerConfigObj = 

  FunctionPortSpecification with properties:

        CPrototype:  'real_T add(real_T u1, real_T u2);'
    InputArguments:  [1×2 Simulink.CustomCode.FunctionArgument]
    ReturnArgument:  [1×1 Simulink.CustomCode.FunctionArgument] 
    GlobalArguments: [1×0 Simulink.CustomCode.FunctionArgument]
CPrototype プロパティは読み取り専用であり、C 関数の入力変数の宣言を示します。InputArgument プロパティと ReturnArgument プロパティによって作成される FunctionArgument オブジェクトは、上記の [端子仕様] テーブル用に定義されたルールに従って、そのプロパティをさらに編集できます。詳細については、FunctionPortSpecification を参照してください。

C Caller ブロックでグローバル引数を変更するには、getGlobalArg を使用して GlobalArguments オブジェクトへのハンドルを作成し、そのプロパティを修正します。

カスタム C Caller ライブラリの作成

ライブラリ モデルを作成して C Caller ブロックをグループ化し、モデルを整理した状態に維持することをお勧めします。データ ディクショナリをライブラリにリンクして、コードで定義したカスタム型を保持することもできます。ライブラリ モデルを使用すると、複数のモデルがある場合やカスタム C コードを使用するモデル参照階層がある場合に特に便利です。

  1. 新しいライブラリ モデルを開きます。[シミュレーション] タブで、[新規][ライブラリ] を選択します。

  2. [モデル化] タブの [設計] で、[シミュレーションのカスタム コード] をクリックします。

  3. コードによって [言語] オプションで C または C++ を選択し、[カスタム コードのインポート] ボックスがオンになっていることを確認します。

  4. ソース コードと依存関係の指定 の説明に従ってソース ファイルとその依存関係を追加します。

  5. C Caller ブロックを作成して C 関数を呼び出します。

  6. ライブラリ モデルから Simulink モデルにブロックを挿入するには、単純にブロックをモデルにドラッグします。

Simulink コード インポーターを使用してカスタム コードから C Caller ブロックのライブラリを作成することもできます。Simulink コード インポーターを使用したカスタム C/C++ コードのインポートを参照してください。

カスタム コードのデバッグ

Simulink 内からコードをデバッグするには、外部デバッガーを起動し、カスタム コードにブレークポイントを設定します。詳細については、Debug Custom C/C++ Codeを参照してください。

モデルからのコードの生成

C Caller はコード生成をサポートします。モデルから生成されたコードでは、C Caller ブロックの各実行が、ブロックに関連付けられた外部 C 関数の呼び出しに対応します。生成コードをビルドするには、[モデル コンフィギュレーション パラメーター] の [コード生成]、[カスタム コード] ペインにカスタム コードに関する正しい情報が入力されている必要があります。モデル コンフィギュレーション パラメーター: コード生成のカスタム コード (Simulink Coder)を参照してください。

制限

  • カスタム コード設定の初期化/終了 — カスタム コードにメモリを割り当てたり割り当て解除したりする必要がある場合は、カスタム コード設定の [初期化関数] および [終了関数] フィールドに割り当ておよび割り当て解除を挿入するか、C Function ブロックを使用します。

  • 複素数データのサポートC Caller ブロックは Simulink の複素数データ型をサポートしません。

  • 可変引数 — C の可変引数はサポートされません (たとえば、int sprintf(char *str, const char *format, ...))。

  • C++ 構文C Caller ブロックはネイティブの C++ 構文を直接サポートしません。C++ コードとインターフェイスする C 関数ラッパーを記述する必要があります。

C Caller ブロックを含むモデルをテストする場合は、Test Integrated C Code (Simulink Test)を参照してください。

メモ

モデルにカスタム コードが含まれる場合、モデルが更新または実行されると、読み込まれたカスタム コードのシミュレーション実行可能ファイルが原因で slprj フォルダーがロックされる場合があります。ロックされているフォルダーは削除できません。実行可能ファイルをアンロードして、slprj フォルダーのロックを解除するには、clear mex コマンドを使用します。clearを参照してください。

参考

ブロック

関数

オブジェクト

関連するトピック