Remanent Variables - RETAIN, PERSISTENT

Remanent variables can retain their value throughout the usual program cycle. You can declare remanent variables as RETAIN variables or, even stricter, as persistent variables in the application. The requirement for full functionality is sufficient memory on the PLC (NVRam, USV). If there is no suitable memory range, the values of VAR RETAIN or VAR PERSISTENT variables will be lost in the event of a power failure!

Hint

  • CODESYS treats a VAR PERSISTENT declaration just like a VAR PERSISTENT RETAIN or VAR RETAIN PERSISTENT declaration.
  • When you open a CoDeSys V2.3 project, the declarations of retain variables remain in effect and unchanged. However, you must revise the declarations of persistent variables or create new ones. You must prepare a global variable list of its own for V3!
  • The AT declaration may not be used in combination with VAR RETAIN or VAR PERSISTENT!

RETAIN variables

You declare RETAIN variables by adding the keyword RETAIN behind the keyword for the type of variable (VAR, VAR_GLOBAL, etc.) in the declaration part of programming objects.

RETAIN variables retain their value after an uncontrolled termination (or online command Reset warm). On restarting the program the system continues to operate with the stored values. In this case, CODESYS reinitializes “normal” variables either with their explicitly predefined initialization values or with the default initialization value.

Variables declared as RETAIN are managed depending on the target system, but typically in their own memory range, which must be secured against power failure.

CODESYS reinitializes RETAIN variables for

  • the command Reset original
  • the command Reset cold (as opposed to persistent variables)
  • a repeated program download

Examples

In a POU:

VAR RETAIN
 iRem1 : INT;
END_VAR

In a GVL:

VAR_GLOBAL RETAIN
 gvarRem1 : INT;
END_VAR

The degree of the value retention of RETAIN variables is automatically contained in that of PERSISTENT variables.

One possible application is a piece counter in a manufacturing plant that should continue to count after a power failure.

Hint

  • If you declare a local variable as RETAIN in a program, then CODESYS saves exactly this variable in the retain range (like a global retain variable).
  • If you declare a local variable as RETAIN in a function block, then CODESYS saves the entire instance of this function block in the retain range (all data of the block), but only the declared RETAIN variable is treated as such.
  • If you declare a local variable in a function as RETAIN, this has no effect. CODESYS does not save the variable in the retain range. If you declare a local variable in a function as PERSISTENT, this similarly has no effect.

Persistent variables

Like the RETAIN variables, PERSISTENT variables retain their values in the case of a Reset cold, a repeated download of the application and a Reset warm (therefore VAR PERSISTENT always corresponds to a VAR PERSISTENT RETAIN or VAR RETAIN PERSISTENT declaration). Therefore CODESYS reinitializes PERSISTENT variables only in case of Reset origin.

One example application for persistent variables is an operating hour meter, which should continue to count after a power failure and also after a repeated download of the application.

Two possibilities to define persistent variables

  • Declaration with the persistence editor in a special global variable list of the object type Persistent variables, which belongs to an application (VAR_GLOBAL PERSISTENT). Only ONE list is permitted per application and CODESYS treats persistent variables that are declared as PERSISTENT from this list only. VAR PERSISTENT declarations that are present in other POUs are added to the list using the menu command Declarations ‣ Add all instance paths . Global PERSISTENT declarations in other modules are not permitted. For persistent variable lists, there must be sufficient memory on the PLC (as for retain variables) in order to guarantee that the values are kept during a power failure.
  • Definition in the Persistence Manager of the Application Composer. This takes place via a completely different mechanism to that for the declaration of the VAR PERSISTENT in the persistence editor and requires, for example, no special memory. Further information about this can be found in the chapters on the Persistence Manager of the Application Composer.

Note

In CODESYS V3.3.0.1 and later, a declaration with VAR_GLOBAL PERSISTENT has the same effect as a declaration with VAR_GLOBAL PERSISTENT RETAIN or VAR_GLOBAL RETAIN PERSISTENT.

Example

Persistent variable list:

VAR_GLOBAL PERSISTENT RETAIN
 iVarPers1 : DINT; (* 1. persistent+retain variable App1 *)
 bVarPers : BOOL;  (* 2. persistent+retain variable App1 *)
    // instance path of the persistent variables created
    PLC_PRG.PERS: INT;
END_VAR

Hint

  • You should avoid the use of the data type POINTER TO in persistent variable lists, since the address values can change in the case of repeated downloads of the application. CODESYS prints respective compiler warnings.
  • Each time the application is downloaded again, CODESYS compares the persistent variable list on the PLC and in the project. If there are inconsistencies (changes to declarations and positions in the list), then CODESYS requires you to reinitialize all persistent variables before the download. Inconsistency results from the renaming or deleting or some other change of existing persistent variable declarations.

