FLY Buffer on a Manta M8P: wiring, Klipper config and serial calibration

Build notes · Klipper / Kalico

Hardware inventory, wiring, Klipper configuration and serial calibration for a FLY‑LLL PLUS filament buffer with the MDM breakage/blockage module, on an Ender 5 Max converted to CoreXY.

BTT Manta M8P V2.0 · CB2 Kalico v2026.04 EBB36 toolhead over CAN Cartographer v4

1 · The machine

Context for the pin choices below — the buffer has to land on whatever a given board has spare.

PartDetailNotes
FrameEnder 5 Max (F004), converted to CoreXY400 × 400 bed
MainboardBTT Manta M8P V2.0STM32H723, USB→CAN bridge
HostBTT CB2 running Kalicov2026.04.00
Toolhead MCUBTT EBB36 v2 / Gen2STM32G0B1, CAN on PB12/PB13
ExtruderOrbiter 2.0 + Smart Sensorrotation_distance 4.637
HotendTriangle Labs / Phaetus Rapido HFPT1000, 2.2 kΩ pullup
ProbeCartographer v4own CAN node, fw 6.2.0
BufferMellow FLY‑LLL PLUS + FLY‑MDMfw 2.0.1

2 · How the buffer subsystem actually works

What the buffer is for

On a long filament path — a bowden run, a top-mounted spool, anything with a drag chain — the extruder is doing two jobs at once: metering filament precisely, and dragging it through the whole path against spool inertia and friction. The second job interferes with the first. Under load the extruder gear slips or skips, and you get under-extrusion that is very hard to distinguish from a partial clog.

A powered buffer takes the second job away. It feeds filament forward at roughly the rate the extruder is consuming it, keeping a small slack loop so the extruder only ever has to meter, never pull. It needs to know how fast to feed — which is the whole reason Klipper sends it a signal at all.

How blockage detection falls out of that

Once the buffer knows both how much filament was asked for and how much actually moved, it can compare them. In normal printing those two track each other closely. When they diverge past a tolerance, something is wrong: the filament has snapped, jammed, or is slipping. That comparison is the whole detection mechanism, and it is why the step signal matters — without it the buffer has nothing to compare against.

This is the part worth understanding before wiring anything, because it isn’t obvious from the config. There are two independent signal paths, and Klipper sits at opposite ends of each.

OUT   Klipper ──[ STEP + DIR ]──▶ buffer // a step stream mirroring the real extruder // tells the buffer how much filament was demanded BACK MDM ──▶ buffer ──[ switch ]──▶ Klipper // MDM measures actual movement + presence // buffer compares demand vs actual, pulls the line on a fault

[extruder_stepper buffer_monitor] does not drive a motor. The buffer has its own controller, driver and power. That section exists purely to generate a step/dir stream synchronised to the real extruder, which the buffer reads as “this much filament was asked for”. That’s why it has no enable_pin, and why FORCE_MOVE on it will never move filament.

The return path is a single switch line. With the MDM module fitted, breakage and blockage arrive on that same line — the mainboard cannot tell which occurred.

3 · Wiring

Three connections to the mainboard. The vendor’s guidance is to put STEP on any spare PWM, RGB or 12864 header (the BL‑Touch servo port is explicitly endorsed) and DIR on a spare limit‑switch header.

SignalM8P pinPhysical portBuffer end
STEPPD12BL‑Touch / servo headerPA5
DIRPF0spare endstop headerPB11
BreakagePF2Z‑STOP headerswitch out

PF2 is free here because Z homes off the Cartographer (endstop_pin: probe:z_virtual_endstop), leaving the physical Z‑STOP port unused. The MDM module connects directly to the buffer, not to the mainboard.

These are the spare ports on this machine

There is nothing special about PD12, PF0 and PF2 — they are simply the headers that happened to be free here. Z homes off the Cartographer, so the physical Z‑STOP port was going unused, and nothing was occupying the BL‑Touch header. Your board will have a different set spare.

Pick whatever suits the signal type — STEP and DIR are plain digital outputs and will work on any free GPIO, and the breakage line needs a switch input with a pull‑up — then change the config to match. A STEP pin does not need to be PWM‑capable; Klipper generates step pulses through its own timing, not a duty cycle.

Check the board, not the comment

Verify pin↔port mapping against your board’s own Klipper config rather than a comment in someone’s printer.cfg. On the M8P V2.0, PC15 and PF0 are BTT’s designated filament sensor ports, PF1 is Motor4’s endstop, and PF2–PF4 are Motor3/2/1 endstops. Guessing costs hours.

4 · Klipper configuration

The step feed

Every value here must mirror your [extruder], not the vendor’s example. If your extruder has no gear_ratio, omit it here too.

[extruder_stepper buffer_monitor]
extruder: extruder
step_pin: PD12              # -> buffer PA5
dir_pin:  PF0               # -> buffer PB11
rotation_distance: 4.637     # matches [extruder] exactly
microsteps: 16
full_steps_per_rotation: 200
# no gear_ratio: the Orbiter's gearing is already inside 4.637
# no enable_pin: there is no driver on the Klipper side

Those four values exist so the buffer can convert the pulse stream back into millimetres. Klipper emits one pulse per microstep of the real extruder; the buffer multiplies by its own steps figure to recover a distance. If the two sides disagree about how much filament one pulse represents, every comparison it makes is wrong by a constant factor — so these must mirror [extruder] exactly, including a gear_ratio if you have one.

The return sensor

[filament_switch_sensor Material_breakage_detection]
switch_pin: ^PF2
pause_on_runout: True
runout_distance: 7.0          # suppress until 7mm has extruded
runout_gcode:
    RESPOND TYPE=echo MSG="Filament breakage detected, print paused"
insert_gcode:
    RESPOND TYPE=echo MSG="Filament inserted, ready to continue printing"
event_delay: 2.0
pause_delay: 2.0
debounce_delay: 2.0

The three delays are not interchangeable. debounce_delay filters electrical chatter on the switch line so a momentary glitch is not read as a break. runout_distance is the useful one: it requires that much further extrusion after the signal before acting, which rides out brief transients during fast moves without hiding a genuine break. event_delay and pause_delay govern how soon the macro runs and how long it waits before parking.

Two traps in the vendor sample

detection_length is not valid here. It belongs to filament_motion_sensor; the switch sensor’s equivalent is runout_distance. Klipper refuses to start if you paste it in.

Drop the PAUSE from runout_gcode. With pause_on_runout: True the pause already happens — the explicit call just logs “Print already paused”.

Arming it at print start

If you use the Mainsail/Fluidd client macros, the sensor is enabled by PRINT_START only when this is set. Left empty — the default — the sensor is never armed and never checked:

[gcode_macro _CLIENT_VARIABLE]
variable_runout_sensor: "filament_switch_sensor Material_breakage_detection"

It also gives you a pre‑print check: if the sensor reads empty, the print aborts with “Filament not detected, Print aborted!” rather than printing air.

5 · Buffer serial configuration

The buffer keeps its own parameters in its own flash. Nothing in printer.cfg reaches them, and they survive nothing if the board is replaced — so record them somewhere version‑controlled.

Connecting

USB from the buffer to the host. It enumerates as a CDC ACM device:

$ ls -l /dev/serial/by-id/
usb-STMicroelectronics_FLY_F072CB_CDC_in_FS_Mode_... -> ../../ttyACM0

$ screen /dev/ttyACM0 115200

Commands

CommandDoes
infoPrint all current parameters
versionFirmware version — MDM needs ≥ V1.1.5
steps nSignal pulses per mm
encoder nFilament distance per encoder pulse (mm)
scale nError tolerance multiplier
timeout nIdle stop time (ms)
speed nFeed speed
accel nFeed acceleration
I nMotor current (mA)
Bare parameter names are setters

Sending encoder with no argument doesn’t query it — it sets it to zero, which silently collapses allow_error to 0.00 and disables detection. Use info to read. Only rt and version are true getters.

What each parameter does

