Resolving WAGO 750-841 RETAIN Struct Loss After Power Cycle

Daniel Price9 min read
HMI ProgrammingTroubleshootingWago
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

On this WAGO 750-841 controller, single RETAIN variables survived a power cycle and the RETAIN structs did not. The cause was the boot project. A manual Online → Create Boot Project fixed it, even though automatic boot-project creation was already enabled. CODESYS allowed the RETAIN declaration on the struct, so nothing looked wrong during development. The controller came back from power-up with whatever image and retain map its boot project described. Work through the checks below in order, because each one rules out a layer of the path.

Where does struct data travel between power-down and the first scan?

A retained value takes three steps. First, while the PLC runs, the runtime writes the variable into the retentive RAM segment defined by the target's memory layout. Second, on power-up the runtime loads the boot project stored on the controller, not the project open on your PC. Third, the runtime matches the boot project's retain map against the retentive segment and restores the values into the variables it describes.

If the boot project on the controller comes from an earlier build, its retain map describes the older variable layout. That older layout may be the one before you moved the struct into VAR_GLOBAL RETAIN. At power-up the runtime then initializes the struct to defaults and restores only the variables that the old map knew about. That explains how individual RETAIN words, with or without %MW addresses, can hold their values while the struct loses its data.

Hop What happens Where it breaks
Runtime → retentive RAM RETAIN variables written to the retain segment during RUN Retain segment too small in Target Settings → Memory Layout
Flash → runtime at power-up Boot project loaded Boot project stale or never created from Online mode
Retain segment → variables Values restored according to the boot project's retain map Map mismatch after a full download, or illegal AT placement inside a struct
Variables → Modbus TCP HMI and PC read and write the %MW area Connection load drops sessions (separate fault, covered below)

Is the controller running a boot project built from the current program?

Check this first, because it resolved the case here. The auto-create boot project option was enabled, yet the struct only held its values after a manual Online → Create Boot Project.

  1. Log in to the 750-841 with the current program and confirm that CODESYS reports the online and offline programs as identical.
  2. Run Online → Create Boot Project while still logged in.
  3. Write test values into the struct from a watch list. Power the controller off and back on.
  4. Reconnect. If CODESYS asks to download the program again, the controller did not boot the program you think it did. Repeat step 2 and check again.

If the struct now holds its values: go to the final procedure and verification section. If the struct still resets and single RETAIN variables survive: continue to the declaration check.

Which symptom pattern points to which cause?

Observation after power cycle Likely cause Next check
All RETAIN variables lost, structs included Boot project missing, or retain segment not configured Boot project, then Memory Layout
Single RETAIN words kept, struct fields reset Stale boot project whose retain map predates the struct declaration Manual Create Boot Project
CODESYS asks to download after reconnect No boot project, or boot project does not match the PC program Create the boot project from Online mode
Values kept through power cycles, lost after program transfer Full download reinitializes retain data Save values to the PC before downloading
Some array elements kept, later ones reset Retain segment smaller than the declared footprint, or an overlapping AT address Memory Layout size and address map
Values kept, but Modbus TCP drops intermittently Too many simultaneous TCP clients (PC IDE, HMI, Modbus monitor) Reduce concurrent connections

Is the struct declared in a form the retain map can restore?

The CODESYS help on structures states: "Interlocking structures are allowed. The only restriction is that variables may not be placed at addresses (the AT declaration is not allowed!)." This rule applies to the members of a structure. You cannot write AT %MW... on individual fields inside TYPE ... STRUCT. You can still place a whole instance of the struct, or an array of struct instances, in the RETAIN section, and you can give that instance an AT address.

The following pattern ran on a 750-841 and kept its data through power loss:


Check these points in your own declaration:

  • Define the struct as a data type (DUT). Then declare the instance inside VAR_GLOBAL RETAIN. A struct declared as a local variable of a POU is not retentive unless that POU's own variable block is RETAIN.
  • Leave every member without an AT clause.
  • If you give the instance an AT %MW address, calculate where it ends and keep every other AT variable outside that range. In the example, the array starts at %MW12 and ends near word 2250. The next addressed variables start at %MW2514, so there is no overlap. From those two numbers, each Scheda element takes roughly (2250 − 12) / 25 ≈ 89 words. Recalculate this for your own type.

If the declaration already matches this pattern and the struct still resets after a manual boot project: check the retain segment size.

Does the retain segment in Memory Layout cover the whole footprint?

Open Resources → Target Settings → Memory Layout and read the Retain area size. On the controller in this case the field read 16#4000, which is 16384 decimal and was taken as 16384 retentive words. CODESYS normally raises a warning when the RETAIN declarations exceed the segment.

Work out the footprint in the running program instead of estimating it:

VAR
    RetainBytes : UDINT;
END_VAR

