INTRODUCTION:
M98 and M99 are G-code commands used in CNC machining to create and manage subprograms, which are reusable blocks of code. Using them makes programs shorter, easier to edit, and more organized when you have repetitive operations like drilling multiple holes or machining identical features.
· M98 is the call command. It tells the machine to pause the current program, jump to a separate subprogram, run it, and then come back.
· M99 is the return command. Placed at the end of a subprogram, it tells the machine to finish the subprogram and jump back to the main program, resuming from the line right after the M98 call.
· Repeat Count: A parameter used with M98 that instructs the machine to run the same subprogram multiple times in immediate succession, without having to call it again.
Syntax for Repeating a Subprogram:
· Common Fanuc Style: M98 P[program number] L[repeat count]
· Example: M98 P2000 L5 calls subprogram O2000 five times.
· Alternative Style: The repeat count is included in the P address.
· Example: M98 P52000 calls subprogram O2000 five times (the first digits specify the count).
Why Use Subprograms?
We can write a common sequence like a drilling cycle or a pocketing routine once and call it multiple times with M98. If you need to change that sequence, you edit it in just one place (the subprogram) instead of every location it's used. It breaks a complex program into logical, manageable blocks.Let me explain the precise step by step sequence the machine's control system follows when it reads an M98 command. Here’s what happens inside the CNC controller when it encounters M98 P2000 L3:
1. The control reads the entire line M98 P2000 L3.
2. It parses parameters and interprets P2000 as the subprogram number and L3 as the repeat count.
3. It saves the return address. It saves the current position i.e. the next line number in the main program in its internal memory. This is the return address.
4. It jumps to subprogram O2000 and runs all its code. When it hits M99, it does not immediately return to the main. Instead: It checks the repeat counter. If the counter (started at 3) is greater than 1, it decrements the counter (to 2), jumps back to the beginning of O2000, and runs it again. This creates a loop at the subprogram level. The machine stays inside the M98 P2000 L3 call until the subprogram has been executed 3 consecutive times.
5. After the 3rd execution of O2000 and its M99, the repeat counter is now 0. The control finally returns to the main program and moves to the very next line after the M98 call.
EXAMPLE:
Main Program:
N10 G90 G0 X0 Y0
N20 M98 P2000 L3 <-- PC is here. Reads call. Saves "Return to N30". Jumps to O2000.
N30 G0 Z100 <-- RETURN ADDRESS. PC will come back here after 3 loops.
N40 M30
Subprogram O2000:
O2000
N100 G91 G0 X10 <-- PC jumps here from Main N20.
N110 G1 Z-5 F100
N120 G0 Z5
N130 M99 <-- PC hits this. Not done! L=3, so loop. Go back to N100.
(After 3rd loop, M99 triggers final return to Main N30.)
Execution Path of Program Counter (PC):
Main:N20 → O2000:N100 → N110 → N120 → O2000:N100 → N110 → N120 → O2000:N100 → N110 → N120 → Main:N30 → N40
2. Drilling Three Holes:
(MAIN PROGRAM)
G0 X10 Y10 (Move to first hole position)
M98 P1000 (Call subprogram O1000 to drill)
G0 X30 Y10 (Move to second hole)
M98 P1000 (Call the same subprogram)
G0 X50 Y10 (Move to third hole)
M98 P1000 (Call it again)
M30 (End main program)
(SUB PROGRAM O1000)
O1000
G91 G1 Z-5 F100 (Drill down 5mm)
G4 P0.5 (Dwell for 0.5 seconds)
G1 Z5 (Retract)
G90 (Switch back to absolute coordinates)
M99 (Return to main program)
3. DRILL 5 HOLES:
(MAIN PROGRAM)
G90 G54 (Absolute coordinates, work offset)
G0 X0 Y0 (Rapid to start position)
M98 P51000 (Call subprogram O1000 five times)
G0 Z50 (Retract tool safely)
M30 (End program)
(SUB PROGRAM: SINGLE DRILL CYCLE)
O1000
G91 G1 Z-20 F100 (1. Drill down 20mm INCREMENTALLY)
G0 Z5 (2. Rapid retract 5mm)
G4 P0.5 (3. Dwell for 0.5 sec at bottom)
G0 Z15 (4. Rapid retract fully to clear)
G90 (5. Switch back to ABSOLUTE coords)
G0 X10 (6. Move 10mm to next hole position)
M99 (RETURN to main program)
Subprogram Nesting and Storing Subprograms:
When you have nested subprograms (a subprogram calling another), the machine uses a "stack" to remember return addresses. A subprogram can itself call another subprogram. This is called nesting, but it has a limit (often 4 levels, but this varies by machine).Typically, subprograms are defined within the same file as the main program, marked by a label like O2000. Some controllers, like MASSO, require subprograms to be in separate .nc files.
Example: Main → O2000 (L2) → O1000 (L3)
1. Main calls O2000 with L2. Return address (Main_N30) is saved to Stack Level 1.
2. O2000 calls O1000 with L3. Return address (O2000_N120) is saved to Stack Level 2.
3. O1000 runs 3 times (internal loop), then its M99 returns to Stack Level 2 (O2000).
4. O2000 runs its next line, hits its M99. But L2 for O2000 isn't done! So it loops within O2000, calling O1000 another 3 times.
5. Finally, O2000's loop finishes, and its M99 returns to Stack Level 1 (Main).
This is why there's a nesting limit (often 4-10 levels). The controller's stack has limited memory.
EXAMPLE:
This example drills a 3x3 grid of holes (9 total) using subprograms with repeat counts. It demonstrates nesting (a subprogram calling another subprogram).Program Logic:
1. Main Program: Calls a ROW subprogram 3 times to make 3 rows.
2. ROW Subprogram (O2000): Calls the DRILL subprogram 3 times to make 3 holes in a row, then moves to the next row's start position.
3. DRILL Subprogram (O1000): Executes the single drilling cycle and then moves to the next hole position in the row.
(MAIN PROGRAM - O0001)
G90 G54 G0 X0 Y0 Z50 (Set absolute coords, work offset, safe start)
M98 P2000 L3 (Call the ROW subprogram 3 times to make 3 rows)
G90 G0 Z100 (Return to safe Z in absolute mode)
M30 (End main program)
%
(SUB PROGRAM 1: DRILL ONE HOLE & INDEX IN X - O1000)
O1000
G91 G1 Z-22 F150 (1. INCREMENTAL drill down into part)
G0 Z2 (2. Rapid incremental retract a bit)
G4 P0.2 (3. Dwell for 0.2 sec at bottom)
G0 Z20 (4. Rapid incremental retract fully to clear)
G90 (5. Switch back to ABSOLUTE coords)
G0 X15 (6. ABSOLUTE move 15mm to next X hole position)
M99 (Return to caller - either main or O2000)
%
(SUB PROGRAM 2: MAKE ONE ROW & INDEX IN Y - O2000)
O2000
G90 G0 X5 Y5 (1. ABSOLUTE move to start of row at X5,Y5)
M98 P1000 L3 (2. Call DRILL subprogram 3 times for this row)
G91 (3. Switch to INCREMENTAL for the row shift)
G0 Y15 (4. INCREMENTAL move 15mm to next row start in Y)
G90 (5. Switch back to ABSOLUTE for next call)
M99 (Return to main program)
```
Step-by-Step Execution Flow:
1. The main program O0001 starts and calls O2000 with L3.2. First call of O2000 (Row 1):
It moves to the first row position (X5, Y5). It calls O1000 with L3. First call of O1000: Drills hole 1, then moves to X20. Second call of O1000: Drills hole 2, then moves to X35. Third call of O1000: Drills hole 3, then moves to X50. O2000 finishes by moving incrementally to Y20 for the next row, then returns (M99) to the main program.
3. Second call of O2000 (Row 2): It repeats, but now starting at X5, Y20, drilling holes at X20, Y20, X35, Y20, and X50, Y20.
4. Third call of O2000 (Row 3): Repeats at Y35.
5. After the third M99 from O2000, the main program resumes, moves the tool to a safe height, and ends with M30.
Each subprogram should do one logical task (O1000 = drill one hole and move to next X; O2000 = position row and shift Y).
Coordinate Mode is Key (G90/G91):
In summary, M98 and M99 create modular, reusable code. The repeat count (L) automates multiple executions. The core to mastering them is precise control over your coordinate modes (G90/G91) within each subprogram's logic. This is the most important concept. For repeat counts to work, your subprogram must position the tool incrementally (G91) for the repeating pattern (like moving to the next hole), and then often switch back to absolute (G90) for stable positioning. Mixing these up is the most common source of errors. The drill cycle uses G91 for the Z-axis movements which repeat identically each time, but uses G90 for X positioning to place holes at specific absolute position.Use M98 for fixed, repetitive sequences. If you need to pass different parameters (like hole depth or spacing) each time you call the routine, use G65 (Macro Call) instead.
0 Comments