What GMP Adds to Normal Coding Practice
IEC 61131-3 is a manufacturing standard — it defines syntax, semantics, and programming models for PLC languages, but says nothing about pharmaceutical compliance. GAMP 5 is a validation framework — it defines what evidence you need to demonstrate a system is fit for its intended use, but doesn't specify how you write a function block. GMP-compliant PLC code sits at the intersection: it must satisfy the programming discipline that IEC 61131-3 enables and the evidential requirements that GAMP 5 demands.
In practice, GMP adds four requirements on top of normal good coding practice:
- Traceability — every function block and every piece of logic must be linkable back to a requirement in the FDS. Code that cannot be traced to a requirement is either scope creep or a gap in the FDS, and either is a finding.
- Reviewability — the code must be structured and commented such that a reviewer who did not write it can verify, rung by rung or block by block, that it implements the FDS correctly. Terse, uncommented code fails the review regardless of whether it works.
- Testability — every GxP-critical function must be individually testable, which means isolatable. Logic that is deeply entangled — where a single rung affects three different process outcomes — cannot be cleanly tested against a specific acceptance criterion.
- Change safety — the code must be structured such that a future change through change control can be made with bounded, predictable impact. Spaghetti logic where changing one thing has unpredictable effects elsewhere is a long-term validation liability.
Language Selection — The GMP Perspective
IEC 61131-3 defines five languages: Ladder Diagram (LD), Function Block Diagram (FBD), Structured Text (ST), Instruction List (IL — deprecated in the 3rd edition), and Sequential Function Chart (SFC). On most modern platforms — TIA Portal, Studio 5000, Codesys — you can mix languages within a project, using each for the type of logic it is best suited to. That is also the GMP-preferred approach, because it aligns each language with its reviewability advantage.
Ladder Diagram remains the most QA-familiar language — it maps visually to relay logic that electrical engineers and validation specialists recognise. For this reason, interlock logic is often best written in LD even on projects where the rest of the code uses ST, because the code review will include QA reviewers who are not ST-literate. A QA reviewer can follow a rung that says "pump runs AND level is above 20% AND no fault active, therefore start permissive is true." They may not be able to follow the same logic written as nested conditions in Structured Text.
Structured Text has the significant advantage for pharma of being text-based, which means it can be tracked in Git and diffed between versions — you can see exactly which lines of logic changed between v2.1 and v3.0. For audit trail function blocks, string handling, and complex calculation logic, ST is the right choice. It is also more concise than LD for complex conditional expressions, which reduces the visual noise that obscures logic during review.
Sequential Function Chart is the natural language for batch sequences and CIP/SIP phases because the states and transitions are visually explicit. An OQ tester can follow the sequence on screen as it executes and verify that the actual state transitions match the FDS description. For any process that has defined phases — fill, heat, hold, cool, drain — SFC makes both the design and the testing significantly cleaner than the equivalent LD implementation.
Function Block Headers — The Code Review Anchor
Every Function Block in a GMP PLC project must have a header comment that makes it self-documenting. The header is not optional and is not a nice-to-have — it is what the code reviewer reads first to understand what the block is supposed to do before verifying that it actually does it. Without a header, the reviewer must infer intent from the code itself, which is slower and more error-prone.
The minimum required header content for a pharma FB:
The FDS and URS references in the header are what allow the code reviewer to locate the design intent without searching. When the reviewer is checking that FB_PID_GxP correctly implements FDS Section 3.1, they need both the code and the FDS open — the header reference makes that navigation automatic. The revision history in the header must also match the version control tags: if CCR-007 is in the header, v1.1_CCR-007 must exist in the version archive.
Inline Comments — What Must Be Explained
Not every line of code needs a comment. Commenting b_PumpRun := TRUE; with "set pump run to true" adds noise without adding clarity. The standard for inline comments in a GMP context is: comment every non-obvious logic decision, every interlock condition, and every GxP-critical state transition.
The interlock comment referencing IL_004 and CP-SYS-001 is not decoration — it is what allows the code reviewer to cross-reference the implemented logic against the interlock register. If the comment says IL_004 but the interlock register in the SDS appendix doesn't contain IL_004, that is a gap found during review. The comment creates the traceability link that makes the finding possible.
GMP-Prohibited Coding Patterns
Several common PLC coding patterns that work fine in industrial automation are explicitly problematic in pharma. Understanding why helps avoid them systematically rather than just memorising a list of rules.
Set/Reset Latches on Critical Process States
An SR latch that holds a "batch complete" or "sterilisation done" state is untestable in isolation. To verify the state is correct, you must trace every Set instruction that could have asserted it and every Reset instruction that could have cleared it — across potentially multiple function blocks and OBs. More critically, a latch can retain a state across a CPU restart if the data block is retentive, which means a retained "batch complete" flag from a previous run could affect the next batch in ways that are difficult to detect. Use explicit state machines with defined entry and exit conditions instead.
Hardcoded Process Values
A temperature setpoint, alarm limit, or timer value hardcoded directly into a rung rather than referenced from a configurable data block cannot be changed through change control without a code change. On a validated system, that means a change control every time an operational parameter needs adjustment — even if the change is within the validated operating range. Configurable parameters must be in data blocks with appropriate access control. The URS acceptance criterion for that parameter should define the configurable range, and the OQ should verify that changes within the range are handled correctly and logged.
Multiple Write Points for the Same Physical Output
If a physical output — a valve command, a heater enable, a pump start — can be driven from multiple locations in the programme (from OB1, from OB35, from a safety interlock, and from a manual override), then there is no single authoritative source for that output state. Testing the output in an OQ test case verifies which write "won" at that moment, not that the system behaves consistently. Every physical output must have exactly one assignment instruction, in exactly one location, driven by virtual memory bits that aggregate all the conditions. All other logic writes to virtual bits. OB1 maps virtual bits to physical I/O at the end of each scan.
Commented-Out Production Code
Code that has been commented out and left in the programme creates confusion during code review — the reviewer cannot tell whether the commented section represents an intentional design decision, an abandoned approach, or a mistake. On a validated system, commented-out code that was once active is a change that should have gone through change control. Remove it, commit the removal as a tagged version referencing the relevant CCR, and the question is closed. Left in, it is a perpetual source of review questions.
These four patterns — SR latches on critical states, hardcoded process values, multiple write points, commented-out code — appear on virtually every code review checklist for pharma PLC projects. They are not obscure requirements. If your code contains any of them, expect code review findings. Fixing them before the code review saves time; fixing them during the review creates additional documentation overhead and may require re-verification of the affected test cases.
Writing for Testability — Acceptance Criteria to Code
The risk assessment determines which functions need to be tested and at what depth. High-risk functions need to be tested against specific, measurable acceptance criteria. The code structure determines whether those test cases can actually be executed cleanly.
A test case for a temperature interlock might say: "Apply a simulated temperature value of 91°C to TT_R01_101. Verify that alarm HH_TT_101 activates within 1 second, the heater output HT_R01_001 de-energises immediately, and the audit trail records the alarm event with timestamp and process value." For that test to be executable, the code must:
- Have the simulation bit on TT_R01_101's UDT that allows a simulated value to be injected without live process input
- Have the alarm evaluation running in a fixed-interval OB so the 1-second response time is deterministic and testable
- Have a single write point for HT_R01_001 so that de-energisation is unambiguous
- Have FB_AuditTrail called in the alarm evaluation logic so the audit trail entry is generated at the point of alarm activation, not asynchronously
If any of those structural elements are missing, the test case cannot be executed as written. The choice is to rewrite the test case (weakening the validation evidence) or fix the code (which may require re-review if caught late). Structuring the project correctly from the start is what prevents that choice from arising.
The SDS template includes a Coding Standards appendix that documents all the standards described in this article as a controlled, project-specific reference. The code review checklist references each standard by appendix item, so the review is structured around the standards rather than relying on the reviewer's memory. The FAT and OQ protocol templates pre-include test cases for the GxP-critical code patterns — simulation bit injection, audit trail verification, setpoint change logging — so the testability requirements are built into the protocol structure from the start.