RetainBytes := SIZEOF(ArchivioSchede);   (* bytes; divide by 2 for words *)

Add up the SIZEOF results for every RETAIN block. Compare the total with the Memory Layout value, using the same unit that the dialog uses. If the struct array alone fills the segment, the variables declared after it are the ones that get lost. Shrink the array or enlarge the segment within the limits the target allows. Then create the boot project again.

When should the struct be mirrored into %MW RETAIN arrays instead?

Use mirroring when you cannot change the struct's storage class. Examples are a struct buried in function block instances, or a program you do not want to restructure. The idea is to keep the working data in normal RAM and copy it every scan into a plain RETAIN array. On the first cycle after power-up, copy it back. Laid out flat, the struct data in this case came to 15 arrays of 16 elements, or 240 words. One contiguous RETAIN array holds that more simply than 15 separate ones.

Mirror loop (CODESYS 2.3 ST, word-aligned struct of WORD members):


Instead of the FirstScan flag, you can do the restore in a POU bound to the controller's start event in the task configuration. That POU runs once on the first cycle in RUN. Two cautions apply:

  • Mirroring only moves the problem. SaveArea is still a RETAIN variable, so it still depends on a valid boot project and enough retain space. If the direct struct declaration fails because of a stale boot project, the mirror fails in the same way.
  • If the HMI writes to %MW100..%MW339 over Modbus, the next scan overwrites that write with the RAM copy. Either have the HMI write to the working struct through its own addressed variables, or copy from SaveArea to the struct when a write-handshake flag is set.

Why do Modbus TCP sessions drop while CODESYS and the HMI share the retain area?

This is a separate fault from retain loss, but it shows up on the same installation. Here, an operator panel and a PC Modbus monitor both read and wrote the retain %MW area. The panel sometimes reported a Modbus TCP error, the monitor disconnected, and the CODESYS session was sometimes dropped as well. Occasionally the controller froze with all LEDs flashing red until power was removed. A second 750-841 running a touch panel showed the same Modbus errors only while the CODESYS IDE was also connected. With the panel alone it ran cleanly.

Trace the request path. Each client opens its own TCP session to the controller's Ethernet stack. The IDE's online session, the HMI polling, and the Modbus monitor compete for the same connection resources and CPU time as the PLC task. Isolate the load step by step:

  1. Disconnect the IDE and run the HMI alone for a representative period. Log how many Modbus errors occur.
  2. Add the Modbus monitor and log again. Then add the IDE.
  3. Look at the Ethernet and Modbus settings in the controller's web-based management pages, and lengthen the HMI poll interval if errors rise with each added client.
  4. If the controller freezes with red LEDs, read the LED blink code before you cycle power. The blink sequence identifies the fault class in the controller manual.

How do you prove the struct survives power loss and a program transfer?

A full program download reinitializes retained data, even on a correctly configured controller. Power cycles are safe; downloads are not, unless the values have been saved to the PC first. Before a download, read the struct values into a watch/recipe list. After the download, write them back. Then run this verification:

  1. Log in with the final program and run Online → Create Boot Project. Do not rely on the automatic option alone.
  2. Create a watch list with individual struct members, for example .ArchivioSchede[1].AnalogOutput and .ArchivioSchede[1].Temperatura1. Include one element near the end of the array, such as .ArchivioSchede[25].AnalogOutput, to confirm that the whole footprint is inside the retain segment.
  3. Write distinctive non-zero values into each watched member.
  4. Remove power from the 750-841, wait for the controller to shut down fully, and restore power.
  5. Reconnect. CODESYS must log in without asking to download the program. If it asks, the boot project does not match; go back to step 1.
  6. Read the watch list. Every member, including the last array element, must show the values written in step 3. Also read the same addresses from the HMI over Modbus to confirm that the retained data is present on the network side.

Frequently asked questions

How do I make a struct RETAIN on a WAGO 750-841 in CODESYS?

Define the struct as a DUT with no AT on any member. Declare an instance or an array of instances inside VAR_GLOBAL RETAIN, optionally with an address such as AT %MW12. Then run Online → Create Boot Project manually.

Why do single RETAIN variables survive but my struct resets on the WAGO 750-841?

The boot project on the controller is stale, and its retain map predates the struct declaration. Creating the boot project manually from Online mode fixed it here, even with automatic boot-project creation enabled.

How do I check the retain memory size on a WAGO 750-841?

Open Resources → Target Settings → Memory Layout and read the Retain area value; here it was 16#4000 (16384). Compare it with the total SIZEOF() of all RETAIN blocks, in the same unit.

How do I keep RETAIN data when downloading a new program to the WAGO controller?

A full download reinitializes retained values, so read them into a watch/recipe list on the PC first and write them back afterward. Power cycles alone do not clear correctly configured RETAIN data.

Back to blog