Mechanism of persistence via VAR PERSISTENT

Persistent variables should be used when variables are required whose value are to be retained even after a download. Basically, you can modify an application completely. As long as the application has the same name as an application located on the controller and has the same list of persistent variables, then the values of the previous list are applied. In this context, “same” means that the variables in the list must be declared in the same order, they must have the same name, and they must have the same data type as the variables on the controller. This is checked by a CRC over the list of variables which is also saved on the controller.

The mechanism works well only when the variables themselves are not modified significantly. Changes in an existing persistent variable list can lead to re-initializations, i.e. to loss of persistence. If you anticipate frequent changes due to the area of application, such a list is not recommended in principle. This refers primarily to changing the name or data type of a variable that has already been declared (see below: “Change to an existing declaration”). Persistent variables are less robust against changes in data type than ordinary variables in an online change. The editor handles adding new declarations and deleting existing declarations in later CODESYS versions (> V3.5 SP1) as follows:

The editor for the persistent variable list orders the persistent variables as the variables are expected in the PLC. The technique is as follows: CODESYS saves a CRC and the length of the persistent variables on the PLC. At download, CODESYS loads these values and compares them with the current values. All variables up to the specified length are compared with the current variables in the project. If the variables are still identical, then they remain uninitialized; the new variables are initialized. The editor intervenes in the variable list, i.e. it replaces deleted variables in the memory by placeholder variables and moves recently inserted variables to the end of the list. Then the order in the editor no longer corresponds to the order in the memory. As a result you can apparently modify them as desired, but you create gaps. The consequence of these gaps is that the memory may no longer suffice for placeholder variables. Therefore, you should clean the gaps after a while (command Rearrange list and clean gaps). However, after clearing the gaps, the list will not match the list on the PLC and the persistent variables are initialized.

Recovering data with the recipe manager: To recover the data, save the data in a recipe with the recipe manager. This creates a new list for all variables of the persistent variable list in the recipe manager, and at the same time the current values are stored by the controller as a recipe. Then execute the command Reorder list and clear gaps and perform a download again. If you execute only the command Restore values from recipe, then the values saved in the recipe are restored.

Changing an existing declaration in the persistent variable list: if you change the name or data type of a variable, this is interpreted as a new declaration and causes a re-initialization of the variables at the next online change or download! It is a case of a change of a user-defined data type, for example: if a new variable is added in a structure, or if the type of a variable changes from INT to UINT in the depth of a used structure. Hence, complex user-defined data types are not suitable for the management in a persistent variable list, at least if it is anticipated that the definition of the user-defined data type will have to be continually changed.

Mapping to existing variables: Any variable in a function block, global variable list, or program can be marked as PERSISTENT RETAIN. For this variable to be truly persistent, it must be added to the list of persistent variables by means of the command Add all instance paths. Then a placeholder for the respective variable is inserted into the list of persistent variables. The persistence of the variable is guaranteed by the following mechanism:

  • The cyclic tasks in which the variable is accessed are determined.
  • At the end of the first cyclic task, the variable is copied to the persistent variables (in each cycle).
  • After restarting the controller, the value of the persistent variable is copied to the ordinary variable.

These persistent variables use twice as much memory: Both at the declaration occurrence as well as in the persistent variable area, and they must be copied in each cycle. This can be time consuming, especially when large structured values are involved. It is always preferable to declare persistent variables directly in the list of persistent variables.

Hint

If you mark a variable as PERSISTENT RETAIN in a function module, global variable list, or program, and transfer it to the list of persistent variables, then the memory consumption and the cycle time are loaded.

Memory location of function block instances

In addition to double memory usage, the following property of function blocks must be considered: Function block instances are always stored as one block of memory. This is necessary so that the same code can work on different instances. However, this means that if a variable in a function block is marked with RETAIN (also with RETAIN PERSISTENT), then every instance of the function block is stored entirely in the retain area. Also variables that are not marked with RETAIN and that are initialized during reset are stored physically in the memory for RETAIN variables. Usually, this is specially protected memory (SRAM), which is not available to the same extent as ordinary memory.

This property is even inherited via function blocks: If a function block contains an instance located in SRAM, then all instances of this function block must also be stored in SRAM. This means that by declaring a single VAR RETAIN PERSISTENT in a function block, you can use up all of your retain memory very quickly.

This is not the case if a function block contains a POINTER to an instance in SRAM. Therefore, you should always be careful when declaring RETAIN in function blocks.

Overview table for the behavior with RETAIN and PERSISTENT declared variables

after online command VAR VAR RETAIN

VAR RETAIN PERSISTENT

VAR PERSISTENT RETAIN

Reset warm   x x
Reset cold     x
Reset origin      
Download     x
Online Change x x x

See also