Hardware: Zhejiang New Folinn Electric Co. BD612 Series (also sold as BD600 — unit splashes BD600 on boot)
Spindle: 4.5kW, 800Hz, 24000rpm, 220V 3-phase, 20A rated
Controller: Expatria Technologies FlexiHAL (STM32F446, grblHAL firmware)
Plugin: MODVFD v0.05 (grblHAL Plugins_spindle)
Communication: Modbus RTU over RS485
Last verified: 2026-05-17
The BD612 is an engraving-machine-specific variant of the BD600 series. The unit's keypad displays BD600 on power-up splash. Parameters and register addresses from the full BD600 manual apply, with exceptions noted below.
Register addresses were determined empirically using mbpoll and cross-referenced against a LinuxCNC vfdmod configuration shared by user H2B on the LinuxCNC forum (thread: "Vfdmod — An easy VFD control over MODBUS RTU").
RS485 connection:
- FlexiHAL
A→ VFDSG+ - FlexiHAL
B→ VFDSG- - FlexiHAL
GND→ VFDGND/ACM
Motor cable shielding:
- Ground shield at VFD end only — connect to VFD earth terminal
⊕ - Leave spindle/motor end of shield floating
- Grounding both ends creates a ground loop and worsens EMI
4th wire alongside U/V/W:
- This is the PE/earth/ground wire for the motor chassis
- Connect to VFD grounding terminal
⊕(earth symbol) — NOT to U/V/W - Never leave unconnected — floating motor chassis is a shock hazard and EMI source
| Parameter | Value |
|---|---|
| Baud rate | 9600 |
| Data bits | 8 |
| Stop bits | 1 (8N1) |
| Parity | None |
| Slave address | 1 |
| Protocol | Modbus RTU |
Critical: Factory default is
8N2(F13.02=3). Must be changed to8N1(F13.02=0) for grblHAL compatibility. grblHAL has hardcoded8N1with no configurable override.
| Register | Address (hex) | Address (decimal) | Function | Notes |
|---|---|---|---|---|
| Control word | 0x1000 |
4096 |
Run/stop/reset | Write only |
| Frequency setpoint | 0x3000 |
12288 |
Set speed as % | -10000 to +10000 = -100% to +100% of max freq |
| Frequency readback | 0x3001 |
12289 |
Read actual freq | Units: 0.1Hz/unit. 8000 = 800.0Hz |
| Bus voltage | 0x3002 |
12290 |
DC bus voltage | Read only |
Critical note: Register
0x1001is referenced in some online BD600 configs as the frequency setpoint. On this BD612 variant0x3000is the correct percentage-based setpoint. Register0x1001is the control word register — writing frequency values there has no effect on output frequency.
| Value (hex) | Value (decimal) | Meaning |
|---|---|---|
0x0001 |
1 |
Run forward (CW) |
0x0002 |
2 |
Run reverse (CCW) |
0x0005 |
5 |
Stop (free coast) |
0x0006 |
6 |
Stop (decelerate) |
0x0007 |
7 |
Fault reset |
Register 0x3000 uses percentage scaling — 10000 = 100% of F00.03 (max frequency):
| Desired speed | Register value | Hex |
|---|---|---|
| 24000rpm (800Hz, 100%) | 10000 |
0x2710 |
| 12000rpm (400Hz, 50%) | 5000 |
0x1388 |
| 6000rpm (200Hz, 25%) | 2500 |
0x09C4 |
| 1000rpm (33.3Hz, 4.2%) | 417 |
0x01A1 |
Register 0x3001 returns actual output frequency in 0.1Hz units:
| Register value | Actual frequency | RPM |
|---|---|---|
8000 |
800.0Hz | 24000rpm |
4000 |
400.0Hz | 12000rpm |
2000 |
200.0Hz | 6000rpm |
Standard flags for all commands: -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1
Note:
-1= one-shot (exit after one poll).-q= quiet (suppress banner). Always use both. Note: mbpoll uses 1-based register addressing. Add 1 to hardware register address. e.g. hardware0x3000= mbpoll-r 0x3001. Note: grblHAL uses direct hardware addressing with no offset.
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3003 -c 1 COM4
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3001 COM4 -- 0x1388
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x1001 COM4 -- 0x0001
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x1001 COM4 -- 0x0006
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x1001 COM4 -- 0x0007
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3002 -c 2 COM4
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0xF001 -c 10 COM4
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0xF201 -c 10 COM4
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0xFD01 -c 7 COM4
| Parameter | Value | Hex | Meaning |
|---|---|---|---|
F00.00 |
2 |
0x0002 |
V/F control mode |
F00.01 |
2 |
0x0002 |
RS485 command source |
F00.02 |
0 |
0x0000 |
Modbus run source |
F00.03 |
8000 |
0x1F40 |
Max frequency = 800.0Hz |
F00.04 |
8000 |
0x1F40 |
Upper frequency limit = 800.0Hz |
F00.05 |
0 |
0x0000 |
Lower frequency limit = 0Hz |
F00.06 |
9 |
0x0009 |
Frequency A source = RS485 |
F00.07 |
0 |
0x0000 |
Frequency B source = keypad |
F00.08 |
0 |
0x0000 |
Frequency B range |
F00.09 |
0 |
0x0000 |
Frequency source = A only |
F00.10 |
0 |
0x0000 |
Keypad preset frequency = 0 |
F00.11 |
1 |
0x0001 |
Frequency resolution = 0.1Hz |
F00.12 |
1000 |
0x03E8 |
Acceleration time = 10.0s |
F00.13 |
1000 |
0x03E8 |
Deceleration time = 10.0s |
F00.22 |
9 |
0x0009 |
Bind RS485 command to RS485 freq source |
F00.10warning: This parameter reverts to 800Hz on power cycle if not explicitly saved. IfF00.22is misconfigured and VFD falls back to keypad preset, spindle will run to full speed. Keep at0for safety.
F00.22is critical: WithoutF00.22=9, the VFD displayHvalue (setpoint) changes with Modbus frequency commands but thePvalue (actual output) does not respond — spindle runs atF00.10preset instead. This was the key missing parameter.
F00.03keypad limit: Maximum value accepted via Modbus write is limited by firmware to ~32000 (320Hz). Values above this returnInvalid data. SetF00.03via keypad directly. The keypad accepts up to 800.00Hz on this unit.
| Parameter | Value | Hex | Meaning |
|---|---|---|---|
F02.00 |
0 |
0x0000 |
Common asynchronous motor |
F02.01 |
45 |
0x002D |
Rated power = 4.5kW |
F02.02 |
8000 |
0x1F40 |
Rated frequency = 800.0Hz |
F02.03 |
24000 |
0x5DC0 |
Rated speed = 24000rpm |
F02.04 |
220 |
0x00DC |
Rated voltage = 220V |
F02.05 |
2000 |
0x07D0 |
Rated current = 20.0A |
F02.02ordering: Must be set beforeF00.03. The drive enforcesF00.03 ≤ F02.02— ifF02.02is still at default 50Hz,F00.03cannot be raised above ~320Hz via Modbus.
| Parameter | Value | Hex | Meaning |
|---|---|---|---|
F04.00 |
0 |
0x0000 |
Linear V/F curve |
F04.01 |
1 |
0x0001 |
Torque boost = 0.1% |
F04.02 |
500 |
0x01F4 |
Torque boost cutoff = 50.0Hz |
F04.10 |
64 |
0x0040 |
V/F over-excitation gain |
| Parameter | Value | Hex | Meaning |
|---|---|---|---|
F13.00 |
1 |
0x0001 |
Slave address = 1 |
F13.01 |
5 |
0x0005 |
Baud rate = 9600 |
F13.02 |
0 |
0x0000 |
Data format = 8N1 |
F13.03 |
20 |
0x0014 |
Response delay = 20ms |
F13.04 |
0 |
0x0000 |
Timeout action |
F13.05 |
1 |
0x0001 |
Standard Modbus protocol |
F13.06 |
0 |
0x0000 |
Current resolution |
F13.01 baud rate lookup:
| Value | Baud rate |
|---|---|
0 |
1200 |
1 |
2400 |
2 |
4800 |
3 |
7200 |
4 |
9600 — NOT this |
5 |
9600 ← use this |
6 |
19200 |
7 |
38400 |
F13.02 data format lookup:
| Value | Format | Notes |
|---|---|---|
0 |
8N1 |
Use this — matches grblHAL |
1 |
8E1 |
|
2 |
8O1 |
|
3 |
8N2 |
Factory default — causes silent failure with grblHAL |
- Navigate keypad to
F00.28 - Set to
1(restore factory defaults, preserves motor params) or2(clear fault history only) - Press
FUNC/DATAto confirm - Power cycle VFD
- Re-enter all
F00,F04,F13parameters from this document - Motor parameters
F02.01–F02.05are preserved through factory reset
$10=11 ; Status report mask — REQUIRED for spindle speed reporting in ?
; Bit 0 (1) = MPos, Bit 1 (2) = Bf, Bit 3 (8) = FS feed+speed
; Without $10=11, ? never shows |FS:| field and spindle state is invisible
$30=24000 ; Max spindle speed (RPM)
$31=0 ; Min spindle speed (RPM)
$32=0 ; Laser mode = off
$39=0 ; Spindle at-speed input = disabled
$394=0 ; Spindle on delay = 0s
$370=0 ; Modbus stream = FlexiHAL onboard RS485 transceiver
; CRITICAL — other values route to wrong UART, nothing works
$374=2 ; Modbus baud rate = 9600
; CRITICAL — default is 3=19200, causes completely silent failure
; $376/$377/$378 return Error 53 (not available) — use $374 only
$395=5 ; Active spindle = MODVFD
$462=4096 ; Run/stop register = 0x1000
$463=12288 ; Frequency setpoint register = 0x3000 (percentage-based)
; NOT 0x1001 — that is the control word register on this variant
$464=12289 ; Frequency readback register = 0x3001
$465=1 ; Run forward command = 0x0001
$466=6 ; Run reverse command = 0x0006 (uses stop+reverse, not 0x0002)
$467=6 ; Stop command = 0x0006 (decelerate to stop)
$468=10000 ; RPM → register multiplier
$469=24000 ; RPM → register divider
; Formula: register = RPM × $468 / $469
; S24000 → 24000 × 10000/24000 = 10000 = 100% = 800Hz ✓
; S12000 → 12000 × 10000/24000 = 5000 = 50% = 400Hz ✓
; S1000 → 1000 × 10000/24000 = 416 = 4.2% = 33Hz ✓
$470=3 ; Readback RPM multiplier
$471=1 ; Readback RPM divider
; Formula: RPM = register_value × $470 / $471
; 4000 (400Hz) × 3/1 = 12000rpm ✓
; 8000 (800Hz) × 3/1 = 24000rpm ✓
$476=1 ; Modbus slave address = 1
M3 S value |
Register sent | VFD display | Actual speed |
|---|---|---|---|
S24000 |
10000 |
P800.0 |
24000rpm |
S12000 |
5000 |
P400.0 |
12000rpm |
S6000 |
2500 |
P200.0 |
6000rpm |
S1000 |
416 |
P33.3 |
1000rpm |
With $10=11, the ? response includes spindle state:
<Idle|MPos:x,y,z|Bf:128,1024|FS:0,12000>
FS:feed,spindle — spindle value shows commanded RPM. Actual RPM from readback register updates asynchronously.
- On
M3 Sxxx, grblHAL callsspindleSetState() - First: writes run command (
$465) to run/stop register ($462) — blocking FC06 - Only if step 2 ACKs: writes frequency value to frequency register (
$463) — blocking FC06 - grblHAL withholds
okuntil both writes complete (up to 500ms, 5 retries each) - Periodic non-blocking FC03 reads from
$464update at-speed status asynchronously - Readback RPM =
register_value × ($470 / $471)
Important: grblHAL <Idle state in ? response means no axis motion — it does NOT mean spindle is off. Spindle state is shown in |FS:| field only when $10=11.
| Code | Meaning | Common Cause | Fix |
|---|---|---|---|
E004 |
Overcurrent during acceleration | Wrong V/F curve, accel too fast | Check motor params, increase F00.12 |
E008 |
AC drive overload | Wrong motor parameters | Correct F02.01–F02.05 |
E032 |
Current limit fault | V/F instability, torque boost too high | Set F04.01=0, check F04.11 |
E034 |
Speed deviation | Encoder feedback diverged from setpoint | Switch to V/F mode F00.00=2 |
ALARM:1 |
grblHAL hard limit | EMI from spindle triggering limit inputs | Shield cables, improve grounding |
ALARM:8 |
Homing fail | Machine not homed, or in alarm state | $X then $H |
ALARM:14 |
Spindle at-speed timeout | Modbus not communicating | Set $470=0 while debugging |
If spindle does not respond to M3:
-
Verify
$10=11— without this?shows no spindle state and debugging is blind -
Test with mbpoll first — disconnect grblHAL, use mbpoll to confirm basic comms:
mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3003 -c 1 COM4Should return bus voltage ~
0x0D00(330V). If timeout: check wiring, checkF13.02=0 -
Verify baud rate:
F13.01=5(9600) must match$374=2(9600) -
Verify stop bits:
F13.02=0(8N1) — factory default3(8N2) causes silent failure -
Verify UART:
$370=0routes to FlexiHAL onboard RS485 -
Check
F00.22=9— without this,Hvalue changes but spindle doesn't respond -
Check
F00.06=9— RS485 must be selected as frequency source -
Disable readback during debug:
$464=0prevents grblHAL from holding the bus -
Watch VFD display:
H= setpoint received, not running.P= running.HwithoutP= run command not working
-
Modbus frequency ceiling:
F00.03cannot be written above ~32000 (320Hz) via Modbus — firmware enforces signed 16-bit limit. Set via keypad (accepts up to 800.00Hz). -
F00.10reverts: Keypad preset frequency reverts to previous value on power cycle unless saved via EEPROM write. Keep at0as safety default. -
grblHAL stop bits: MODVFD has hardcoded
8N1.$376/$377/$378returnError 53. VFD must be set toF13.02=0. -
grblHAL
<Idlewhile running: Normal — means no axis motion, not spindle off. Use$10=11and?to see actual spindle state. -
G4 dwell timeout in ncSender: ncSender has 1s
oktimeout.G4 P2(2s dwell) will show timeout warning but completes correctly — grblHAL sendsokafter the dwell. Not a fault. -
grblHAL continuous Modbus polling: With
$464set, grblHAL polls the readback register continuously, blocking mbpoll access. Set$464=0before using mbpoll while grblHAL is connected.
- LinuxCNC forum: "Vfdmod — An easy VFD control over MODBUS RTU" — BD600 config by user H2B
- grblHAL Plugins_spindle: https://github.com/grblHAL/Plugins_spindle
- Expatria Technologies FlexiHAL: https://github.com/Expatria-Technologies/Flexi-HAL
- BD600 Series manual: Zhejiang New Folinn Electric Co., Ltd
All settings verified via mbpoll and grblHAL on 2026-05-17. Settings marked CRITICAL were confirmed to cause silent failure when incorrect.