Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save leehambley/9137ee5647f70589a6559f6923c188fa to your computer and use it in GitHub Desktop.

Select an option

Save leehambley/9137ee5647f70589a6559f6923c188fa to your computer and use it in GitHub Desktop.
FlexiHal with ncSender/IOSender and Fuling/Folinn BD600/BD612 VFDs

Folinn / Fuling BD612 Series VFD — grblHAL MODVFD Setup Guide

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


Background

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").


Hardware Wiring

RS485 connection:

  • FlexiHAL A → VFD SG+
  • FlexiHAL B → VFD SG-
  • FlexiHAL GND → VFD GND/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

Modbus Communication Parameters

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 to 8N1 (F13.02=0) for grblHAL compatibility. grblHAL has hardcoded 8N1 with no configurable override.


Modbus Register Map (empirically verified)

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 0x1001 is referenced in some online BD600 configs as the frequency setpoint. On this BD612 variant 0x3000 is the correct percentage-based setpoint. Register 0x1001 is the control word register — writing frequency values there has no effect on output frequency.

Control Word Values (0x1000)

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

Frequency Setpoint Scaling (0x3000)

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

Frequency Readback Scaling (0x3001)

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

mbpoll Commands (Windows, USB-RS485 on COM4)

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. hardware 0x3000 = mbpoll -r 0x3001. Note: grblHAL uses direct hardware addressing with no offset.

Test communication (read bus voltage)

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3003 -c 1 COM4

Set frequency (example: 50% = 12000rpm)

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3001 COM4 -- 0x1388

Run forward

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x1001 COM4 -- 0x0001

Stop (decelerate)

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x1001 COM4 -- 0x0006

Fault reset

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x1001 COM4 -- 0x0007

Read actual running frequency and bus voltage

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0x3002 -c 2 COM4

Read F00 parameters (first 10)

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0xF001 -c 10 COM4

Read F02 motor parameters

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0xF201 -c 10 COM4

Read F13 communication parameters

mbpoll -1 -q -m rtu -b 9600 -d 8 -s 1 -P none -a 1 -t 4:hex -r 0xFD01 -c 7 COM4

VFD Keypad Parameter Settings

F00 — Standard Function Parameters (confirmed values)

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.10 warning: This parameter reverts to 800Hz on power cycle if not explicitly saved. If F00.22 is misconfigured and VFD falls back to keypad preset, spindle will run to full speed. Keep at 0 for safety.

F00.22 is critical: Without F00.22=9, the VFD display H value (setpoint) changes with Modbus frequency commands but the P value (actual output) does not respond — spindle runs at F00.10 preset instead. This was the key missing parameter.

F00.03 keypad limit: Maximum value accepted via Modbus write is limited by firmware to ~32000 (320Hz). Values above this return Invalid data. Set F00.03 via keypad directly. The keypad accepts up to 800.00Hz on this unit.

F02 — Motor 1 Parameters (confirmed values)

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.02 ordering: Must be set before F00.03. The drive enforces F00.03 ≤ F02.02 — if F02.02 is still at default 50Hz, F00.03 cannot be raised above ~320Hz via Modbus.

F04 — V/F Control Parameters (confirmed values)

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

F13 — Communication Parameters (confirmed values)

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

Factory Reset Procedure

  1. Navigate keypad to F00.28
  2. Set to 1 (restore factory defaults, preserves motor params) or 2 (clear fault history only)
  3. Press FUNC/DATA to confirm
  4. Power cycle VFD
  5. Re-enter all F00, F04, F13 parameters from this document
  6. Motor parameters F02.01–F02.05 are preserved through factory reset

grblHAL MODVFD Settings (confirmed working)

Complete $ settings for spindle/Modbus

$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

Frequency scaling summary

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

Status report

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.


MODVFD Plugin Behaviour (from modvfd.c source)

  1. On M3 Sxxx, grblHAL calls spindleSetState()
  2. First: writes run command ($465) to run/stop register ($462) — blocking FC06
  3. Only if step 2 ACKs: writes frequency value to frequency register ($463) — blocking FC06
  4. grblHAL withholds ok until both writes complete (up to 500ms, 5 retries each)
  5. Periodic non-blocking FC03 reads from $464 update at-speed status asynchronously
  6. 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.


Common Fault Codes

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

Debugging Procedure

If spindle does not respond to M3:

  1. Verify $10=11 — without this ? shows no spindle state and debugging is blind

  2. 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 COM4
    

    Should return bus voltage ~0x0D00 (330V). If timeout: check wiring, check F13.02=0

  3. Verify baud rate: F13.01=5 (9600) must match $374=2 (9600)

  4. Verify stop bits: F13.02=0 (8N1) — factory default 3 (8N2) causes silent failure

  5. Verify UART: $370=0 routes to FlexiHAL onboard RS485

  6. Check F00.22=9 — without this, H value changes but spindle doesn't respond

  7. Check F00.06=9 — RS485 must be selected as frequency source

  8. Disable readback during debug: $464=0 prevents grblHAL from holding the bus

  9. Watch VFD display: H = setpoint received, not running. P = running. H without P = run command not working


Known Limitations

  • Modbus frequency ceiling: F00.03 cannot be written above ~32000 (320Hz) via Modbus — firmware enforces signed 16-bit limit. Set via keypad (accepts up to 800.00Hz).

  • F00.10 reverts: Keypad preset frequency reverts to previous value on power cycle unless saved via EEPROM write. Keep at 0 as safety default.

  • grblHAL stop bits: MODVFD has hardcoded 8N1. $376/$377/$378 return Error 53. VFD must be set to F13.02=0.

  • grblHAL <Idle while running: Normal — means no axis motion, not spindle off. Use $10=11 and ? to see actual spindle state.

  • G4 dwell timeout in ncSender: ncSender has 1s ok timeout. G4 P2 (2s dwell) will show timeout warning but completes correctly — grblHAL sends ok after the dwell. Not a fault.

  • grblHAL continuous Modbus polling: With $464 set, grblHAL polls the readback register continuously, blocking mbpoll access. Set $464=0 before using mbpoll while grblHAL is connected.


References


All settings verified via mbpoll and grblHAL on 2026-05-17. Settings marked CRITICAL were confirmed to cause silent failure when incorrect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment