Siemens S7-300 Program Structure: OB, FB, FC, DB Reference

David Krause20 min read
S7-300SiemensTechnical Reference
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

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:

  1. 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).
  2. User program execution – OB1 is called and runs the user code. Subordinate blocks (FCs, FBs) are invoked from OB1 or from other blocks.
  3. 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:

  1. Use only Ladder, OB1, and FCs for the first project. Use DBs to store data; do not write FBs or instance DBs yet.
  2. 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.

Field note: Avoid the temptation to flatten all logic into OB1 with direct addresses. Even on a 7-day schedule, defining a small global DB per process unit (one per tank, one per motor starter) cuts commissioning time significantly because HMIs and drive blocks can be wired once.

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.3 in 2010, stop and add a symbol.
  • Address the periphery with the right prefix. Process image access is I / Q; direct periphery is PI / 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:

  1. Open PLC → Monitor/Modify and confirm OB1 is in RUN. The CR register or the LED state on the CPU must show "RUN".
  2. Open PLC → Accessible Nodes and read the diagnostic buffer. Any OB80, OB82, OB85, OB86, OB121, OB122 entries are configuration issues to fix.
  3. From SIMATIC Manager, Options → Block Consistency to check for any cross-references or interface mismatches.
  4. Use Reference Data → Program Structure to confirm OB1 calls all expected FCs/FBs and that no FB has an undefined instance.
  5. 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).
  6. Force a STOP→RUN transition and confirm retentive data is preserved (compare DB contents to a snapshot).
  7. Trigger each error OB in turn (e.g. remove a slave, exceed OB35 time) and confirm the CPU does not STOP.
  8. 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.

Back to blog