Allocated variables

Topics:

  1. Do not use direct addressing [++]
  2. Avoid multiple write accesses to outputs [++]
  3. Avoid overlapping memory areas of address variables [+]

Do not use direct addressing

Direct addressing should not be used for allocated variables. Instead of direct addressing, the use of automatic addressing using the * placeholder is recommended. If the placeholders * (%I*, %Q* or %M*) are used, TwinCAT automatically performs flexible and optimized addressing.

There should also be no direct address accesses in the implementation part.

Static Analysis:

Verify using the following Static Analysis rules:

Thematically recommended Static Analysis rule:

Negative sample:

VAR
    bInputSignal  AT%IX4.0 : BOOL;
    bVar                   : BOOL;
END_VAR
bVar := %IX0.0;

Positive sample:

VAR
    bInputSignal  AT%I*    : BOOL;
END_VAR

Avoid multiple write accesses to outputs

Multiple write access to outputs should be avoided. Multiple write access to outputs occurs if outputs are written at more than one point in the program.

Exception to this rule: assignments in different branches of an IF or CASE statement.

Static Analysis:

Check with the help of Static Analysis rule:

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

Negative sample:

PROGRAM Sample_neg
VAR
    bErrorLed      AT%Q*  : BOOL;             // Machine's error LED
    bErrorDrill           : BOOL;             // Drill error status
    bErrorTransport       : BOOL;             // Transport error status
    nTestCounter          : WORD;             // Simple counter
END_VAR
--------------------------------------------------------------------
bErrorLed := bErrorDrill OR bErrorTransport;  // NON COMPLIANT: bErrorLed will be written more than once: See action CounterInc
CounterInc();
--------------------------------------------------------------------
--------------------------------------------------------------------
(* --- Method: CounterInc ---
   This method increments the counter and checks if nCounterValue is equal to 0 *)
bErrorLed   := (nTestCounter = 0);            // NON COMPLIANT: bErrorLed will be written more than once: See program MAIN
nTestCounter := nTestCounter + 1; 

Positive sample:

PROGRAM Sample_pos
VAR
    bErrorLed      AT%Q* : BOOL;     // Machine's error LED
    bErrorDrill          : BOOL;     // Drill error status
    bErrorTransport      : BOOL;     // Transport error status
    bErrorCounter        : BOOL;     // Test counter error status
    nTestCounter         : WORD;     // Simple counter
END_VAR
--------------------------------------------------------------------
CounterInc();
    bErrorLed := bErrorDrill         // COMPLIANT
    OR bErrorTransport  
    OR bErrorCounter;
--------------------------------------------------------------------
--------------------------------------------------------------------
(* --- Method: CounterInc ---
This method increments the counter and checks if nCounterValue is equal to 0 *)
bErrorCounter  := (nTestCounter = 0); // COMPLIANT
nTestCounter   := nTestCounter + 1;

Avoid overlapping memory areas of address variables

Overlapping memory areas of address variables should be avoided. Overlapping memory areas occur if the same storage space is used by several variables.

If an overlapping memory area is required for programming reasons, UNIONs can be used for stylistic purposes. Overlapping memory areas in other variables, e.g. address variables, should be avoided.

Static Analysis:

Check with the help of Static Analysis rule:

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

Negative sample:

PROGRAM Sample_neg
VAR
    nTestWord       AT%MW2  : WORD;  // Test WORD
    nTestLowByte    AT%MB4  : BYTE;  // NON COMPLIANT: overlaps with nTestWord
    nTestHighByte   AT%MB5  : BYTE;  // NON COMPLIANT: overlaps with nTestWord
END_VAR
--------------------------------------------------------------------
nTestLowByte   := 0;                 // NON COMPLIANT: writes nTestWord = 16#xx00
nTestHighByte  := 0;                 // NON COMPLIANT: writes nTestWord = 16#00xx
nTestWord      := 16#C0FF;           // Writes nTestLowByte and nTestHighByte too

Positive sample:

// Structure for the positive sample
TYPE ST_2_BYTES :
STRUCT
    nLow        : BYTE;        // Low byte
    nHigh       : BYTE;        // High byte
END_STRUCT
END_TYPE
// Union for the positive sample
TYPE U_BYTE_WORD :
UNION
    stLowHigh   : ST_2_BYTES;  // Struct with two bytes
    nValue      : WORD;        // Test WORD to be united with the two-byte-struct
END_UNION
END_TYPE
PROGRAM Sample_pos
VAR
    uTestWordToBytes   AT%MW2  : U_BYTE_WORD;                // Test union
    nTestLowByte               : BYTE;                       // COMPLIANT: not addressed
    nTestHighByte              : BYTE;                       // COMPLIANT: not addressed
END_VAR
--------------------------------------------------------------------
uTestWordToBytes.nValue := 16#C0FF;                          // A test value 
nTestLowByte            := uTestWordToBytes.stLowHigh.nLow;  // Will be 16#FF
nTestHighByte           := uTestWordToBytes.stLowHigh.nHigh; // Will be 16#C0

 

See also: