SinelaboreRT Header Logo

SinelaboreRT

Productivity for embedded software development

User Tools

Site Tools


wiki:examples:function_blocks_desing

Signal Forming Function Block Design with State Diagrams

In this tutorial you will learn

  • how to use conditions to trigger state transitions in your state machine
  • how to benefit from adding attributes to a stateful class
  • using state machines to create library of reusable function blocks for control signal forming

In another example you can learn how to create a PLCOpen safety function block using the same concept.

What are conditional events

The code generator supports two basic modes of operation which should not be mixed. Either it processes events. Only if an event is present a transition is taken. Events are eventually send to the state machine using an event queue. Alternatively transitions are triggered by boolean conditions. If a boolean condition is true a state change happens. The latter one is useful if binary signals should be processed like we will see in our example. In this case the state machine runs without receiving a dedicated event but depending on state boolean state is used to trigger state transitions.

The Problem

Image an embedded system - such as an industrial control device - which has several binary inputs. Often the behaviour of such a device is influenced by the state of these inputs. E.g. an actor should be switched on, a lamp should be activated etc. But often not the raw input signal should be used but a preprocessed signal such as:

  • Trigger an activity on the rising or falling edge of an input signal (ftrig, rtrig). These bocks are useful to create an event from a boolean signal.
  • Delay the input signal for some time (so called on-delay)
  • Wait until an input signal was switched off again (so called off-delay)
  • Combination of the two above (on/off delay)
  • Offering a pause input to pause the time condition of the above signals
  • Offer an option to reset a started timing
  • Shaping an input signal - i.e. creating a pulse of defined length independent from the length of the input signal
  • Debounce inputs

There exist many more such functions. You might have come across them in your own practise.

The Solution

It would be very beneficial to have a library of such functions that can be easily integrated into a system design. All the above ones require some state so it makes sense of course to model them as state machines. The design presented here is based on Enterprise Architect and uses the option to model additional attributes in the class. Such attribute are added to the instance data. It can be used for internal variables but also as interface to the outside. We will use both in the examples here. Lets start with the ftrig and rtrig functions first. They do not depend on time and are therefor a bit simpler to model.

Before looking into the state machines take a look in the class diagram first.

 Class diagram of the function block library

Each function is modelled as class. The classes have more or less additional attributes. All have binary signals such as q (output) and set. Others have also the additional binary signals pause and reset or variables defining the delay times. Then also internal data is modelled e.g. to store the elapsed time.

To model attributes it is recommend to define your own data types using the 'primate data type' feature of UML. This allows to ensure the use of a consistent set of data types with the rest of your code not modelled in UML. The following figure shows the model tree with the classes and data type definitions inside a common package. Model tree with classes and data type definitions

RTRIG and FTRIG Function

The following two state diagrams show the models for the falling edge (ftrig) and the rising edge (rtrig) function. There is no time information needed. Only the status of the previous input signal. Conditional triggers are marked with a hash # as first character. rising edge state machine falling edge state machine

Pulse Function

The single pulse function is shaping the length of an input signal to a defined pulse length at the output. It requires a notion of time. The implementation just uses the system tick to get time information and calculating the elapsed time with each call of the state machine.

Pulse former state machine

On/Off Delay with Pause and Reset Inputs

This function block is the most complex one. It requires several internal variables to store temporary information and two independent time settings. The reset and pause inputs make the function even more flexible.

 On/off delay state machine

Generating Code

To generate code from the state machine model the following command lines were used (the class path -cp points to the location of the codegen.jar file):

java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:on_off" -o ton_toff signalprocessing.xmi
java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:ftrig" -o ftrig signalprocessing.xmi
java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:rtrig" -o rtrig signalprocessing.xmi
java -cp "../../../*" codegen.Main -p ea -t "Model:signal_processing:package:single_pulse" -o single_pulse signalprocessing.xmi
clang -l ncurses ton_toff.c main_on_off.c -o ton_toff
clang -l ncurses main_rtrig.c rtrig.c -o rtrig 
clang -l ncurses main_ftrig.c ftrig.c -o ftrig
clang -l ncurses main_single_pulse.c single_pulse.c -o single_pulse

The only two additional functions that must be provided are the ones delivering the elapsed time information.

uint32_t getSystemMilli(){
    struct timeval now;
    gettimeofday(&now, NULL);
    return now.tv_usec/1000 + now.tv_sec*1000;
}
 
uint32_t getDiffMilli(uint32_t old_milli){
    uint32_t milli = getSystemMilli();
    uint32_t diff =  milli - old_milli;
    //printf("Milli=%d, old_milli=%d Diff=%d", milli, old_milli, diff);
    return diff;
}

That's all. All the rest is generated!

Testing the Implementation

To test the implementations test patters were generated with which the state machines were called. The inputs and outputs of relevant signals were displayed via the curses library over time. Some examples:

ton with pause  tond=500, toffd=0
  Set:___***************_______________
Reset:_________________________________
Pause:_____****________________________
    Q:____________******_______________
 
 
ton/toff  tond=300, toffd=800
  Set:__*******___________***__________
Reset:_____________________*___________
Pause:_________________________________
    Q:_____************________________
 
rtrig testcase 2
Set:___****__*___
  Q:___*_____*___
 
ftrig testcase 1
Set:___****_*__*_
  Q:_______*_*__*
 
 
single pulse false at begin
Set:___*************______*__________
  Q:___***________________***________
 
Debounce button test
 Input__*__*_**__****************_*_**_*_*___*____*__________
 Out  _____________*************************_________________
 Cnt  0011120120012345678999999997867867564201111120000000000

Final Thoughts

State machines with conditional transitions are a powerful way to model signal forming functions. The shown approach makes reuse more easily possible within the same or further projects. In addition it has the general benefit that the model is the documentation and both is always 100% in sync with the implementation. Alone this benefit should motivate you to not write your next state based design by hand but use a modelling tool and generate the code.

If you are interested in the complete code just send me a mail. The model files are available here:

EA: Enterprise Architect Model file (created with version 16)

UModel: UModel Model file

Built in Editor: Model files for the built-in state diagram editor

Looking forward to receive your thoughts and ideas for other useful blocks.

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
wiki/examples/function_blocks_desing.txt · Last modified: 2022/08/17 17:44 by pmueller

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki