Siemens S7-300 Program Structure: OB, FB, FC, DB Reference
The Siemens SIMATIC S7-300 PLC uses a modular, block-based program architecture that differs fundamentally from the tag-based memory model used in Allen-Bradley ControlLogix or the file-based structure of legacy PLC-5/SLC 500. Engineers migrating from AB or Mitsubishi platforms must understand the S7-300 block hierarchy (OB, FB, FC, DB, SFB, SFC, SDB) before they can write maintainable code. This reference covers the canonical program model, the role of each block type, the instance DB mechanism that gives FBs their state, the differences between STEP 7 Classic and TIA Portal project files, and a field-tested migration path for AB-trained programmers.
S7-300 Program Execution Model
The S7-300 CPU executes a cyclical scan with three phases:
- Input image update – The CPU reads the physical inputs from the I/O modules and writes them to the Process Image of the Inputs (PII).
- User program execution – OB1 is called and runs the user code. Subordinate blocks (FCs, FBs) are invoked from OB1 or from other blocks.
- Output image write – The Process Image of the Outputs (PIQ) is written to the physical output modules.
Because the inputs and outputs are imaged to internal memory areas at fixed points in the scan, your logic operates on a consistent snapshot. Direct I/O access (read/write to the periphery with the P prefix, e.g. PIB 0, PQB 0) is possible but bypasses the process image and is generally reserved for time-critical applications or for diagnostic data on the input side.
Organization Blocks (OBs)
OBs are the entry points into the S7 user program. The CPU operating system calls OBs based on events, not from user code. Each OB has a fixed priority class and a defined trigger:
| OB Number | Name | Priority | Trigger |
|---|---|---|---|
| OB1 | Main cyclic program | 1 | Endless loop; called after every scan |
| OB10 | Time-of-day interrupt | 2 | Configurable calendar time (once, every minute, hourly, daily, weekly, monthly, yearly) |
| OB20 | Delay interrupt | 3 | Started by SFC32 to start a delay |
| OB35 | Cyclic interrupt | 12 | Fixed interval (default 100 ms, configurable 1 ms–60 s) |
| OB40 | Hardware interrupt | 16 | Rising or falling edge on a digital input or alarm from an analog module |
| OB80 | Time error | 26 | OB35 overrun, scan time exceeded |
| OB82 | Diagnostic interrupt | 26 | Diagnostic-capable I/O module reports fault or removal |
| OB85 | Program sequence error | 26 | Missing OB call, I/O access error on updated image |
| OB86 | Rack/station failure | 26 | PROFIBUS-DP slave or rack failure |
| OB100 | Warm restart | 27 | CPU RUN selector change, or STOP-to-RUN with retentive memory preserved |
| OB101 | Hot restart | 27 | S7-400 only; S7-300 uses OB100 |
| OB102 | Cold restart | 27 | Full memory reset on transition to RUN |
| OB121 | Programming error | Priority of the OB that caused the error | Illegal instruction, range violation, missing block |
| OB122 | I/O access error | Priority of the OB that caused the error | Read/write to a missing or faulty I/O module |
OB1 is the workhorse. Most user logic is called from OB1 directly or through a small ladder of FC calls. OB35 is the standard cyclic interrupt for time-based tasks such as PID control loops. OB100 replaces the first-scan flag used in AB; flags set in OB100 remain true for the first scan, so a one-shot pattern looks like this:
// OB100 - one-shot initialization
AN "First_Scan_Done"
S "System_Initialized"
S "First_Scan_Done"
The error OBs (OB80, OB82, OB85, OB86, OB121, OB122) are loaded by default to keep the CPU in RUN when a recoverable fault occurs. If they are not present in the project, the CPU goes to STOP on the first error. Always download all error OBs at project bring-up.
Functions (FCs)
An FC is a subroutine with no memory. It accepts IN, OUT, and IN_OUT parameters and returns TEMP variables. When the FC exits, all TEMP data is lost; the only state carried out of an FC is what the caller passes through the parameter interface. Because of this, FCs cannot hold retentive values across calls without external memory.
Common uses for FCs:
- Math, scaling, and conversion (e.g. raw analog to engineering units)
- Reusable algorithms that are stateless (e.g. moving average with input pointer)
- Driver blocks that read inputs, compute, and write outputs
- Modbus, USS, or other serial protocol handlers
Declare FC parameters in the variable declaration table (interface). Example FC interface for a scale block:
| Type | Name | Data Type | Comment |
|---|---|---|---|
| IN | Raw_Value | INT | 0–27648 for 4–20 mA / 0–10 V |
| IN | EU_Low | REAL | Engineering unit at 0 raw |
| IN | EU_High | REAL | Engineering unit at 27648 raw |
| OUT | EU_Value | REAL | Scaled result |
| OUT | Range_Error | BOOL | TRUE if input out of range |
| TEMP | Span | REAL | Internal scratch |
When you call an FC from LAD/FBD/ST, the parameter list appears in the call box. Wire each input from a global data block, a memory flag, or another block's output. FCs are reused by calling them multiple times from OB1 with different parameter sources; no instance DB is involved.
Function Blocks (FBs) and Instance DBs
An FB is a subroutine with memory. The static variables declared in the FB are stored in an associated DB called an instance DB. Every call to an FB must specify an instance DB, either a single-instance or a multi-instance. The instance DB is the FB's "memory card" – it persists between calls, retains values on CPU restart (subject to the retentivity setting), and gives the FB its state.
Static, Temporary, and Parameter Variables
The FB interface has three variable sections:
- VAR_INPUT – Inputs from the caller; not retained across calls
- VAR_OUTPUT – Outputs to the caller
- VAR_IN_OUT – Pass-by-reference parameters; changes inside the FB are visible to the caller
- VAR (static) – Internal memory that lives in the instance DB
- VAR_TEMP – Scratch memory; lost when the FB exits
- CONST – Named constants
The combination of static memory and a parameter interface is what makes FBs the S7 analog of an AB Add-On Instruction (AOI) with internal state. The block type is reentrant: the same FB code, called twice with two different instance DBs, behaves as two independent objects.
Single-Instance vs Multi-Instance
Single-instance: each FB call gets its own dedicated DB. You can call the same FB type with different DBs to instantiate multiple independent copies (e.g. ten motor starters of the same type). Single-instance is the easiest mental model for migration from AB AOIs.
Multi-instance: the FB is called from inside another FB. The outer FB owns the instance memory for the inner FB; no separate DB is created. Multi-instance keeps the data hierarchy in one DB and reduces DB count. Use it for a structured plant model where a "Line" FB contains "Motor" FBs.
Example: a motor FB with start/stop logic, run feedback, fault latch, and elapsed-time counter. Each call gets its own instance DB; the same code is reused for 30 motors by changing the instance DB number at the call site. Symbolic access (e.g. "Motor_DB_1".Run_Command) keeps the code readable as the plant grows.
Data Blocks (DBs)
DBs are pure data containers. There are two kinds:
- Instance DB – Created automatically when you generate an instance for an FB. Its layout is dictated by the FB declaration. You can read/write it symbolically using the FB's static variable names. STEP 7 / TIA Portal regenerates the instance DB when the FB interface changes (right-click the FB → "Instance DB" → "Update" in STEP 7 Classic, or accept the automatic update prompt in TIA Portal).
- Global DB (also called "shared DB") – A user-defined data container that any block can read or write. Use global DBs for plant-level variables, HMI tag databases, recipes, and process setpoints.
A global DB example for a tank level station:
| Address | Symbol | Type | Initial Value | Comment |
|---|---|---|---|---|
| DB10.DBX0.0 | Auto_Mode | BOOL | FALSE | Operator selected AUTO |
| DB10.DBX0.1 | Pump_1_Run | BOOL | FALSE | Pump 1 command |
| DB10.DBX0.2 | Pump_2_Run | BOOL | FALSE | Pump 2 command |
| DB10.DBD4 | Level_PV | REAL | 0.0 | Process value from analog in |
| DB10.DBD8 | Level_SP | REAL | 50.0 | Setpoint from HMI |
| DB10.DBW12 | Level_Pct | INT | 0 | 0–10000 = 0.00–100.00 % |
| DB10.DBD14 | Pump_1_RunHours | REAL | 0.0 | Total run hours |
DBs support both absolute addressing (DB10.DBX0.0) and symbolic addressing ("Tank_10_DB".Auto_Mode). Always use symbolic addressing in new code. Set the DB attribute Non-Retain or Retain for each variable to control which values survive STOP→RUN and power cycle. The S7-300 supports a configurable retentive range in the CPU properties (default: 16 merker bytes, 8 S7 timers, 8 S7 counters); everything else is non-retentive unless stored in a retentive DB.
User-Defined Types (UDTs) for Reusable Structures
UDTs are templates for data structures. A UDT can be used as the type of a global DB, a section of a global DB, or as the type of an FB static. Use a UDT whenever you have repeating data with the same layout:
// UDT 100 "Motor_UDT" structure
STRUCT
Run_Command : BOOL;
Run_Feedback : BOOL;
Fault : BOOL;
Fault_Reset : BOOL;
Speed_Setpoint: REAL;
Speed_Actual : REAL;
Run_Hours : REAL;
Starts_Total : DWORD;
END_STRUCT;
Declare "Motor_Array" : ARRAY[1..30] OF "Motor_UDT" in a global DB, and the same template is reused for 30 motors. HMIs can browse the array symbolically (WinCC, TIA Portal HMI tags).
Memory Areas and Symbolic Addressing
The S7-300 memory is split into regions. The most common operand areas:
| Area | Prefix | Size (CPU 315-2 PN/DP example) | Description |
|---|---|---|---|
| Process image inputs | I | 2 KB | Inputs updated each scan |
| Process image outputs | Q | 2 KB | Outputs written each scan |
| Periphery inputs | PI | 2 KB | Direct read of physical inputs (no image) |
| Periphery outputs | PQ | 2 KB | Direct write of physical outputs |
| Bit memory (merkers) | M | 4 KB | Internal flags; not retentive by default |
| Timers | T | 512 | IEC S5-style timers |
| Counters | C | 512 | IEC S5-style counters |
| Local data (stack) | L | 32 KB | TEMP variables per priority class |
| Data blocks | DB | depends on work memory | DB contents |
Standard ladder symbols in S7 correspond to:
-
I – digital input (e.g.
I 0.0,IB 0,IW 0,ID 0) -
Q – digital output (e.g.
Q 4.0,QB 4,QW 4,QD 4) -
M – internal bit (e.g.
M 10.0,MW 10,MD 10) - PIW / PQW – analog input/output via the periphery (used for modules outside the process image, such as fast analog or special function modules)
For S7-300 with STEP 7 Classic, the analog modules are typically configured in HW Config and assigned to the process image in the module properties. By default, analog I/O is not in the process image; the standard pattern is to use L PIW 256 and T PQW 256 with SFC26 / SFC27 for selective update, or to include the analog channels in the process image via Hardware Configuration. Many modern projects enable "Update of the process image for I/O points" in the CPU properties and then use IW 128 and QW 128 for analog.
STEP 7 Classic Project File Structure
A STEP 7 Classic project is a folder hierarchy. The root project folder is named after the project and contains a Global folder, a s7asrcom / s7hgmr folder, and the STEP 7 folder. The relevant items in STEP 7 are:
-
Project.s7p– the project file opened by SIMATIC Manager -
SIMATIC 300 Station– the hardware station object -
S7 Program– the program container with sources, blocks, and symbols -
Sources– STL source files and SCL source files (plain-text versions of the blocks) -
Blocks– the compiled S7 blocks (System Data, OB, FB, FC, DB, SFB, SFC, SDB, UDT, VAT) -
Symbols– the symbol table (Symbol Editor)
Compiled blocks are stored on disk in a compressed binary form. A "know-how protected" FB has its compiled code scrambled; the source remains in the Sources folder for maintenance. The complete S7 project layout is documented in the Siemens Working with STEP 7 manual available from the official Siemens Industry Online Support.
On the CPU side, blocks are stored in load memory (typically MMC on S7-300) and run from work memory. Each block has a maximum size (FB/FC ≤ 64 KB on S7-300/400; DB ≤ 64 KB). The S7-300 program size is limited by the work memory of the CPU (CPU 312: 16 KB, CPU 315-2: 256 KB, CPU 319-3: 1.4 MB).
For deeper reference on project layout, see the Siemens Working with STEP 7 manual (S7gs___b.pdf) and the S7-300 system data / module specifications under Siemens Industry Online Support.
System Blocks (SFB, SFC, SDB)
Beyond user blocks, the S7-300 ships with system functions and system function blocks:
- SFC – system functions in the CPU operating system (e.g. SFC0 SET_CLK to set the clock, SFC14/15 for DP standard slave comms, SFC20 BLKMOV for block move, SFC24/25/26/27 for test, SFC51 RDSYSST for diagnostic buffer read)
- SFB – system function blocks with instance DB in the system data (e.g. SFB0/SFB1 for OB1 input/output, SFB2/SFB3/SFB4 for instance DB scan, SFB47 counter, SFB48/49 frequency measurement)
- SDB – system data blocks containing the hardware configuration and the connection database (NetPro); generated by HW Config and NetPro, not user-edited
Calls to SFCs and SFBs go in the user program just like FC/FB calls, but you cannot edit their source. The full list of SFCs/SFBs depends on the CPU firmware; consult the S7-300 CPU manual for the exact set on a given CPU (e.g. CPU 315-2 PN/DP, 6ES7315-2EH14-0AB0).
Allen-Bradley to Siemens S7-300 Migration
An engineer trained on AB can be productive on S7-300 in a week by following a constrained subset of the language. Once the basics are stable, expand into the Siemens-specific features. The two rules of thumb:
- Use only Ladder, OB1, and FCs for the first project. Use DBs to store data; do not write FBs or instance DBs yet.
- Address the variables directly (symbolic optional). Once you are comfortable, switch to symbolic-only and add FBs.
AB-to-S7-300 mapping reference:
| Allen-Bradley | Siemens S7-300 | Notes |
|---|---|---|
| Program file (e.g. LADDER.ACD) | S7 Program / Blocks | SIMATIC Manager is the S7-300 equivalent of RSLogix |
| Main routine (Program:MainProgram) | OB1 | Cyclic, called every scan |
| Subroutine / JSR | FC call (in OB1) | No state inside FC |
| Add-On Instruction (AOI) | FB + instance DB | Persistent state in instance DB |
| Tag (BOOL, INT, REAL) | Symbol in symbol table, data in M area or global DB | Use global DB instead of M for > 100 tags |
| Input module (e.g. 1756-IB16IF) | SM321 digital input module | Wired to I area (e.g. I 0.0) |
| Output module (e.g. 1756-OB16E) | SM322 digital output module | Wired to Q area (e.g. Q 4.0) |
| Analog input (e.g. 1756-IF8H) | SM331 analog input module | Wired to PIW or IW if in process image |
| BTR / BTW / MSG (CIP MSG) | PUT / GET (SFB14/15) or BSEND / BRCV (FB12/13) over ISO-on-TCP | Connection configured in NetPro |
| Periodic task (1 ms – 1000 ms) | OB35 cyclic interrupt (1 ms – 60 s) | Configured in CPU properties |
| First Scan bit (S:FS) | Bit set in OB100 | No equivalent in OB1; use OB100 one-shot |
| Retentive tag (RETENTIVE) | Global DB with RETAIN attribute, or bit in retentive M area | Configure retentive M/T/C in CPU properties |
| BCD / HEX toggle | BTI, ITB, BTD, DTB, BCD_I, I_BCD | Native conversion instructions in STL |
The transition from direct addressing to symbolic addressing is the single biggest productivity gain. Once symbols are in place, the same HMI and operator screens built against the symbol table remain valid when the rung logic changes.
Best Practices and Anti-Patterns
Field-proven rules for the S7-300 program structure:
- OB1 stays thin. It calls FCs that contain the actual logic. A 5-net OB1 is normal; a 200-net OB1 is a code smell and a scan-time risk.
- One FB per physical or logical asset. A pump, a valve, a PID loop, a recipe step. The FB owns the static state (run command, feedback, fault, runtime, alarm mask).
- Use a global DB per area or per process unit. "Tank_10_DB" with all tags for tank 10. Avoid one megaglobal DB with 5,000 tags.
- Always load OB80, OB82, OB85, OB86, OB100, OB121, OB122. Empty error OBs are fine; missing OBs cause a STOP.
- Set retentivity explicitly. Use the Retain attribute on DB variables that must survive power cycle, and on the M area in the CPU properties. A non-retentive variable in a DB will reset to its initial value on STOP→RUN.
- Use UDTs for repeating structures. A "Motor_UDT" with 12 fields can be the type of 30 instance DBs, all readable symbolically.
- Do not write logic in OB35 that touches the same bits as OB1. Cyclic interrupts and the main scan are asynchronous; race conditions are easy to create. Use a mailbox in a global DB.
-
Stay symbolic. If you find yourself writing
DB101.DBX2.3in 2010, stop and add a symbol. -
Address the periphery with the right prefix. Process image access is
I/Q; direct periphery isPI/PQ. Mixing them up is a common bug source.
Anti-patterns to avoid:
- Using M area as a global variable pool beyond a few hundred bits. It will fragment maintenance and SCADA/HMI mapping.
- Writing more than 100 nets in OB1. It blocks the cyclic interrupt and inflates scan time.
- Re-using instance DB numbers manually. Let STEP 7 / TIA Portal assign them.
- Calling FBs with global data instead of VAR_IN_OUT. It works, but it locks the FB to a specific DB layout.
- Editing SDBs by hand. They are generated by HW Config and NetPro.
STEP 7 Classic vs TIA Portal Project Layout
STEP 7 Classic (V5.x) stores the project as a folder of files. TIA Portal (V13–V20) stores the project as a single SQLite database file (*.ap16 for V16, *.ap20 for V20, etc.). The block names and numbers are identical; only the on-disk format changes. An S7-300 project can be migrated from STEP 7 Classic to TIA Portal via the "Migrate project" menu in TIA Portal, with some limitations on unsupported SFCs/SDBs and the requirement to install the appropriate HSP (Hardware Support Package).
For S7-300 specifically, the TIA Portal toolchain adds:
- Integrated symbolic programming – symbols are stored with the program blocks
- Block type versioning and library support
- Online diff between the project and the CPU
- Graph view for sequential processes
- Cross-vendor library import (e.g. shared blocks across multiple S7-300/400/1500 CPUs)
For S7-300/400, STEP 7 Classic is still required for legacy SFBs, some older SFCs, and for older HMI ProTool projects. TIA Portal is the strategic path for all new development. The STEP 7 Classic manual "Working with STEP 7" (linked above) is the canonical reference for project structure on the V5.x toolchain.
Verification Checklist
After bringing up a new S7-300 program, verify the program structure with these steps:
- Open PLC → Monitor/Modify and confirm OB1 is in RUN. The
CRregister or the LED state on the CPU must show "RUN". - Open PLC → Accessible Nodes and read the diagnostic buffer. Any OB80, OB82, OB85, OB86, OB121, OB122 entries are configuration issues to fix.
- From SIMATIC Manager, Options → Block Consistency to check for any cross-references or interface mismatches.
- Use Reference Data → Program Structure to confirm OB1 calls all expected FCs/FBs and that no FB has an undefined instance.
- From Reference Data → Cross References, verify the I, Q, M, DB, and P areas are used as expected (e.g. no stray writes to read-only flags).
- Force a STOP→RUN transition and confirm retentive data is preserved (compare DB contents to a snapshot).
- Trigger each error OB in turn (e.g. remove a slave, exceed OB35 time) and confirm the CPU does not STOP.
- Compare the offline project to the online project with PLC → Compare. The block numbers and timestamps must match.
Troubleshooting Matrix
| Symptom | Likely Cause | Diagnostic Step | Resolution |
|---|---|---|---|
| CPU goes to STOP immediately | Missing OB, programming error, SDB fault | Read diagnostic buffer (PLC → Diagnostic Buffer) | Load missing OB, fix the FC/FB that raised the error, regenerate SDBs |
| CPU goes to STOP at first scan | OB121 or OB122 triggered | Diagnostic buffer shows the failing block and MC7 instruction | Fix the bad instruction, e.g. divide by zero, OOR array index |
| OB35 not running | OB35 not loaded or not configured | CPU Properties → Cyclic Interrupts | Set the OB35 time base (1 ms – 60 s) and load the OB |
| Inputs read as 0 | Wrong slot, wrong I address, or module not in process image | Online → Monitor with VAT, then read PIW directly | Fix HW Config, set module "Update process image" or use PIW |
| Instance DB has wrong structure | FB interface changed after instance DB was generated | Compare interface of FB vs instance DB | Regenerate instance DB (right-click FB → Instance DB → Update) |
| FC returns wrong values | TEMP not initialized; non-volatile assumption | Check FC with monitor | Move persistent state to a global DB or convert FC to FB |
| Symbol shows "????" in online view | Symbolic address not compiled, or HMI connection issue | Save and recompile (Blocks → Compile) | Re-download all blocks including SDBs |
| DB retentivity lost on power cycle | Retain attribute not set, or outside CPU retentive range | DB Properties → Retain bit, CPU Properties → Retentive Memory | Add the variable to the DB Retain list and ensure it is in the CPU's retentive area |
| "Know-how protection" blocks not opening | SFC109/SFC108 protection block missing or password lost | Need field report or backup of the SCL/STL source | Re-import the source from the S7 project's Sources folder |
| CPU SF LED on, BF LED blinking | PROFIBUS slave or DP master fault | Diagnostic buffer + HW Config online diagnostics | Check DP cable, slave address, terminating resistors; replace slave if hardware fault |
| Analog value stuck at 0 or 32767 | Wire break on 4–20 mA, wrong module range | Module diagnostics in HW Config online | Re-seat wiring, change measurement type to 4-wire / 2-wire per sensor |
FAQ
What is the difference between an FC and an FB in S7-300?
An FC is a stateless subroutine: it has no memory and cannot hold values between calls. An FB is a stateful subroutine: every call is paired with an instance DB that stores the FB's static (VAR) variables, so an FB behaves like an Add-On Instruction in Allen-Bradley. Use FCs for stateless math and conversion, and FBs when the block must remember state such as a motor runtime counter or a PID integrator.
How does an instance DB differ from a global DB?
An instance DB is generated automatically from an FB's interface declaration; its layout matches the FB's static variables and is read/written symbolically through the FB. A global DB (shared DB) is user-defined; any code can read/write any global DB by symbolic name or absolute address. Use instance DBs for FB state, and global DBs for plant-level variables, HMI tags, and recipes.
How do I replace the Allen-Bradley First Scan bit on S7-300?
Use OB100 (or OB102) to set a one-shot flag in the first scan. The S7-300 does not have a built-in first-scan bit. The pattern is to declare a static First_Scan in a global DB, set it TRUE in OB100, and reset it in OB1 after the initialization logic. For warm restart, OB100 is called once when the CPU transitions from STOP to RUN.
Why does my S7-300 CPU go to STOP with a SF LED and OB not loaded?
An S7-300 with all OBs at their defaults stops on any unhandled error. If a programming error (OB121) or I/O access error (OB122) is triggered and the corresponding OB is not present in the project, the CPU transitions to STOP and the diagnostic buffer lists the OB number. Download the empty OBs (right-click Blocks → Insert New Object → Organization Block) for OB80, OB82, OB85, OB86, OB121, and OB122 so the CPU can log and continue past recoverable faults.
Can I open a STEP 7 Classic S7-300 project in TIA Portal?
Yes. TIA Portal V13 and later support migration of S7-300/400 projects via "Project → Migrate project". The migration converts the S7 Program into TIA Portal blocks, preserves symbol tables, and rebuilds HW Config into the TIA device view. Some legacy SFCs and SDBs require manual adjustment, and the appropriate HSP (Hardware Support Package) for the CPU family must be installed. After migration, recompile the program, compare it to the online CPU, and re-download all blocks to verify the runtime behavior matches the original.