Create a Customized Asynchronous Library
This topic describes how to implement asynchronous blocks for use with your target RTOS, using the Async Interrupt and Task Sync blocks as a starting point. Rate Transition blocks are target-independent, so you do not need to develop customized rate transition blocks.
Note
The operating system integration techniques that are demonstrated in this topic use blocks that are in the Interrupt Templates block library. The blocks in that library serve as examples to help you develop custom blocks for a specific target environment.
About Implementing Asynchronous Blocks
You can customize the asynchronous library blocks by modifying the block implementation. These files are
The block's underlying S-function MEX-file
The TLC files that control code generation of the block
In addition, you need to modify the block masks to remove references specific to the example RTOS (VxWorks®) and to incorporate parameters required by your target RTOS.
Custom block implementation is an advanced topic, requiring familiarity with the Simulink® MEX S-function format and API, and with the Target Language Compiler (TLC). These topics are covered in the following documents:
Simulink topics What Is an S-Function?, Use S-Functions in Models, How S-Functions Work, and Implementing S-Functions describe MEX S-functions and the S-function API in general.
The Inlining S-Functions, Inline C MEX S-Functions, and S-Functions and Code Generation describe how to create a TLC block implementation for use in code generation.
The following sections discuss the C/C++ and TLC implementations of the asynchronous
library blocks, including required SimStruct
macros and functions in the
TLC asynchronous support library (asynclib.tlc
).
Async Interrupt Block Implementation
The source files for the Async Interrupt block are located in
(open):matlabroot
/rtw/c/tornado/devices
vxinterrupt1.c
: C MEX-file source code, for use in configuration and simulationvxinterrupt1.tlc
: TLC implementation, for use in code generationasynclib.tlc
: library of TLC support functions, called by the TLC implementation of the block. The library calls are summarized in asynclib.tlc Support Library.
C MEX Block Implementation
Most of the code in vxinterrupt1.c
performs ordinary functions that
are not related to asynchronous support (for example, obtaining and validating parameters
from the block mask, marking parameters nontunable, and passing parameter data to the
file).model
.rtw
The mdlInitializeSizes
function uses special
SimStruct
macros and SS_OPTIONS
settings that are
required for asynchronous blocks, as described below.
Note that the following macros cannot be called before
ssSetOutputPortWidth
is called:
ssSetTimeSource
ssSetAsyncTimerAttributes
ssSetAsyncTimerResolutionEl
ssSetAsyncTimerDataType
ssSetAsyncTimerDataTypeEl
ssSetAsyncTaskPriorities
ssSetAsyncTaskPrioritiesEl
If one of the above macros is called before ssSetOutputPortWidth
,
the following error message
appears:
SL_SfcnMustSpecifyPortWidthBfCallSomeMacro { S-function '%s' in '%<BLOCKFULLPATH>' must set output port %d width using ssSetOutputPortWidth before calling macro %s }
ssSetAsyncTimerAttributes. ssSetAsyncTimerAttributes
declares that the block requires a
timer, and sets the resolution of the timer as specified for block parameter
Timer resolution (seconds).
The function prototype is
ssSetAsyncTimerAttributes(SimStruct *S, double res)
where
S is a Simstruct pointer.
Parameter Timer resolution (seconds) is set to
res
.
The following code excerpt shows the call to ssSetAsyncTimerAttributes.
/* Setup Async Timer attributes */ ssSetAsyncTimerAttributes(S,mxGetPr(TICK_RES)[0]);
ssSetAsyncTaskPriorities. ssSetAsyncTaskPriorities
sets the Simulink task priority for blocks executing at each interrupt level, as specified
for block parameter Simulink task priority.
The function prototype is
ssSetAsyncTaskPriorities(SimStruct *S, int numISRs, int *priorityArray)
where
S
is aSimStruct
pointer.numISRs
is the number of interrupts specified for block parameter VME interrupt number(s).priorityarray
is an integer array containing the interrupt numbers specified for block parameter VME interrupt number(s).
The following code excerpt shows the call to
ssSetAsyncTaskPriorities
:
/* Setup Async Task Priorities */ priorityArray = malloc(numISRs*sizeof(int_T)); for (i=0; i<numISRs; i++) { priorityArray[i] = (int_T)(mxGetPr(ISR_PRIORITIES)[i]); } ssSetAsyncTaskPriorities(S, numISRs, priorityArray); free(priorityArray); priorityArray = NULL; }
SS_OPTION Settings. The code excerpt below shows the SS_OPTION
settings for
vxinterrupt1.c
. SS_OPTION_ASYNCHRONOUS_INTERRUPT
should be used when a function call subsystem is attached to an interrupt. For more
information, see the documentation for SS_OPTION
and
SS_OPTION_ASYNCHRONOUS
in
.matlabroot
/simulink/include/simstruc.h
ssSetOptions( S, (SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME | SS_OPTION_ASYNCHRONOUS_INTERRUPT));
If an S-function specifies the
SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME
option and inherits a
sample time of Inf
, the code generator determines how to produce
code for the block based on whether the block is invariant. A block is invariant if its
port signals are invariant. A signal is invariant if it has a constant value during the
entire simulation. If you specify a Constant block sample time, do not
assume that the port signals are invariant. For more information, see Inline Invariant Signals. If
the block is not invariant, the code generator produces code only in the initialize
entry-point function. If the block is invariant, the code generator does not produce
code for the block.
TLC Implementation
This section discusses each function of vxinterrupt1.tlc
, with an
emphasis on target-specific features that you will need to change to generate code for
your target RTOS.
Generate #include Directives. vxinterrupt1.tlc
begins with the statement
%include "vxlib.tlc"
vxlib.tlc
is a target-specific file that generates directives to
include header files for the example RTOS (VxWorks). You should replace this with a file
that generates includes for your target RTOS.
BlockInstanceSetup Function. For each connected output of the Async Interrupt block,
BlockInstanceSetup
defines a function name for the corresponding
ISR in the generated code. The functions names are of the form
isr_num_vec_offset
where
is the ISR number defined
for block parameter VME interrupt number(s), and
num
is an interrupt table offset
defined by block parameter VME interrupt vector offset(s).offset
In a custom implementation, this naming convention is optional.
The function names are cached for use by the Outputs
function,
which generates the actual ISR code.
Outputs Function. Outputs
iterates over the connected outputs of the Async
Interrupt block. An ISR is generated for each such output.
The ISR code is cached in the "Functions"
section of the
generated code. Before generating the ISR, Outputs
does the
following:
Generates a call to the downstream block (cached in a temporary buffer).
Determines whether the ISR should be locked or not (as specified by block parameter Preemption Flag(s)).
Determines whether the block connected to the Async Interrupt block is a Task Sync block. (This information is obtained by using the
asynclib
callsLibGetFcnCallBlock
andLibGetBlockAttribute
.) If so,The preemption flag for the ISR must be set to
1
. An error results otherwise.The RTOS (VxWorks) calls to save and restore floating-point context are generated, unless the user has configured the model for integer-only code generation.
When generating the ISR code, Outputs
calls the
asynclib
function LibNeedAsyncCounter
to
determine whether a timer is required by the connected subsystem. If so, and if the time
source is set to be SS_TIMESOURCE_SELF
by
ssSetTimeSource
, LibSetAsyncCounter
is
called to generate an RTOS (VxWorks) tickGet
function call and
update the counter. In your implementation, you should generate either an equivalent
call to the target RTOS, or generate code to read the a timer register on the target
hardware.
Start Function. The Start
function generates the required RTOS (VxWorks) calls
(int_connect
and sysInt_Enable
) to connect
and enable each ISR. You should replace this with calls to your target RTOS.
Terminate Function. The Terminate
function generates the call
sysIntDisable
to disable each ISR. You should replace this with
calls to your target RTOS.
Task Sync Block Implementation
The source files for the Task Sync block are located in
(open). They
arematlabroot
/rtw/c/tornado/devices
vxtask1.cpp
: MEX-file source code, for use in configuration and simulation.vxtask1.tlc
: TLC implementation, for use in code generation.asynclib.tlc
: library of TLC support functions, called by the TLC implementation of the block. The library calls are summarized in asynclib.tlc Support Library.
C MEX Block Implementation
Like the Async Interrupt block, the Task Sync block sets
up a timer, in this case with a fixed resolution. The priority of the task associated with
the block is obtained from block parameter Simulink task priority.
The SS_OPTION
settings are the same as those used for the Async
Interrupt block.
ssSetAsyncTimerAttributes(S, 0.01); priority = (int_T) (*(mxGetPr(PRIORITY))); ssSetAsyncTaskPriorities(S,1,&priority); ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_ASYNCHRONOUS | SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME)); }
TLC Implementation
Generate #include Directives. vxtask1.tlc
begins with the statement
%include "vxlib.tlc"
vxlib.tlc
is a target-specific file that generates directives to
include header files for the example RTOS (VxWorks). You should replace this with a file
that generates includes for your target RTOS.
BlockInstanceSetup Function. The BlockInstanceSetup
function derives the task name, block
name, and other identifiers used later in code generation. It also checks for and warns
about unconnected block conditions, and generates a storage declaration for a semaphore
(stopSem
) that is used in case of interrupt overflow
conditions.
Start Function. The Start
function generates the required RTOS (VxWorks) calls
to define storage for the semaphore that is used in management of the task spawned by
the Task Sync block. Depending on the value of the
CodeFormat
TLC variable of the target, either a static storage
declaration or a dynamic memory allocation call is generated. This function also creates
a semaphore (semBCreate
) and spawns an RTOS task
(taskSpawn
). You should replace these with calls to your target
RTOS.
Outputs Function. The Outputs
function generates an example RTOS (VxWorks) task
that waits for a semaphore. When it obtains the semaphore, it updates the block tick
timer and calls the downstream subsystem code. Outputs
also
generates code (called from interrupt level) that grants the semaphore.
Terminate Function. The Terminate
function generates the example RTOS (VxWorks)
call taskDelete
to end execution of the task spawned by the block.
You should replace this with calls to your target RTOS.
Note also that if the target RTOS has dynamically allocated memory associated with
the task, the Terminate
function should deallocate the
memory.
asynclib.tlc Support Library
asynclib.tlc
is a library of TLC functions that support the
implementation of asynchronous blocks. Some functions are specifically designed for use in
asynchronous blocks. For example, LibSetAsyncCounter
generates a call
to update a timer for an asynchronous block. Other functions are utilities that return
information required by asynchronous blocks (for example, information about connected
function call subsystems).
The following table summarizes the public calls in the library. For details, see the
library source code and the vxinterrupt1.tlc
and
vxtask1.tlc
files, which call the library functions.
Summary of asynclib.tlc Library Functions
Function | Description |
---|---|
| For use by inlined S-functions with function call outputs. Generates code to execute a function call subsystem. |
| Returns a field value from a block record. |
| Given an S-Function block and call index, returns the block record for the downstream function call subsystem block. |
| Provides access to the time counter of an upstream asynchronous task. |
| Provides access to the high word of the time counter of an upstream asynchronous task. |
| Determines whether an asynchronous task needs a counter and manages its own timer. |
| If the calling block requires an asynchronous counter, returns
|
| Returns code that sets |
| Generates code to set the tick value of the block's asynchronous counter. |
| Generates code to set the tick value of the high word of the block's asynchronous counter |