Guy and Seth on Simulink

May 7th, 2008

Bus Signals in the Generated Code

Blog reader Paul J. shared with us his mental model of the bus as a structure. While this isn’t true of virtual buses, it is precisely true of nonvirtual buses. In fact, when you generate the code for a nonvirtual bus using Real-Time Workshop, the result is a structure.

Focus on the boundaries

In a previous post about nonvirtual bus signals I talked about memory allocated for the bus. The places we have to think about memory allocation are the boundaries of systems. Here is the simplebusdemo_nv.mdl

Simple bus demo diagram with a nonvirtual bus

This model has the root level boundaries defined by the inport and outport blocks. It also has a boundary at the edge of the ReusableFcn subsystem. The main_bus crosses this boundary and the generated code is different if the bus is virtual versus nonvirtual.

The ReusableFcn subsystem contains a Bus Selector and two gain blocks.

ReusableFcn subsystem with nonvirtual bus input

I configured the subsystem to generate a reusable function. Here are the settings for the subsystem:

ReusableFcn subsystem parameters

Basically, I have specified how Real-Time Workshop should wrap up the algorithm implemented inside this system. By specifying “Treat as atomic unit”, the blocks inside the system execute together. Real-Time Workshop will generate reusable function code with my specified name (ReusableFcn) into a file of the same name (ReusableFcn.c). The reusable function code will pass input and output signals as arguments to the function.

I can now picture what this will look like:

ReusableFcn(inputs..., outputs...)

Virtual buses pass every element separately

ReusableFcn subsystem with virtual bus input

When the bus signal is virtual at the inport to the ReusableFcn, only the elements of the bus that are used in the system need to be passed through the boundary. Here is the actual code for the function call:

30   /* Outputs for atomic SubSystem: '<Root>/ReusableFcn' */
31   ReusableFcn(simplebusdemo_vir_U.Pulse, simplebusdemo_vir_U.Chirp,
32               &simplebusdemo_vir_B.ReusableFcn_m);
33 

Notice, there is no evidence in the code that a bus signal exists. At compile-time, direct connections between sources and destinations replace the virtual bus.

19 /* Output and update for atomic system: '<Root>/ReusableFcn' */
20 void ReusableFcn(real32_T rtu_0, real_T rtu_1, rtB_ReusableFcn *localB)
21 {
22   /* Gain: '<S1>/Gain' */
23   localB->Gain = 2.0F * rtu_0;
24 
25   /* Gain: '<S1>/Gain1' */
26   localB->Gain1 = 3.0 * rtu_1;
27 }

Nonvirtual buses are structures

ReusableFcn subsystem with nonvirtual bus input

The nonvirtual bus is a contiguous block of memory. This is assembled and passed into the ReusableFcn.

30   /* local block i/o variables */
31   main_bus rtb_main_bus;
32 
33   /* BusCreator: '<Root>/Bus Creator' incorporates:
34    *  BusCreator: '<Root>/BusConversion_InsertedFor_Bus Creator_at_inport_0'
35    *  BusCreator: '<Root>/BusConversion_InsertedFor_Bus Creator_at_inport_1'
36    *  Inport: '<Root>/In1'
37    *  Inport: '<Root>/In2'
38    *  Inport: '<Root>/In3'
39    *  Inport: '<Root>/In4'
40    *  Inport: '<Root>/In5'
41    */
42   rtb_main_bus.bus1.Chirp = simplebusdemo_nv_U.Chirp;
43   rtb_main_bus.bus1.Constant[0] = simplebusdemo_nv_U.Constant[0];
44   rtb_main_bus.bus1.Constant[1] = simplebusdemo_nv_U.Constant[1];
45   rtb_main_bus.bus1.Constant[2] = simplebusdemo_nv_U.Constant[2];
46   rtb_main_bus.bus2.Clock = simplebusdemo_nv_U.Clock;
47   rtb_main_bus.bus2.Pulse = simplebusdemo_nv_U.Pulse;
48   rtb_main_bus.bus2.Sine[0] = simplebusdemo_nv_U.Sine[0];
49   rtb_main_bus.bus2.Sine[1] = simplebusdemo_nv_U.Sine[1];
50 
51   /* Outputs for atomic SubSystem: '<Root>/ReusableFcn' */
52   ReusableFcn(&rtb_main_bus, &simplebusdemo_nv_B.ReusableFcn_a);

Each of the input signals is being copied into the rtb_main_bus variable, which is an instance of the main_bus type. This structure matches the bus object definition specified by main_bus, bus1, and bus2.

I notice that the ReusableFcn has a shorter interface. Now the only input signal is a pointer to the rtb_main_bus, which is allocated locally.

ReusableFcn subsystem with nonvirtual bus input

19 /* Output and update for atomic system: '<Root>/ReusableFcn' */
20 void ReusableFcn(const main_bus *rtu_In1, rtB_ReusableFcn *localB)
21 {
22   /* Gain: '<S1>/Gain' */
23   localB->Gain = 2.0F * (*rtu_In1).bus2.Pulse;
24 
25   /* Gain: '<S1>/Gain1' */
26   localB->Gain1 = 3.0 * (*rtu_In1).bus1.Chirp;
27 }

In the case of nonvirtual bus signals, the concept of interface specification using the bus object carries all the way down to the generated code.

Now it’s your turn

We have now covered most of the important topics on bus signals. What questions remain about bus signals and their use in your models? Post a comment here.

6 Responses to “Bus Signals in the Generated Code”

  1. Bob replied on :

    Any particular reason you chose to specify the name of the atomic subsystem? I try to avoid that in case I’ve used the block twice with different I/O data types, and usually find the name in the generated code comes close enough to the subsystem name to make traceability possible.

  2. Bob replied on :

    Occasionally we’ve used busses to parameterize a model. To cut down on function interface overhead, the non-virtual bus makes sense. But if you use a set of Constant blocks to feed a Bus Creator outputting a non-virtual bus, the generated code looks like:
    rtb_bus.bus1.Parameter1 = 7;
    rtb_bus.bus1.Parameter2 = FRED;
    rtb_bus.bus2.Parameter3 = 8;
    instead of:
    rtb_bus = { {7, FRED}, {8} };
    And this usually appears in the step, not the initialize.

    Is there a way to get the preferred output?

  3. Seth replied on :

    @Bob – I chose to specify the name because I wanted to shorten things up for the blog post. When I used the Auto or Subsystem Name option I got this:


    19 /* Output and update for atomic system: '<Root>/ReusableFcn' */
    20 void simplebusdemo_nv_ReusableFcn(const main_bus *rtu_0,
    21 rtB_ReusableFcn_simplebusdemo_n *localB)
    22 {

    I was just trying to avoid the line wrap.

    Regarding parameterization using bus signals, this is a limitation of the current behavior of bus signals. Currently, bus signals can not inherit the Inf sample time, so they end up in the step function even if the inputs are constant. It should be possible to use a custom storage class to control the generation of the code for the bus and put the code into the initialization section.

  4. Angelo replied on :

    Hi Seth,

    I’m looking for a way to transmit names of signals from Simulink to Matlab (in a structure?) but I encountered some problem. One way should be showing the propagated signals (from the Signal Properties…) but I need switching with a command (e.g. with a set_param command: something like

    set_param(ln_sn_hand.Inport(j),'ShowPropagatedSignals','all');
    

    ) this line parameter from ‘off’ to ‘on’ (or to ‘all’) and it seems to me this is not a enabled parameter of the line.

    Could you give some input about that?

    Thanks

    angelo

  5. wei replied on :

    @angelo, what you had is a port handle. port of Inport type can’t propagate signal. Your command will work for outport.

    Alternatively if line handle is available, you can always do

    set(lineH,'signalPropagation','on')
    

    @seth,
    Block parameter is fairly documented. But not line, prot etc. Maybe worth an entry here?

  6. Angelo replied on :

    Hi wei,

    thanks for yous suggestion, but maybe I found something more general to my problem. My primitive problem was to read the signal names flowing on lines and it seems that more people have these issues:

    http://www.mathworks.de/support/solutions/data/1-2JW10T.html?product=SL&solution=1-2JW10T

    I encountered some more problem with masked blocks but I think it could be a good way to go.

    Cheers

    angelo

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


MathWorks
Guy Rouleau and Seth Popinchalk are Application Engineers for MathWorks. They write here about Simulink and other MathWorks tools used in Model-Based Design.

These postings are the author's and don't necessarily represent the opinions of The MathWorks.