CNC Subprograms & Macros: M98, M99, G65, G66, G67 Explained with Real Examples
Subprograms and macros are essential tools for modular, efficient, and automated CNC programming.
They allow repeated toolpaths, logic-based machining, and parameterized operations without rewriting G-code.
This guide explains M98, M99, G65, G66, and G67 — the foundation of subroutines and parametric control in modern CNC systems.
📌 1. Overview
| Code | Function | Description |
|---|---|---|
| M98 | Call subprogram | Executes another program (Oxxxx) |
| M99 | Return or loop | Returns to main or restarts sub |
| G65 | Non-modal macro call | Executes custom macro once |
| G66 | Modal macro call | Executes macro continuously until G67 |
| G67 | Cancel modal macro | Stops G66 mode |
📌 2. M98 — Subprogram Call
M98 P1000
Calls subprogram O1000 and returns after completion.
You can also specify repeat count and location:
M98 P1000 L3
Calls subprogram O1000 three times.
📌 3. M99 — Return or Loop
M99
- Inside a subprogram → returns to main program.
- In main program (at end) → loops back to program start.
📌 4. Example: Simple Subprogram Call
Main Program (O0001):
%
O0001 (MAIN PROGRAM)
G90 G17 G21 G40 G80 G54
T01 M06
M98 P1000 L2
M30
%
Subprogram (O1000):
%
O1000 (DRILL HOLE)
G81 X50. Y50. Z-20. R2. F150
G80
M99
%
The hole cycle runs twice because of
L2.
📌 5. Nested Subprograms (Multi-Level Calls)
M98 P2000
...
O2000
M98 P3000
M99
Subprogram O2000 calls another subprogram O3000, forming a hierarchy.
Used in repetitive machining with different setups.
📌 6. Local Subprogram (Inside Main Program)
You can define a local subprogram at the end of a main program:
%
O0100
M98 P9001 L5
M30
O9001
G81 X0 Y0 Z-10. R2. F200
G80
M99
%
Many CNCs allow internal subroutine definitions using
O9xxxnumbers.
📌 7. G65 — Macro Call with Parameters
G65 executes a custom macro program (O9000–O9999) with parameter passing.
Parameters are defined using address letters (A–Z) and accessed via local variables (#1–#33) inside the macro.
Example:
G65 P9001 A50. B25.
Macro Program (O9001):
O9001
#1 = #1 (A parameter → #1)
#2 = #2 (B parameter → #2)
G00 X#1 Y#2
G81 Z-10. R2. F200
G80
M99
| Parameter | Mapping |
|---|---|
| A → #1 | B → #2 |
Passes variable coordinates or settings directly from the main program.
📌 8. Example: Drilling Array Using G65
%
O0101 (ARRAY DRILLING)
#100 = 0
WHILE [#100 LT 3] DO1
G65 P9002 X[#100*50] Y0
#100 = [#100 + 1]
END1
M30
O9002
#1 = #24 (X)
#2 = #25 (Y)
G81 X#1 Y#2 Z-15. R2. F200
G80
M99
%
Automatically drills three holes spaced 50 mm apart — fully parametric.
📌 9. G66 — Modal Macro Call
G66 P9003 A10. B20.
Runs macro O9003 automatically for every subsequent block until G67.
Example:
G66 P9003 A10. B5.
X0 Y0
X50 Y0
X50 Y50
G67
Macro (O9003):
O9003
#1 = #1 (A)
#2 = #2 (B)
G81 Z[-#1] R#2 F150
G80
M99
Great for drilling multiple holes with one setup command.
📌 10. G67 — Cancel Modal Macro
G67
Ends modal macro mode — always use before tool change or new operation.
📌 11. Fanuc Example — Hole Pattern
%
O0200 (MACRO HOLE PATTERN)
G90 G17 G21 G40 G80 G54
T05 M06
S1500 M03
G66 P9010 Z-20. F200.
X0 Y0
X50 Y0
X50 Y50
X0 Y50
G67
M30
O9010
G81 Z#26 R2. F#9
G80
M99
%
Simplifies drilling multiple locations using a single macro template.
📌 12. Haas Example — Subprogram Call
M97 P10
...
N10 G81 Z-15. R2. F150
G80
M99
Haas uses M97 for local subroutine calls (label
Nwithin same program).
📌 13. Siemens Example
CALL O1000
RET
Siemens supports structured subprogram syntax similar to Fanuc M98/M99.
📌 14. Heidenhain Example
CALL LBL 1
LBL 1
CYCL DEF 200 DRILLING Q200=+2 Q201=-10 Q206=+200
LBL 0
Heidenhain uses LBL (Label) for subprograms — more readable and flexible.
📌 15. Common Mistakes
| Mistake | Result |
|---|---|
| Missing M99 in subprogram | CNC continues into next code block (crash risk) |
| Forgetting G67 | Macro keeps running unintentionally |
| Wrong parameter mapping | Macro reads incorrect data |
Missing # variable scope | Local/global confusion |
| Infinite recursion (M98 inside itself) | Loop freeze or alarm |
📌 16. Advanced Example — Automatic Bolt Circle Drilling
%
O0300 (BOLT CIRCLE MACRO)
#101 = 8 (Number of holes)
#102 = 40. (Radius)
#103 = 0. (Start angle)
#104 = 360./#101
#105 = 0
WHILE [#105 LT #101] DO1
#106 = [COS[#103 + #105*#104]*#102]
#107 = [SIN[#103 + #105*#104]*#102]
G81 X#106 Y#107 Z-15. R2. F200
G80
#105 = [#105 + 1]
END1
M30
%
Automatically drills 8 holes equally spaced on a 40 mm radius bolt circle — no CAM needed.
📌 17. Future Trends (2025–2030)
- AI-driven macros: CNC interprets machining intent and generates macro logic automatically.
- Adaptive subprogram libraries: Machines share macros through networked databases.
- Digital twin verification: Simulates macro logic and parametric conditions before execution.
✅ Conclusion
Subprograms (M98/M99) and macros (G65/G66/G67) are the backbone of intelligent, modular CNC programming.
They enable code reuse, automation, parameterized machining, and drastically reduce human error — essential for modern high-mix, low-volume production environments.
Leave a comment