An S5-to-S7 program migration on a Siemens S7-314 CPU surfaced a class of fault that the original Siemens conversion utility could not flag automatically: the standard library replacements FC82, FC83 and FC84 silently consumed scratchpad flag words in the M area, overwriting unrelated bits that the application program had been using since the machine was first commissioned on an S5 115U. The fault chain ended at a Wohale (Anka) text display that refused to acknowledge commands, and at a counter C4 that would not increment because its trigger flag M237.2 was being clobbered every OB1 scan. This article captures the symptom tree, the underlying memory-model differences, and the field-proven relocation sequence used to recover the program.
Symptom Tree
Three separate, apparently unrelated, faults appeared simultaneously after the converted program was downloaded to the S7-314:
- Counter C4 would not increment. Manual increment in the VAT showed the count advancing, but in real time it froze at the loaded value.
- The Wohale (Anka) text display returned no acknowledgement to operator keystrokes. Display variables stayed at zero.
- Program number selection on the text display did not update, even after pressing the program-change keys.
- The mode-selection state machine in FB100 returned wrong mode IDs to FC82, so Auto / Manual / Diagnostic transitions intermittently failed.
All four symptoms had the same root: scratchpad flag words in MW236 through MW254 were being overwritten by blocks the operator had no reason to suspect.
Root Cause: FC82, FC83 and FC84 Internals
FC82 in the converted S7 project is the manual replacement written to mimic the S5 standard function block FB241. FC83 corresponds to FB242, FC84 to FB243. These S5 blocks were part of the original Siemens PG2000 / COM standard function set and were widely used as floating-point, code-conversion and BCD-arithmetic helpers in OCME and similar packaging machinery of that era. To preserve call compatibility, the S7 re-implementations of FB241/242/243 used local M-area scratchpad addresses inside the converted blocks themselves, in exactly the same way the original S5 code did - the S5 standard library had been doing the same thing for years.
The migration tool copied the call sites of FB241/242/243 in the original S5 program and re-targeted them to FC82/83/84. Because the original S5 programmer at OCME had also happened to map unrelated application flags into the same numeric range, every call to FC82/83/84 was effectively stomping on live data. The conversion was mechanically correct; the allocation was not.
The S5 Scratchpad Range F200.0 - F255.7
In S5, the marker range F200.0 through F255.7 was reserved by Siemens as a scratchpad area for FB200-FB255. These FBs were the standard library blocks distributed on the S5 PG software. Siemens explicitly documented that flag words in this range could be modified by any FB in the F200-FB255 set during their execution. The convention was: any flag at zero in this range was fair game for temporary use by the standard library. Application code was expected to live outside F200-FW255.
On S7, there is no formal scratchpad range in the same way - the marker area is just MB0-MB2047 on a 314IFM, for example - so the conversion tool has no obvious place to relocate the scratchpad usage of FC82/83/84. The re-implementations therefore continue to use the same M-byte addresses the S5 library used, and the conflict re-emerges. The official Siemens Industry Online Support entry for the Step 5 standard library documents the F200-F255 convention and is the reference for any engineer auditing a legacy allocation; see the Siemens Industry Online Support portal for the relevant S5 manuals.
Why a Mechanical Translation Behaves Differently on S7-314
On an S5 115U, the F200-F255 scratch range is small and the standard library blocks were the only consumers. Application code that stayed out of FW200-FW255 worked. In the S5 program in question, the original programmer had nonetheless used bits inside MW236-MW254 for live application data, including M237.2 (counter C4 increment), M252.0/M252.1 and the whole of MB253 (Wohale display handshaking). On the S5 these worked because, by accident of timing and scan order, the S5 standard FB241/242/243 either did not actually use those addresses, or used them in a way that did not collide with the application's read/write pattern. Or - more likely - the original S5 programmer did not actually use those addresses, and a later maintenance engineer applied the rule "zero means free" and assigned them in ignorance of the standard library's footprint.
On the S7-314, the re-implemented FC82/83/84 use exactly the same M-byte addresses, and the S7's stricter memory model plus the absence of S5-era scan-order slack made the collision immediate and persistent. Every OB1 pass, FC82 cleared or wrote the affected bits, regardless of what the application had just set. See the S7-300 CPU 31x manual on the Siemens S7-300 documentation page for the marker-area size and OB1 execution model that make this collision deterministic on the S7.
Mapping the Conflict
The marker addresses actively consumed by FC82/83/84 in the migrated project are listed below. Any application flag in these ranges must be considered hostile territory:
| S7 Address | Used By | Conflict In This Project |
|---|---|---|
| MW236 (MB236 / MB237) | FC82 | M237.2 triggers counter C4 increment |
| MW238 - MW242 | FC82 scratch | Mode-decision interlock bits |
| MW244 - MW250 | FC82 / FC83 | Application scratch and interlock flags |
| MW252 - MW254 | FC83, FC84 | M252.0, M252.1 and MB253 used by Wohale display driver |
| MW240 - MW242 | FC82 internal scratch | Application use relocated |
Additionally, indirect M-area writes observed in FB104 confirmed at least one runtime path that wrote M228.0 from a pointer resolved out of DB10.DBW300. Any marker address can therefore become a victim if the application itself is also using indirect addressing into the M area.
How to Find a Hidden Indirect Overwrite
The trap-code technique is the fastest way to identify which block is actually clobbering a suspect address. The pattern is to insert a small diagnostic block at the end of every candidate FC/FB that:
- Captures the current value of AR1 and AR2 (the S7 address registers) before and after the call.
- Compares the captured pointer against the suspect address.
- If AR1 or AR2 equals P#237.2 (the byte.bit address of M237.2 in the M area), stops the CPU with a diagnostic message.
The implementation in STL for the M237.2 case looks like this:
// Network 1 - Trap code, inspect AR1 for M237.2 hit
L P#237.2 // Load constant pointer P#237.2
LAR1 #ar1_save // Shadow AR1
TAR1 #ar1_now // Read current AR1
L #ar1_now
L P#237.2 // Compare against the suspect address
==D // Equal? Then we have a hit
JC TRIP
BEA // No hit, exit normally
TRIP: S M 999.0 // Set diagnostic latch
SET // Stop the CPU
SAVE
The same pattern in SCL or in a small FB wrapper works for an HMI-attached trace. Use M999.0 as the diagnostic latch because the 999 range is conventionally free in S7 projects and is easy to find in cross-reference.
Step-by-Step Resolution
The resolution sequence used on the machine:
- Confirm the collision. Force M237.2 in the S7 VAT and watch it survive the next OB1 scan. If it clears, FC82 is the culprit. Force M252.0 - if it clears, FC83 or FC84 is the culprit.
- Catalogue all marker bytes used by FC82/83/84. Open the FC82/83/84 source in Step 7 and search for every M-address. Build a table of every byte touched. In the affected project, the range was MW236-MW254.
- Identify application flags in that range. Cross-reference M237.2, M252.0, M252.1 and the entire MB253 across all application FBs. List every use.
- Allocate a fresh marker range for application use. Pick a range that FC82/83/84 does not touch. In the affected project, MW260-MW290 was free. Reserve MW260-MW275 for relocated application flags.
- Rewire the application flags. Move M237.2 to M275.2, M252.0 to M276.0, M252.1 to M276.1, MB253 to MB277. Update every reference. Search-and-replace globally with care - confirm no FC/FB re-defines M275.x or M276.x.
- Rewire the Wohale display driver. The display handshaking bits in MB253 must be moved as a complete byte because the Wohale protocol uses bit-banged serial I/O on the byte level.
- Repoint the counter C4 trigger. Update the CU input of C4 in the application FB so it now references M275.2 (the new home of the increment trigger).
- Re-cross-reference FC82/83/84 scratch. Confirm the new application range (MW260-MW290) is clean against FC82/83/84 scratch usage.
- Download and cold-restart.
- Verify. See the next section.
Verification
After the rewire and a cold restart, run the following verification sequence:
- In the VAT, monitor M275.2 (the relocated C4 trigger). Toggle it from the VAT and confirm counter C4 increments exactly once per edge.
- Force a program number change at the HMI. Confirm the Wohale display updates the displayed program number within two scan cycles.
- Operate the machine in Manual, Auto and Diagnostic modes (these are the three states the calling FB100 dispatches to). The state machine depends on the FC82 conversion working correctly.
- Watch MB277 (the relocated Wohale handshake byte) in the VAT. It must toggle symmetrically with the HMI keystrokes - if it stays at zero, the display driver was not fully rewired.
- Run the trap code from the diagnostic section for at least one full production cycle. M999.0 must never latch.
- Trigger every one of the twelve FC83 and FC84 call sites in the dispatcher block and confirm no flag in MW260-MW290 changes.
Preventive S5-to-S7 Conversion Checklist
The following checklist prevents the same fault on future conversions:
- Before running the S5-to-S7 converter, dump every flag word used by the S5 program and mark anything inside FW200-FW255 as suspect.
- After conversion, open every FC that was generated from the standard library (FC81-FC255 are typical candidates) and search for every M-address it touches.
- Build a table: standard-library FC | scratch range. Any application flag in that scratch range must be moved before download.
- Audit every application DB for indirect M-area pointers (look for DBW variables that are later loaded into AR1/AR2). Cross-reference each pointer against the scratch table.
- Reserve a dedicated application marker range in MW260+ (or wherever the project allows) and document it in the conversion report.
- Add the trap-code block as a permanent diagnostic. It costs two networks of STL and zero scan time when inactive.
- After every future change to FC82/83/84 or any other standard-library replacement, re-run the audit. A re-implementation may have shifted the scratch footprint.
- Document the relocation in the S7 source comments so the next engineer does not "reclaim" the relocated bits as free.
Special Case: M237.2 in DB10.DBW432
An additional finding on this project: M237.2 also appeared declared in DB10 at offset DBW432. This is a strong indicator that an indirect path somewhere writes M237.2 from DB10. Confirm by searching the S5 source for any T FW237 or any DB-to-MW transfer whose target is FW237. The fix is the same - the application logic must use the relocated M275.2 - but the DB10 declaration should be updated in parallel so future engineers are not misled by the cross-reference view.
Special Case: M228.0 Indirect Write via DB10.DBW300
Forcing the call to FB104 in the affected project exposed an indirect write to M228.0 with the source pointer in DB10.DBW300. Indirect addressing into the M area is invisible to the static cross-reference view and is the single biggest reason conflicts of this kind persist undetected. After any M-area relocation, audit all DBs for word values that are loaded into AR1/AR2 and confirm the target byte does not overlap the FC82/83/84 scratch range. A two-step audit works well: (a) list every LAR1 / LAR2 in the application, (b) for each one, find the DBW that feeds it, (c) confirm the resulting M-address is not in the scratch range.
Call Sites: Where FC82/83/84 Are Invoked
In the affected project, FC82 is called from FB100 and FB105 (mode-decision blocks). FC83 and FC84 are each called twelve times from the same dispatcher, believed to be FB93 or FB99. Twelve call sites per block is enough that any relocation of the application flag range must be cross-checked across all twelve - missing one site reintroduces the same fault in a different operating mode. Build a call-site matrix:
| FC | Caller(s) | Call Sites | Scratch Range Confirmed |
|---|---|---|---|
| FC82 | FB100, FB105 | 2 | MW236 - MW242 |
| FC83 | FB93 / FB99 (dispatcher) | 12 | MW244 - MW250 |
| FC84 | FB93 / FB99 (dispatcher) | 12 | MW252 - MW254 |
Working STL Snippets
Two reusable STL snippets are useful on this class of fault. The first detects any indirect hit on a suspect marker byte:
// FC104 - end-of-block trap, generic version
L P#M_SUSPECT // Pointer to suspect M-byte
LAR1
TAR1 #ar1_save // Read current AR1
L #ar1_save
L P#M_SUSPECT // Compare against the suspect address
==D
JC FLAG
L 0
T #ar1_save
FLAG: SET
The second forces the trap to fire only on a specific flag-bit, here M237.2:
// Trap for M237.2 only
L P#237.2 // Pointer to M237.2
TAR1 #ar1_now // Read current AR1
L #ar1_now
L P#237.2 // Compare against the suspect address
==D
JC TRIP
BEA // Exit normally if no hit
TRIP: S M 999.0 // Set diagnostic latch
FAQ
What is the S5 scratchpad range and why does it bite S7 conversions?
The S5 standard library uses F200.0-F255.7 as temporary scratchpad memory. An S7 re-implementation of the same function block will use the same numeric M-byte range. Any application flag in that range is silently overwritten on every call. Move the application flag out of the scratch range before download, or relocate the scratch range inside FC82/83/84 to a documented application-owned range such as MW260+.
How do I detect an indirect M-area overwrite that is not visible in cross-reference?
Insert a trap block that compares the value of AR1 or AR2 at the suspect point against the byte-bit pointer of the flag you suspect is being clobbered. If equal, set a diagnostic latch such as M999.0 and stop the CPU. The trap costs two networks of STL and runs only when active, so it is safe to leave in production as a watchdog.
Why does the same converted program work on an S5 115U but fail on an S7-314?
On S5, scan-order slack and the F200-F255 convention gave the original programmer a quiet guarantee that the scratch range was not consumed by application code. On S7, the re-implemented FC uses the same M-byte addresses with no warning and no convention. The application flag that happened to work on S5 is stomped every scan on S7, deterministically, because the S7 OB1 execution model does not provide the same scan-order margin.
Can I change the scratch range used by FC82/83/84 instead of moving the application flags?
Yes - re-implement FC82/83/84 with a relocated scratch range in MW260+. This is the cleaner fix because it pushes the scratch into a documented application-owned range. Re-implementing is only safe if you have the source and have validated every code path; a pure search-and-replace inside FC82/83/84 without revalidation can introduce new arithmetic faults, especially in the BCD and code-conversion paths.
What is the correct counter trigger if M237.2 is moved to M275.2?
Update the CU input of C4 in the application FB to use M275.2 instead of M237.2. Confirm with cross-reference that no other block writes M275.2 - otherwise the counter will increment spuriously. Run the trap-code diagnostic for at least one full production cycle to confirm no block is still hitting the old or new address unexpectedly. If indirect pointers in DB10 pointed at M237.2 originally, update those pointers to point at the new byte 275 before download.