SINUMERIK 840D: Calling Subprograms from Programmed Alarms
Programmed alarms in SINUMERIK 840D sl (triggered by SETAL in the NC program or by a PLC request) cannot directly invoke a subprogram. The NCK scheduler rejects the nested program call because a part program or synchronous action is already active on the channel. This reference documents the workarounds that are field-proven on 840D sl with SINUMERIK Operate: persistent flag handling, SETINT/ASUB asynchronous subprogram triggering, and file-based state retention. The same patterns apply to SINUMERIK 828D and ONE controllers because the NC kernel and the SETAL/sync-action runtime are shared.
1. The Constraint: Why SETAL Will Not Call a Subprogram
The SETAL command raises a configured alarm number in the alarm buffer. The alarm handler runs in the alarm runtime context, not in the context of an NC part program. From the alarm handler the system is not permitted to start a separate subprogram because:
- The channel interpreter is already executing the part program, a synchronous action, or an ASUB. Nested
CALLinstructions require the interpreter to be free to load a new program context, and the alarm path does not provide that. - The PLC is the only path that can request a program change asynchronously, and only through the
FC9/ASUPrequest interface, not through the alarm text processing. - Sync actions (
WHEN ... DO) are evaluated in the IPO cycle. They can set flags, write R parameters, or triggerSETINT, but theDOblock of a sync action cannot containCALL,CALLPATH, orCALLBLOCKon a stock 840D sl build.
The user's symptom — "the sync action refuses to start a subprogram" — is therefore correct behaviour, not a misconfiguration.
2. What the NCK Allows from a Sync Action
| Construct | Allowed in Sync Action | Notes |
|---|---|---|
| Assignment to R parameter | Yes | Local to the program unless declared GUD |
| Assignment to GUD | Yes | Persists across reset only if AP_INIT / AP_MEM attributes are set |
SETAL |
Yes | Triggers programmed alarm |
SETINT |
Yes | Arms an interrupt-driven ASUB |
WRITE to file |
Yes | Persistent across reset/NCK startup |
CALL / CALLPATH
|
No | Rejected by interpreter |
M function output |
Yes | Can request PLC to start an ASUB via FC9
|
Source: SINUMERIK 840D sl Programming Manual (Fundamentals), 06/2019 Edition, Section 10 "Synchronized Actions" and SINUMERIK 840D sl Programming Manual (Job Planning), Section K1 "Flexible NC Programming".
3. The SETINT / ASUB Pattern
The accepted method to start a subprogram from an event detected in a sync action is the asynchronous subprogram (ASUB) path:
- Declare the ASUB routine in a separate program file (for example
_N_ASUP_MPFor a manufacturer part program directory). - Register the routine in machine data so the NCK knows which file is the interrupt handler.
MD11620 $MN_ASUP_TEMPL_OB/MD11610 $MN_ASUP_EDITABLEare not required for the standard pattern; theSETINT(n)instruction names the interrupt number that is hard-wired to a default ASUB at compile time. - From the sync action, raise
SETINT(1)when the alarm condition is true. The NCK takes the IPO-to-IPO interrupt, saves the current program context, and starts the ASUB at the next IPO cycle. - The ASUB runs to completion, then control returns to the interrupted part program.
3.1 Sync Action That Arms the Interrupt
DEF NCK INT _alarm_flag = 0
IDS = 1 EVERY $AC_PATH[0] == 0 AND $A_DBB[0] == 1 DO _alarm_flag = 1 SETINT(1)
The condition checks the actual axis position and a digital input byte from the PLC. When the alarm is to be raised, the sync action sets the local flag and primes the interrupt.
3.2 ASUB Program _N_ASUP_MPF
PROC ASUP SAVE
; Runs in interrupt context
IF _alarm_flag == 1
_alarm_flag = 0
SETAL(65000, 1) ; raise programmed alarm 65000 with channel 1
; perform the operator-defined response here
; (axis stop, spindle stop, custom M-code to PLC)
M00 ; programmed stop; equivalent to halt request
ENDIF
RET
Notes on the SAVE attribute: the interrupt handler must save all R parameters, frames, and G codes that it modifies. The SAVE declaration in the PROC line forces the ASUB to allocate its own R parameter context, preventing leakage back into the calling part program.
4. Persistent State: R Parameters vs GUD vs File
The field report notes that "system variables are set to 0 when the machine is reset." This is correct for stock R parameters. The cure depends on how long the value must survive.
| Storage | Survives Reset | Survives NCK Power Off | Survives HMI Restart | Scope |
|---|---|---|---|---|
| Local R parameter (R0..R99) | No | No | No | Program / ASUB |
| Global R parameter (R100+ via GUD) | Yes (if AP_MEM) |
Yes (if AP_MEM) |
Yes | Channel or NCK-wide |
| GUD file (/_N_DEF_DIR/_N_GUD_DEF) | Yes | Yes | Yes | NCK-wide |
| Local LUD / P variables | No | No | No | Program only |
File via WRITE
|
Yes | Yes | Yes | Any file system path |
| NV variable ($A_*) | No (mostly) | No | No | Per-cycle |
4.1 Defining a GUD That Persists
Open the GUD definition file in the NCK (path: /_N_DEF_DIR/_N_GUD_DEF) and add:
DEF NCK INT _alarm_state = 0 ;AP_MEM=1 implicitly via NCK scope
DEF NCK REAL _alarm_value = 0.0
Scope keywords (per the Programming Manual Fundamentals, Section 2.4):
-
DEF NCK— accessible from every channel, persists because the definition is in the NCK file system. -
DEF CHAN— accessible from the declaring channel only. -
DEF GLOB— same asNCKin modern builds.
AP_MEM attribute applies to the value of a settable frame, not to the GUD definition file. Use the standard HMI archive path /card/sinumerik/nck to ensure values survive a control restart.5. File-Based Persistence with WRITE and READ
When a value must survive even a control rebuild, write it to a file on the CFast card. The WRITE and READ instructions in the part program are part of the standard NC language and require no option (in contrast to EXECSTRING, which requires compile cycles).
DEF STRING[32] _path = "/_N_MPF_DIR/_N_ALARM_LOG_MPF"
DEF INT _rc
; --- write side (in the ASUB after SETAL) ---
WRITE(_error, _path, _rc)
; _error is the alarm number
; --- read side (in the next program start) ---
READ(_error, _path, _rc)
IF _rc == 0
; apply _error
ENDIF
File handling is documented in the Programming Manual Fundamentals, Section 12 "File Programming". The WRITE instruction requires a string expression and writes it as a single line; structured logging requires explicit formatting (for example, SPRINT to compose the line).
6. Why "Global Variables" in a Sync Action Can Fail
The field report states that the user could not get global variables working in a sync action. The most common cause is the location of the assignment. Sync actions execute under a slightly different symbol resolution path than the part program. If the global variable is defined as a DEF CHAN GUD, the channel context is implicit. If the GUD is declared in a definition file that is not loaded into the channel (missing access rights in the definition file), the sync action cannot see it.
Verify with the HMI menu Commissioning > NCK > GUD: the variable must appear with a non-red icon. If it shows red, the access level is wrong. Modify the ACCESS / REDDEF attributes in the GUD definition file:
DEF NCK INT _alarm_state = 0
ACCESS = RW ; read-write from the part program
REDDEF = AS_ACCESSED ; not reduced when read
For the sync action, the variable must be declared at the start of the part program file that contains the IDS block, or referenced fully qualified. See Programming Manual Fundamentals, Section 2.4 "User-Defined Variables (GUD)".
7. Complete End-to-End Example
The following builds a working pattern: the part program watches for an external alarm request, persists the alarm code to a GUD, raises the alarm, and on the next start the part program reads the file and clears the condition.
7.1 GUD Definition (/_N_DEF_DIR/_N_GUD_DEF)
DEF NCK INT _last_alarm = 0
DEF NCK REAL _last_alarm_time = 0.0
ACCESS = RW
REDDEF = AS_ACCESSED
7.2 Sync Action Block (top of the part program)
IDS = 1 WHENEVER $A_DBB[0] == 1 DO _last_alarm = 65000 SETINT(1)
IDS = 2 WHENEVER $A_DBB[0] == 0 DO _last_alarm = 0
7.3 ASUB Handler (/_N_CMA_DIR/_N_ALARM_ASUP_MPF)
PROC ALARM_ASUP SAVE
DEF INT _rc = 0
DEF STRING[64] _line
IF _last_alarm <> 0
_line = SPRINT("ALARM %d @ %f", _last_alarm, $AC_TIMER[1])
WRITE(_line, "/_N_MPF_DIR/_N_ALARM_LOG_MPF", _rc)
SETAL(_last_alarm, 1)
ENDIF
RET
7.4 Operator Acknowledgement Part Program
PROC ACK_ALARM
DEF INT _rc = 0
DEF INT _alarm = 0
READ(_alarm, "/_N_MPF_DIR/_N_ALARM_LOG_MPF", _rc)
IF _rc == 0 AND _alarm <> 0
MSG("Last alarm: " << _alarm)
_last_alarm = 0
; erase log file by writing empty line
WRITE("", "/_N_MPF_DIR/_N_ALARM_LOG_MPF", _rc)
ENDIF
RET
Each step is fully supported on the stock 840D sl and 828D builds. The SPRINT formatter is documented in Programming Manual Job Planning, Section K5 "String Operations".
8. Alternative: PLC-Triggered ASUB via FC9
If the alarm is raised by a PLC condition rather than by NC code, the PLC can request an ASUB directly through the standard interface:
-
FC9 "ASUB" in the SINUMERIK PLC basic program: the PLC sets the request byte and the NCK starts the ASUB. The default ASUB is
_N_ASUP_MPFin the manufacturer directory. - The PLC also writes the alarm number to a configured DB byte; the ASUB reads it and raises the alarm with
SETAL.
This path is preferable when the alarm originates from a sensor the PLC already monitors, because it avoids polling the PLC in a sync action.
Reference: SINUMERIK 840D sl PLC Programming Manual, Section 3.6 "Asynchronous Subprograms (ASUBs)".
9. Verification Procedure
- Load the GUD file via HMI > Commissioning > NCK > GUD > Activate. The system reports "GUD file loaded".
- Set a write access password or accept the default access level for testing.
- In MDA mode, run
IDS=1alone (no part program) and check that the sync action does not raise an alarm — only sets the flag. - Manually run
SETINT(1)and verify that the ASUB is loaded and the alarm text appears on the HMI. - Cycle NCK power; the GUD value must survive. Read with
R_RVAR(1, _last_alarm)in the part program. - Force an NCK reset (Commissioning > NCK > Reset (NCK)). Confirm that the file-based log still contains the alarm entry.
10. Troubleshooting Matrix
| Symptom | Likely Root Cause | Fix |
|---|---|---|
| Alarm not raised on event | Sync action not active because the part program is in a block without motion | Move IDS definition to a globally active file (for example _N_GUD_DEF) or use DO with a non-zero condition |
| Alarm raised but no ASUB runs |
SETINT not armed; MD20150 G-code defaults block SETINT
|
Set MD20150 $MC_GCODE_RESET_VALUES[0] = 0 or move SETINT outside the block where it is being reset |
| GUD value resets on NCK startup | Definition file not archived; REDDEF blocks persistence |
Adjust GUD access attributes and run a full commissioning archive |
| Subprogram call still rejected from sync action | Wrong interpreter path; CALL is fundamentally blocked in sync actions on the build in use |
Move the call into the ASUB; keep the sync action as the trigger only |
| WRITE to file returns error 18 | Path does not exist or file is locked by HMI | Check that the file directory is mounted; use the HMI to inspect the file |
| Alarm appears but the operator cannot clear it | Alarm configured as "Clear by Reset only" in MD11415
|
Configure MD11415 $MN_ALARM_CLEAR_BEFORE_START to allow clear on program start |
11. Field-Commissioning Tips
- Keep the sync action side as small as possible — one assignment and one
SETINT. All complex logic belongs in the ASUB. - Always declare
SAVEon the ASUB'sPROCline. Without it, the ASUB shares R parameters with the interrupted program and can corrupt the parent context. - Do not call
CANCEL(1)from inside the ASUB; that would terminate the interrupted part program rather than return to it. - For test rigs that lack PLC, drive the sync action with a write to a system variable that you can change from the HMI:
$A_DBB[0]is wired to the PLC by default but can be used as a test flag with care. - When the alarm must be cleared at NCK reset, combine the GUD value with the file-based log; the file is the only path that survives the most aggressive resets (for example, NCK general reset, part 5 of the Commissioning > Reset menu).
12. Summary of Constraints
-
SETALcannot start a subprogram. It can only set the alarm number and text. - Sync actions can set state, write R parameters, and prime interrupts, but cannot call subprograms.
- The supported path from a sync action to a subprogram is
SETINT(n)→ NCK interrupt → ASUB. The ASUB is a normal NC part program running in interrupt context. - For state that must survive reset, use GUD variables with the correct
ACCESSandREDDEFattributes, or write to a file via theWRITEinstruction. - For alarms originating in the PLC, use the
FC9ASUB request path rather than a sync action.
13. Frequently Asked Questions
Why does my sync action refuse to call a subprogram on SINUMERIK 840D?
Sync actions are evaluated in the IPO cycle and the language subset excludes CALL, CALLPATH, and CALLBLOCK. The interpreter rejects the instruction on every 840D sl and 828D build. Use SETINT(n) to trigger an asynchronous subprogram (ASUB) instead.
Which variable scope survives an NCK reset on a SINUMERIK 840D?
Local R parameters (R0–R99) reset to 0. Variables defined as DEF NCK in the GUD file (path /_N_DEF_DIR/_N_GUD_DEF) persist across reset and across NCK restart when the file is part of the standard commissioning archive.
How do I raise a programmed alarm from a sync action?
Use SETAL(alarm_number, channel) inside the DO block of the sync action. The alarm appears in the HMI alarm bar and the alarm log. The alarm number must be configured in the alarm text file /_N_CMA_DIR/_N_ALARM_TXT_MPF or in the manufacturer-specific configuration.
Can the PLC start an ASUB directly when an alarm condition is detected?
Yes. Use the standard PLC basic program block FC9 "ASUB". The PLC writes the request byte and the NCK starts the ASUB at the next IPO cycle. The ASUB can then call SETAL with the alarm number supplied by the PLC.
What is the difference between SETINT and a regular CALL in an ASUB?
SETINT(n) arms an interrupt and tells the NCK to start the ASUB associated with interrupt number n when the condition becomes true. A regular CALL requires the interpreter to be idle; SETINT works while the part program is running, making it the only valid way to branch from a sync action.
How do I make a value written from an ASUB visible to the next part program run?
Store the value in a GUD declared DEF NCK for channel-wide visibility, or use WRITE to a file under /_N_MPF_DIR or /_N_CMA_DIR for persistence across NCK reset. Read the value back with READ at the start of the next program.