Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

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

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

  • 単純な C 関数の自動化された統合

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

  • Simulink Coder™ との統合

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

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

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

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

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

  3. C Caller ブロックによる解析を有効にするには [カスタム コードのインポート] ボックスがオンになっていることを確認します。

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

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

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

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

メモ

関数がヘッダー ファイルで宣言されていてソース コードで実装されていない場合、シミュレーションとモデルのコンパイルのために空のスタブ関数が自動的に生成されます。

メモ

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

既定の関数配列レイアウトの定義

Simulink で行列データが格納される順序を指定できます。C 関数へ、または C 関数から渡される行列データは、指定した既定の関数配列レイアウトに変換されます。関数配列レイアウトが指定されていない場合、行列データは C Caller を通じて Simulink データと同じ順序で渡され、行優先と列優先の乱れにより計算エラーが発生することがあります。すべての Simulink データについて同じ既定の関数配列レイアウトに従うようにしてください。

  • 列優先C Caller ブロックは Simulink データを列優先の順序で処理します。3 行 3 列の行列があるとします。C Caller ブロックでは、この行列は 1 列目、2 列目、3 列目の順序で格納されます。

  • 行優先C Caller ブロックは Simulink データを行優先の順序で処理します。3 行 3 列の行列があるとします。C Caller ブロックでは、この行列は 1 行目、2 行目、3 行目の順序で格納されます。

  • 任意C Caller ブロックで、列優先および行優先の両方の順序で配列データを格納できます。その結果、列優先および行優先の両方の設定でコードを生成できます。

  • 指定なし — 配列のデータは列優先および行優先の両方の順序で格納できます。[任意] 設定と比較して、列優先設定でのみコードを生成できます。

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

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

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

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

  4. [OK] をクリックして [コンフィギュレーション パラメーター] を閉じます。

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

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

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

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

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

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

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 スコープSimulink 端子のラベル

InputOutput

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

Parameter

パラメーター名

Constant

定数値の式。

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

タイプ — Simulink データ型と C 関数の引数のデータ型との一致を判別します。

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

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

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

サイズ — 引数のデータの次元を指定します。

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

double u

スカラー (1)

double u[]

double u[][2]

継承 (-1) (既定)

引数が出力端子用の場合、サイズを指定する必要があります。出力端子のサイズは継承できません。

double *u

継承 (-1) (既定)

[出力] 端子のサイズを継承できる場合でも、引数が [inputoutput] 端子用である場合はサイズを継承できません。

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

double u[2][3]

サイズは [2, 3]。

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 ブロックをグループ化し、モデルを整理した状態に維持できます。

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

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

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

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

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

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

カスタム コード用のデバッグ シンボルの生成

外部のデバッガーを MATLAB プロセスに追加し、外部 C コードをデバッグするには、次を使用してデバッグ シンボルを生成します。

Simulink.CustomCode.debugSymbols('on')
この設定をオンにしてモデルを更新したら、デバッグ シンボルが生成され、外部のデバッガーを MATLAB プロセスに追加できます。

次を使用して、この設定をオフにします。

Simulink.CustomCode.debugSymbols('off')

別のプロセスでカスタム コードのシミュレーションを行う

カスタムの C または C++ コードを含むモデルのシミュレーションを実行する場合、MATLAB 外の別のプロセスでカスタム コードを実行できるオプションがあります。このオプションは、カスタム コードをデバッグする場合に役立ちます。別のプロセスで実行すると、カスタム コードの問題が原因で MATLAB がクラッシュすることがなくなり、問題のデバッグと解決が簡単に実行できます。カスタム コードの予期しない例外または Simulink とカスタム コード間のインターフェイスにおけるエラーが原因で問題が生じる可能性があります。

このオプションを有効にするには、モデル コンフィギュレーション パラメーターで、[シミュレーション ターゲット] ペインの [カスタム コードのシミュレーションを別のプロセスで行う] を選択します。このオプションは、以下のブロックのいずれかを使用してモデルに統合されたカスタムの C/C++ コードに適用されます。

  • C Caller

  • C Function

  • MATLAB Function

  • MATLAB System

  • Stateflow® チャート

The Simulation Target pane of the Configuration Parameters dialog. The pane shows a checkbox for 'Simulate custom code in a separate process' parameter.

たとえば、このモデルに、adderObj と呼ばれるオブジェクトにアクセスする関数 adder() を呼び出す C Caller ブロックが含まれるとします。関数を呼び出す前にオブジェクトを作成しなければなりません。オブジェクトを作成するには、モデル コンフィギュレーション パラメーターの [シミュレーション ターゲット] ペインの [初期化関数] から initAdder() を呼び出します。

part of Simulink model canvas including C Caller block with "adder" on the block icon

static Adder* adderObj = nullptr;

int adder(int increment)
{
    adderObj->add_one(increment);
    return adderObj->get_val();
}

void initAdder()
{
    adderObj = new Adder();
}

adder() の前に initAdder() が呼び出されない場合、adder() は初期化されていないポインターにアクセスを試み、実行時例外の原因になります。[カスタム コードのシミュレーションを別のプロセスで行う] パラメーターが選択されていない場合、モデルをシミュレートするときに、この例外によって MATLAB がクラッシュする可能性があります。ただし、このパラメーターが選択されている場合、モデルをシミュレートすると、Simulink 内にエラー メッセージが示されます。

Error message text

次に、[開く] をクリックして外部デバッガーを起動し、エラーの原因となっている問題を解決します。

external debugger showing custom C code with breakpoints set

デバッガーが起動すると、シミュレーションが再開し、カスタム関数エントリのブレークポイントで自動的に停止します。

カスタム コードが完全にデバッグされたら、[別のプロセスでカスタム コードのシミュレーションを行う] をオフにしてシミュレーション時間を高速化できます。

制限

  • グローバル変数 — 関数の入出力としてのグローバル変数は、多次元配列をサポートしません。

  • カスタム コード設定の初期化/終了 — カスタム コードにメモリを割り当てたり割り当て解除したりする必要がある場合は、カスタム コード設定の [初期化関数] および [終了関数] フィールドに割り当ておよび割り当て解除を挿入するか、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を参照してください。

参考

| | | | | | | |

関連するトピック