Generate C Interface Code for Measurement Service Using Persistent Data for Component Deployment
This example shows how to generate component code that includes interface support for accessing state data stored in nonvolatile memory. The generated interface code must align with target environment interface requirements.
The example shows how to:
Represent measurable state data that is stored in nonvolatile memory in the top model.
Configure the code generator to apply a code interface.
Generate and inspect the interface code.
Represent Measurement Data in Top Model
Open example component model ComponentServiceWithPersistency
.
open_system('ComponentServiceWithPersistency');
The integrator and accumulator functions operate on state data, which is stored in nonvolatile memory. Discrete state data is accessed through the measurement service interface for persistent data.
Open the function-call subsystems Integrator
and Accumulator
to review the function modeling.
The integrator function uses a state variable to represent the discrete time integrator. The accumulator function uses a state variable to represent the delay. In this example, the target environment requires the names of the corresponding variables in the generated code to be dti
and delay
.
Configure Measurement Code Interface for Persistent Data
The example model is linked to the shared Embedded Coder Dictionary file ComponentServiceCoderDictionary.sldd
, which defines a service code interface configuration. That configuration defines a measurement service interface named PermanentRAM
. The PermanentRAM
service interface has persistent data support enabled and is configured to apply storage class PersistentMemory
, which is defined with these settings:
Data Access -
Direct
Data Scope -
Exported
Header File -
$N.h
Definition File -
$N.c
Use different property settings for single-instance and multi-instance data -
off
Storage Type -
Unstructured
Data Initialization -
None
Memory Section -
None
Preserve array dimensions -
off
In addition, no qualifiers are specified. In the values for Header File and Definition File, the software replaces $N
with the name of the model.
Configure the model so that the code generator applies the PermanentRAM
coder dictionary interface to the modeling elements that use persistent data.
Open the Embedded Coder app.
On the C Code tab, select Code Interface > Component Interface to configure individual model elements.
In the Code Mappings editor, click the Signals/States tab.
Expand the States node and select the row for
Discrete-Time Integrator
.From the menu in the Measurement Service column of the selected row, select
PermanentRAM
.In the selected row, click the pencil icon.
In the dialog box that appears, set Identifier to
dti
. Alternatively, you can set Identifier in the Property Inspector.Select the row for
Unit Delay
.Set Identifier to
delay
.
Save configuration changes by saving the model.
Generate and Inspect Interface Code
Generate code from the example model. The code generator creates the folder ComponentServiceWithPersistency_ert_rtw
in the current working folder and places source code files in that folder. The generated code is in two primary files: header file ComponentServiceWithPersistency.h
and source code file ComponentServiceWithPersistency.c
. Model data and entry-point functions are accessible to a caller by including the header file in the target environment software.
To inspect the generated code, use the code generation report or, in the Embedded Coder app, use the Code view.
Header File
The header file ComponentServiceWithPersistency.h
declares model data structures and a public interface to the model entry points and exported model data.
This code fragment shows the declaration of block state variables for persistent data that are exported through the header file.
extern double delay[10]; /* '<S1>/Unit Delay' */ extern double dti[10]; /* '<S2>/Discrete-Time Integrator' */
Source Code File
This code fragment in generated source code file ComponentServiceWithPersistency.c
shows code relevant to the measurement service interface for persistent data.
/* Storage class 'PersistentMemory' */ double delay[10]; double dti[10]; . . . void CD_accumulator(void) { const double *tmpDataTransferIRead; double rtb_Sum_0; int32_t i; tmpDataTransferIRead = get_CD_accumulator_DataTransfer(); for (i = 0; i < 10; i++) { rtb_Sum_0 = tmpDataTransferIRead[i] + delay[i]; (getref_CD_accumulator_OutBus_y())[i] = CD_tunable.k * rtb_Sum_0; delay[i] = rtb_Sum_0; } } void CD_integrator(void) { double DiscreteTimeIntegrator[10]; double DiscreteTimeIntegrator_0; double *tmp; uint64_t Integrator_ELAPS_T; int32_t i; tmp = set_CD_integrator_DataTransfer(); if (rtDWork.Integrator_RESET_ELAPS_T) { Integrator_ELAPS_T = 0ULL; } else { Integrator_ELAPS_T = (uint64_t)get_tick_outside_tick_CD_integrator() - rtDWork.Integrator_PREV_T; } rtDWork.Integrator_PREV_T = get_tick_outside_tick_CD_integrator(); rtDWork.Integrator_RESET_ELAPS_T = false; for (i = 0; i < 10; i++) { if (rtDWork.DiscreteTimeIntegrator_SYSTEM_E != 0) { DiscreteTimeIntegrator_0 = dti[i]; } else { DiscreteTimeIntegrator_0 = 0.25 * (double)Integrator_ELAPS_T * rtDWork.DiscreteTimeIntegrator_PREV_U[i] + dti[i]; } DiscreteTimeIntegrator[i] = DiscreteTimeIntegrator_0; dti[i] = DiscreteTimeIntegrator_0; rtDWork.DiscreteTimeIntegrator_PREV_U[i] = (get_CD_integrator_InBus_u())[i]; } rtDWork.DiscreteTimeIntegrator_SYSTEM_E = 0U; memcpy(&tmp[0], &DiscreteTimeIntegrator[0], 10U * sizeof(double)); } void ComponentServiceWithPersistency_initialize(void) { (void) memset((void *)&rtDWork, 0, sizeof(D_Work)); { double *tmp; int32_t i; tmp = set_ComponentServiceWithPersistency_initialize_DataTransfer(); for (i = 0; i < 10; i++) { rtDWork.DiscreteTimeIntegrator_PREV_U[i] = 0.0; tmp[i] = 5.0; } rtDWork.Integrator_RESET_ELAPS_T = true; rtDWork.DiscreteTimeIntegrator_SYSTEM_E = 1U; } } void ComponentServiceWithPersistency_terminate(void) { }
The accumulator and integrator functions use the variables dti
and delay
to hold internal states during algorithmic computations for the functions. Variables dti
and delay
are not initialized in ComponentServiceWithPersistency_initialize
or elsewhere in the generated code because those variables are mapped to persistent data, which is initialized and managed by a nonvolatile memory management service in the external environment.