Use of function blocks

Topics:

  1. Do not declare function block instances as VAR PERSISTENT [++]
  2. Evaluate returned error information of a POU [++]
  3. Do not access local variables of a POU from outside [++]
  4. No direct assignment of objects [++]
  5. No temporary function block instances [+]

Do not declare function block instances as VAR PERSISTENT

Do not declare function block instances as VAR PERSISTENT since this would cause the entire FB instance to be stored in the file of persistent variables. This could cause problems in function blocks that use ADS blocks or pointer variables internally, for example.

Evaluate returned error information of a POU

If a function, a method or a function block returns error information, always evaluate it.

Static Analysis:

Thematically recommended Static Analysis rules:

Negative sample:

PROGRAM Sample_neg 
VAR
    fbFileOpen    : FB_FileOpen;      // FileOpen-FB for logger
    bFileOpenExec : BOOL;             // Execute FileOpen-FB
END_VAR
// NON COMPLIANT: error information of fbFileOpen will not be used
fbFileOpen(
    sPathName := 'C:\TestFile.txt',
    nMode     := FOPEN_MODEWRITE OR FOPEN_MODETEXT,
    ePath     := PATH_GENERIC,
    bExecute  := bFileOpenExec,
    tTimeout  := T#3S);

Positive sample:

PROGRAM Sample_pos 
VAR
    fbFileOpen        : FB_FileOpen;  // FileOpen-FB for logger
    bFileOpenExec     : BOOL;         // Execute FileOpen-FB
    bFileOpenError    : BOOL;         // Error flag of FileOpen-FB
    nFileOpenErrorID  : UDINT;        // Error code of FileOpen-FB
END_VAR
// COMPLIANT: error information will be handled
fbFileOpen(
    sPathName := 'C:\TestFile.txt',
    nMode     := FOPEN_MODEWRITE OR FOPEN_MODETEXT,
    ePath     := PATH_GENERIC,
    bExecute  := bFileOpenExec,
    tTimeout  := T#3S,
    bError    => bFileOpenError,
    nErrId    => nFileOpenErrorID);
 
IF bFileOpenError THEN
    F_DoSomethingUsefulHere();        // Handle error here
END_IF

Do not access local variables of a POU from outside

Local variables of a POU should not be accessed from outside the POU.

In TwinCAT 3, write access to local variables from outside the programming object is not possible, as this would result in a compiler error. Read access, on the other hand, is not intercepted by the compiler.

In order to maintain the intended data encapsulation, it is strongly recommended not to access local variables of a POU from outside the POU – neither in read mode nor in write mode. Furthermore, with library function blocks it cannot be guaranteed that the local variables of a function block will remain unchanged during subsequent updates of the PLC library. This means that it is possible that the application project can no longer be compiled correctly after the library update.

Static Analysis:

Check with the help of Static Analysis rule:

Negative sample:

FUNCTION_BLOCK FB_Sample
VAR
    nLocal          : INT;
END_VAR
PROGRAM MAIN
VAR
    fbSample        : FB_Sample;
    nToBeProcessed  : INT;
END_VAR
--------------------------------------------------------------------
nToBeProcessed := fbSample.nLocal;  // NON COMPLIANT: Do not access local variables from external context.

Positive sample:

FUNCTION_BLOCK FB_Sample
VAR_OUTPUT
    nOutput         : INT;
END_VAR
VAR
    nLocal          : INT;
END_VAR
PROGRAM MAIN
VAR
    fbSample        : FB_Sample;
    nToBeProcessed  : INT;
END_VAR
--------------------------------------------------------------------
nToBeProcessed := fbSample.nOutput;  // COMPLIANT: Output variable is accessed from external context.

No direct assignment of objects

Simple data types (INT, BYTE, STRING, ...) or even structures are often assigned directly.

You should not assign instances of function blocks using allocation operator ':='. When such an assignment is made, a copy of the object is made. However, function blocks often contain addresses internally, which would be corrupted if they were assigned.

To prohibit such an assignment in principle, you can set the attribute 'no_assign' in the definition of a function block.

Static Analysis:

Check with the help of Static Analysis rule:

No temporary function block instances

You should not declare function block instances on the stack, i.e. not as temporary variables. Temporary instances are those that are declared in a method or a function or as VAR_TEMP, and are therefore reinitialized in each processing cycle or with each block call.

Function blocks have a state that is usually retained over several PLC cycles. An instance on the stack exists only for the duration of the function call. It is therefore only rarely useful to create an instance as a temporary variable. Secondly, function block instances are frequently large and require a great deal of space on the stack, which is usually limited on controllers. Thirdly, the initialization and often also the scheduling of the function block can take up quite a lot of time.

Static Analysis:

Check with the help of Static Analysis rule:

The rule SA0167 is also included in the license-free variant Static Analysis Light.

Negative sample:

FUNCTION F_Sample
VAR
    fbCtrl : FB_Control;
END_VAR

Positive sample:

FUNCTION F_Sample
VAR_INPUT
    fbCtrl : REFERENCE TO FB_Control;
END_VAR

 

See also: