Inhalt
TODO bisher sind nur die Buskapitel beschrieben, existiert als pdf
Topic:.SmlkSfunc_jzTc.
Topic:.SmlkSfunc_jzTc.SmlkSfunc_jzTc.
Der SmlkSfunc_jzTc-Generator für Sfunctions generiert aus einem gegebenen Headerfile:
die Busdefinitionen als eben dieses Matlab-Script.
die Wrapper der Sfunctions (C-Sources)
Reflection der struct
in den Header, das sind Konstante, die in C den Aufbau der struct
wiederspiegeln ('reflektieren'), Reflection-Files sind const-Definitionen als C-Sources
Das Generierscript für die mex-Generierung als Matlab-File.
Benötigt wird dazu
Ein Headerfile für mehrere SFBlocks, dieses enthält im Comment die notwenigenen Angaben.
Ein jzTc-Rahmenscript für die Generierung, der die Kern-Scripts aufruft. Dieses Script legt fest:
Welche Headerfiles
Welche C-Files benutzt werden pro Headerfile für alle dort benannten Sfunction
Settings für die Generierung
Die entsprechenden C-Sources für die Kernfunktionen
Man kann den Sfunction-Generator SmlkSfunc_jzTc auch nur für die Buss-Generierung nutzen, bzw. Busse, die nicht in Sfunction
verwendet werden, ebenfalls aus typedef struct
in einem Headerfile generierene. Der Vorteil ist eine einheitliche Herangehensweise und eine klare textuelle Busdefinition
über die struct
. Die struct
bzw. der Header wird dann für die Codegenerierung für ein Zielsystem gleich benutzt.
Topic:.SmlkSfunc_jzTc.bus.
Last changed: 2019-03-10
Busse stellen ein probates Mittel der Datenbündelung in Simulink außerhalb von Sfunction dar. Die Busse werden im Simulink-Datenhaushalt
wie strukturierte Daten abgelegt. Dem entsprechend ist im generiertem Code ein Bus als Datenstruktur mit den entsprechenden
Elementen (struct
) realisiert. Dabei kann entweder der Simulink-Coder aus der Busdefinition die typedef struct { ... }
generieren:
MyBus.DataScope = 'Exported';
oder die Coder setzt die Existenz eines Headers mit einer passenden typedef struct { ... }
für den Bus voraus und benutzt diese Typdefinition:
MyBus.HeaderFile = 'srcC_Model/MeasPrep.h'; MyBus.DataScope = 'Imported';
Diese gezeigten Codezeilen können in ein Matlab-Script enthalten sein, dass den Bus im Simulink-Datenhaushalt definiert durch Abarbeiten dieses Scripts, zweckmäßig beim Modellstart. Der Rahmen für das Script wird gebildet mit
clear MyBus_elems; ix = 1; MyBus_elems(ix) = Simulink.BusElement; MyBus_elems(ix).Name = 's1'; .... MyBus = Simulink.Bus; MyBus.Elements = MyBus_elems; assignin('base','MyBus', MyBus);
Die andere Möglichkeit ist die Nutzung der grafischen Bedienung für die Anlage des Busses. Damit steht die Busdefinition im Modell.
Diese 4 Möglichkeiten:
Bus definieren über Script oder im Modell mit grafischer Bedienung
Bus imported (Header manuell beigestellt) oder exported (Header wird generiert)
sind im Simulink aus Sicht der Mathworks-Strategie-Vorgaben etwa gleichwertig, Mathworks unterstützt alle 4 Kombinationen. Wenn man stark mit Sfunctions arbeitet, Kernfunktionen in C einbinden möchte und dies auch mit Bussen verbinden möchte, dann ist nur eine Kombination zweckmäßig:
Die typedef struct
zu den Bussen wird manuell definiert, also imported
. Die struct
werden in den C-Sourcen der Sfunction direkt verwendet.
Die Busdefinitionen werden über Matlab-Scripte in das Simulink beim Modellstart eingebracht. Das Script ist adäquat zur struct
-Definition textuell und kann miteinander als Textfile versioniert werden.
Topic:.SmlkSfunc_jzTc.SmlkSfunc_jzTc.
Der SmlkSfunc_jzTc-Generator für Sfunctions generiert aus einem gegebenen Headerfile:
die Busdefinitionen als eben dieses Matlab-Script.
die Wrapper der Sfunctions (C-Sources)
Reflection der struct
in den Header, das sind Konstante, die in C den Aufbau der struct
wiederspiegeln ('reflektieren'), Reflection-Files sind const-Definitionen als C-Sources
Das Generierscript für die mex-Generierung als Matlab-File.
Benötigt wird dazu
Ein Headerfile für mehrere SFBlocks, dieses enthält im Comment die notwenigenen Angaben.
Ein jzTc-Rahmenscript für die Generierung, der die Kern-Scripts aufruft. Dieses Script legt fest:
Welche Headerfiles
Welche C-Files benutzt werden pro Headerfile für alle dort benannten Sfunction
Settings für die Generierung
Die entsprechenden C-Sources für die Kernfunktionen
Man kann den Sfunction-Generator SmlkSfunc_jzTc auch nur für die Buss-Generierung nutzen, bzw. Busse, die nicht in Sfunction
verwendet werden, ebenfalls aus typedef struct
in einem Headerfile generierene. Der Vorteil ist eine einheitliche Herangehensweise und eine klare textuelle Busdefinition
über die struct
. Die struct
bzw. der Header wird dann für die Codegenerierung für ein Zielsystem gleich benutzt.
Topic:.SmlkSfunc_jzTc.busport.
Video über Busse in Sfunctionen, mit Debug des Checks, ca. 20 min
Die Sfunction können Busse im Simulink direkt von den Adressen an den Ports zugreifen:
MyBus const* x_bus = ( MyBus const*)ssGetInputPortSignal(simstruct, ixInputPort);
Simulink speichert im Bus die Daten im passenden Layout zur struct, allerdings mit Bedingungen:
Bitfields in der struct
werden in Bussen nicht berücksichtigt. Diese sind aber günstig für Boolean-Variable.
Der Bus und die struct
müssen genau übereinstimmen, sowohl von der Versionierung (welche Elemente, welche Typen) als auch vom Speicherlayout. Letzteres
ist in vielen Fällen, aber nicht garantiert verwirklicht.
Wenn die Busdefinition aus dem Headerfile generiert wird und der Headerfile im Speicherlayout genauso eingestellt ist wie der Bus (das ist in einem 64-bit-System 8-Byte-Alignment), dann passen diese Dinge.
Der Legacy-Code-Sfunction-Generator von Mathworks setzt die Übereinstimmung nicht voraus, da ein Anwender beliebig zusammenstellen kann. Daher werden dort alle Buselemente über memcpy in die temporär angelegte Struktur kopiert und umgekehrt bei Outputs, die Sfunction bekommt dann den Zeiger auf die temporäre struct im Stack. Das ist etwas Overhead.
Bei der SmlkSfunc_jzTc-Generierung wird folgender Weg gegangen:
Der Anwender bestimmt mit der Bezeichnung
...( ..., MyBus* x_bus, MyBus* x_cbus, MyOutBus* y_ybus, MyBus* y_ycbus, ...)
ob das Argument als direkte Bus oder kopierte Einzelelemente in der struct übernommen wird. Die letztere Variante ist notwendig
wenn die struct
Bitfields für boolean enthält oder die Busdefinition von der struct
Definition abweichen kann, insbesondere auch wenn union
verwendet werden.
Wenn die Elemente kopiert werden, dann nicht über memcpy
wenn es sich um Bitfields handelt. Damit gelingt deren Abbildung als bool
-Typ.
Die _bus
oder _ybus
-Variante setzt voraus, dass das Memorylayout des Busses mit dem der struct
übereinstimmt, prüft dies aber bei der Initialisierung. Für die Prüfung muss bekannt sein, welche Namen und Position in der
struct
die einzelnen Elemente im Bus haben. Beide können erfrag werden. Die der struct
über Reflection und die des Busses über die entsprechenden ssGetBusElement...(...)
-Funktionen aus dem Simulink-API. Wenn die Übereinstimmung nicht gegeben ist, wird die Simulation mit einer Fehlermeldung
bei der Initalisierung abgebrochen. Wenn die Busdefinition aus dem Header generiert wurde, kann es sich dabei um folgende
Ursachen handeln:
Versions-Mismatch
Der Header ist komplex, enthält doch bitfield oder union, ist also für diese Arbeitsweise nicht geeignet.