ParameterControlsChoosing a value
stepsPulses per mm of filament Calculated from your extruder — see below. Not a preference.
encodermm of filament per encoder pulse A property of the MDM hardware. Leave at stock unless measured travel disagrees with demand by a constant ratio.
scaleError tolerance multiplier allow_error = encoder × scale. Lower catches blockages sooner but false-triggers on fast moves; higher is forgiving but slower to notice a real jam.
timeoutIdle stop, milliseconds Must exceed the longest gap between extrusions — which is your whole PRINT_START, not a print pause. See gotcha 1.
speedFeed rate ceiling Needs to exceed your peak demand. A 40mm purge at 2mm/s needs very little; compare against actual demand, not the documented default.
accelFeed acceleration Governs how quickly it matches a change in demand. Matters at the start of a move, not during steady extrusion.
IMotor current, mA Raise only if the buffer is stalling under load. Higher current means more heat.

Deriving steps

This is the one value you must calculate, and the shipped default is almost certainly wrong for your extruder:

pulses/mm = (full_steps_per_rotation × microsteps) ÷ rotation_distance

            (200 × 16) ÷ 4.637  =  690.1

$ steps 690.1
set steps succeed! steps=690     # stored as an integer

The shipped default of 916 was 33% off for this extruder. Until it’s set, the buffer is judging every print against the wrong demand figure.

Working values

$ info
encoder_length=1.73            # mm per encoder pulse (stock)
timeout=600000                # see gotcha 1 below
signal_steps=690              # calculated above
speed(mm/s)=60.00
acceleration(mm/s^2)=300.00
allow_error_scale=5.00
allow_error=8.65              # = encoder_length × scale
I_CURRENT=600
DUANLIAO_OUT_STATE=0          # NOT a live output reading

6 · Verification, in order

Each step isolates one link. Doing them out of order wastes time.

  1. Klipper loads

    FIRMWARE_RESTART and confirm no config error. Check QUERY_FILAMENT_SENSOR SENSOR=Material_breakage_detection responds.

  2. The sensor reads both states

    Query with filament loaded, then with it pulled clear of the buffer — you want detected and not detected. Allow for debounce_delay before re‑querying. A reading that never changes is a dead line, not a polarity problem.

  3. A real break pauses the print

    Mid‑print, cut the filament on the spool side of the buffer input. Expect a pause after roughly runout_distance more extrusion, plus pause_delay.

  4. Extrude without faulting

    Hot, idle, M83 then G1 E30 F300. No fault should occur. If it does, the buffer is seeing demand that doesn’t match measured movement — work through the gotchas below before suspecting wiring.

  5. Confirm the extruder is honest

    Mark the filament, disable the sensor so nothing interrupts, command G1 E100 F300, measure. If 100 mm commanded doesn’t give 100 mm delivered, fix that before blaming the buffer — its complaint would be correct.

7 · Gotchas

1 · The idle timeout will bite you

The buffer stops its motor after timeout ms with no trigger. The default is 60 000 — sixty seconds. A typical PRINT_START spends three to four minutes heating, homing, probing and meshing with no extrusion at all, so the buffer falls asleep before the first purge.

The symptom is a false “breakage” roughly twenty seconds into the purge line, on every print, with the toolhead sensor showing high pulling force — the extruder dragging filament through a buffer that isn’t running. Raise it past your start sequence:

$ timeout 600000    # 10 minutes

2 · DUANLIAO_OUT_STATE is not a live reading

It looks like the buffer’s fault output and it is tempting to poll it for diagnostics. It reported 0 throughout confirmed fault events sampled at 1 Hz. Don’t build a diagnosis on it.

3 · Klipper can’t verify the outbound link

STEP and DIR are outputs with no readback, so nothing in Klipper can confirm the buffer is receiving them. To test it, disconnect STEP at the buffer end while the mainboard keeps driving the wire — that distinguishes “buffer is responding” from “interference on the sensor line”. Disconnecting at the mainboard end proves nothing, because it removes both possibilities at once.

4 · Long continuous extrusions are the stress case

Error accumulates within a single sustained move and recovers between moves. Short steps stay under tolerance where one long move won’t. A KAMP line purge — 40 mm in one uninterrupted G1 — is the most demanding thing in the whole start sequence, which is why it surfaces problems nothing else does.

Values above are from a working installation, not from the vendor documentation — several differ. Verify against your own extruder and board before copying.

Leave a Reply

Your email address will not be published. Required fields are marked *