Skip to content

Creality K2 Series

HelixScreen has a cross-compilation target for the Creality K2 series of enclosed CoreXY printers. The K2 series runs Klipper with stock Moonraker, making it a natural fit for HelixScreen.

All K2 models use Allwinner ARM Cortex-A7 dual-core processors running Tina Linux (OpenWrt-based).

ModelBuild VolumeDisplayChamber HeaterCFSStatus
K2260 mm cubed4.3” 480x800NoOptionalUntested
K2 Pro300 mm cubed4.3” 480x800Yes (60C)OptionalUntested
K2 Plus350 mm cubed4.3” 480x800Yes (60C)OptionalUntested
K2 Max350 mm cubed4.3” 480x1600YesYes (combo)Hardware confirmed
K2 SE220x215x245 mmUnknownNoUnknownUser-confirmed install (wget)

Hardware (Confirmed on K2 Max — 2026-03-23)

Section titled “Hardware (Confirmed on K2 Max — 2026-03-23)”
SpecValue
SoCAllwinner sun8iw20p1 (ARM Cortex-A7, dual-core, 57 BogoMIPS)
Display480x1600 portrait, 32bpp, fbdev (/dev/fb0)
Stock UI/usr/bin/display-server (must be stopped to use framebuffer)
RAM488 MB total
Storage27.5 GB on /mnt/UDISK
OSOpenWrt 21.02-SNAPSHOT, Linux 5.4.61 armv7l
Init Systemprocd (OpenWrt-style, NOT systemd)
MCUGD32F303RET6 on /dev/ttyS2 @ 230400 baud
Nozzle MCUGD32F303CBT6 on /dev/ttyS3 @ 230400 baud
MoonrakerPort 7125 (direct), port 4408 (nginx proxy)
Klipper UDS/tmp/klippy_uds
SSHroot / creality_2024 (enable via Settings menu)
Config path/mnt/UDISK/printer_data/config/
Klipper path/usr/share/klipper/
Logs path/mnt/UDISK/printer_data/logs/
Gcode path/mnt/UDISK/printer_data/gcodes/ (also /root/klipper/gcodes/)
Web serverweb-server on ports 80, 443, 9998, 9999
ADBadbd on port 5037
WebRTCwebrtc_local on port 8000 (camera)
  • No curl — BusyBox wget only (no HTTPS support). Use python3 urllib for HTTP requests.
  • armv7l — Dual-core Cortex-A7 (NOT Cortex-A53). Lower performance than K1 series.
  • 480x1600 display — The K2 Max has a taller display than other K2 models (480x800). Needs software rotation to landscape. The lcm_id=gc9503cv_ue_480_800 in cmdline suggests the base panel is 480x800 but the K2 Max may use a different panel.
  • Python 3.9 — Available at /usr/bin/python3.

The K2 target uses Bootlin’s armv7-eabihf musl toolchain with fully static linking. We target armv7 (32-bit) because Tina Linux uses 32-bit userland.

Terminal window
# Build the Docker toolchain and cross-compile (first time only — cached after)
make k2-docker

The Docker image (docker/Dockerfile.k2) downloads Bootlin’s armv7-eabihf musl toolchain (stable-2024.02-1).

Terminal window
make PLATFORM_TARGET=k2 -j
SettingValue
Architecturearmv7-a (hard-float, NEON VFPv4)
Toolchainarm-buildroot-linux-musleabihf-gcc (Bootlin musl)
LinkingFully static (musl)
Display backendfbdev (/dev/fb0)
Inputevdev (auto-detected)
SSLDisabled (Moonraker is local on port 4408)
Optimization-Os with LTO (size-optimized)
Platform defineHELIX_PLATFORM_K2

The K2 target is included in the GitHub Actions release pipeline (.github/workflows/release.yml). Release artifacts are built automatically:

Terminal window
# Manual packaging
make package-k2
  • A Creality K2, K2 Pro, K2 Plus, or K2 Max printer
  • Stock firmware with root access — no custom firmware (Guilouz, etc.) required
  • Root access enabled: Settings > “Root account information” > acknowledge disclaimer > wait 30 seconds > press “Ok”
  • SSH access: ssh root@<printer-ip> (password: creality_2024)
  • Find your printer’s IP: Settings > Network on the printer touchscreen

Important: K2 hostname does NOT resolve via mDNS — always use the IP address.

Terminal window
# 1. Build the K2 binary (Docker — works on any host OS)
make k2-docker
# 2. Deploy and run in foreground (first time — watch the output)
make deploy-k2-fg K2_HOST=192.168.x.x
# 3. For production: deploy in background
make deploy-k2 K2_HOST=192.168.x.x
Terminal window
# Full deploy (binary + assets + config + platform hooks)
make deploy-k2 K2_HOST=192.168.x.x
# Deploy and run in foreground with debug logging
make deploy-k2-fg K2_HOST=192.168.x.x
# Deploy binary only (fast iteration during development)
make deploy-k2-bin K2_HOST=192.168.x.x
# SSH into the printer
make k2-ssh K2_HOST=192.168.x.x
# Full build + deploy + run cycle
make k2-test K2_HOST=192.168.x.x

Deploy directory: /opt/helixscreen (override with K2_DEPLOY_DIR). SSH credentials: root/creality_2024 (override with K2_USER/K2_PASS).

Note: The K2 uses BusyBox (OpenWrt), so deployment uses tar/ssh transfer instead of rsync.

  1. Stops any running HelixScreen processes
  2. Deploys platform hooks (config/platform/hooks-k2.sh/opt/helixscreen/platform/hooks.sh)
  3. Transfers binaries, assets, XML layouts, and config
  4. Installs SysV init script at /etc/init.d/S99helixscreen for boot persistence
  5. Ensures /opt/helixscreen symlink points to /mnt/UDISK/helixscreen
  6. Platform hooks stop the stock Creality UI (display-server, Monitor, etc.) via procd
  7. Platform hooks start wpa_supplicant to replace the stock wifi-server
  8. Starts HelixScreen on the framebuffer

To restore the stock Creality touchscreen:

Terminal window
ssh root@<printer-ip>
killall helix-screen helix-splash helix-watchdog 2>/dev/null
/etc/init.d/app enable # Re-enable stock UI on boot
/etc/init.d/app start # Start stock UI now

HelixScreen renders directly to /dev/fb0. The platform hooks stop the stock display-server to release the framebuffer. This is handled automatically by the deploy targets.

The K2 Max framebuffer is 480x1600 portrait — HelixScreen will need software rotation to landscape mode, plus touch coordinate transform.

HelixScreen uses evdev and auto-detects the capacitive touch controller. Running as root (default) avoids permission issues on /dev/input/event*.

CFS (Creality Filament System) — Full Protocol Reference

Section titled “CFS (Creality Filament System) — Full Protocol Reference”

The CFS is a multi-material filament management system using RS-485 serial communication. Each CFS unit holds 4 spools; up to 4 units can be daisy-chained for 16-color printing.

The CFS is implemented as Klipper modules, but the core logic is in closed-source Cython .so blobs:

ModuleSourceFunction
box.py3-line shimLoads MultiColorMeterialBoxWrapper from box_wrapper.cpython-39.so
box_wrapper.cpython-39.soBinary blob (Cython)All CFS protocol, RFID, motor control, filament state
auto_addr.py3-line shimLoads AutoAddrWrapper from auto_addr_wrapper.cpython-39.so
auto_addr_wrapper.cpython-39.soBinary blobRS-485 device discovery and address assignment
filament_rackKlipper moduleExternal filament rack sensor

From the active box.cfg on the K2 Max:

[serial_485 serial485]
serial: /dev/ttyS5
baud: 230400
[auto_addr]
[filament_rack]
not_pin: !PA5
[box]
bus: serial485
filament_sensor: filament_sensor
Tn_extrude_temp: 220 # Extrusion temperature
Tn_extrude: 140 # Extrusion length
Tn_extrude_velocity: 360 # Extrusion speed
Tn_retrude: -10 # Retraction after cut
Tn_retrude_velocity: 600 # Retraction speed
buffer_empty_len: 30 # Buffer tube reserve length
has_extrude_pos: 1 # Has dedicated purge station
extrude_pos_x: 133 # Purge station X
extrude_pos_y: 378 # Purge station Y
safe_pos_x: 225 # Safe park X
safe_pos_y: 345 # Safe park Y
# ... cut positions, clean positions, etc.
DetailValue
Bus/dev/ttyS5 at 230400 baud
Frame format0xF7 | addr | length | status | function_code | data[] | CRC8
Slave addresses0x01-0x04 (individual CFS units), 0xFE (broadcast boxes), 0xFF (all devices)
CommandsConnect, RFID read, motor control, extrude/retract, version/SN query, sensor queries

The [box] Klipper module exposes full CFS state via Moonraker’s printer.objects.query. This is the primary interface for HelixScreen integration.

Query: GET /printer/objects/query?box

FieldTypeDescription
statestringConnection state: "connect", "None"
filamentintFilament loaded flag (1 = loaded)
enableintCFS enabled for printing
auto_refillintAuto-refill (backup spool) enabled
filament_useupintFilament use-up tracking enabled
mapdictTool-to-slot mapping: {"T1A": "T1A", "T1B": "T1B", ...}
same_materialarrayGroups of slots with matching material for auto-refill

Each CFS unit (T1=unit 1, T2=unit 2, etc.) has:

FieldTypeExampleDescription
statestring"connect" / "None"Unit connection state
filamentstring"None"Currently loaded filament
temperaturestring"27"Internal temperature (C)
dry_and_humiditystring"48"Relative humidity (%)
filament_detectedstring"None"Filament detection state
measuring_wheelstring"None"Measuring wheel state
versionstring"1.1.3"Firmware version
snstring"10000882925..."Serial number
modestring"0"Operating mode
venderarray[4]hex stringsRaw RFID vendor data per slot
remain_lenarray[4]["35","57","52","52"]Remaining filament length (meters) per slot
color_valuearray[4]["0000000","0FFFFFF","00A2989","0C12E1F"]Filament color hex per slot
material_typearray[4]["101001","101001","101001","101001"]Material type code per slot
uuidarrayintsRFID UUID bytes
change_color_numarray[4]["-1","-1","-1","-1"]Color change count per slot

Slots use a T{unit}{letter} naming convention:

  • Unit: 1-4 (CFS unit number)
  • Letter: A-D (slot within unit)
  • Example: T1A = Unit 1, Slot A; T3C = Unit 3, Slot C

The map field maps virtual tool names to physical slots (usually 1:1 unless remapped).

The material_type field uses a format: 1XXXXX where XXXXX is the material database ID.

CodeMaterial
101001Creality Hyper PLA
102001Creality Hyper PLA-CF
106002Creality Hyper PETG
103001Creality Hyper ABS
100001Generic PLA
100003Generic PETG
100004Generic ABS
100005Generic TPU

The full material database is at /mnt/UDISK/creality/userdata/box/material_database.json (77 materials, fetched from Creality cloud). Material entries include brand, name, meterialType (sic — Creality typo), density, diameter, temp range.

Colors are 7-character hex strings with a leading 0: "0RRGGBB". Examples:

  • "0000000" = black
  • "0FFFFFF" = white
  • "00A2989" = teal
  • "0C12E1F" = orange-red

Units that are not connected report all fields as "None" or "-1".

External filament rack (non-CFS) state:

{
"vender": "-1",
"color_value": "-1",
"material_type": "-1",
"remain_material_color": null,
"remain_material_type": null,
"remain_material_velocity": 360
}
{
"motor_ready": true,
"is_homing": false,
"cut": { "state": true, "pos_x": -7.7 }
}
ObjectDescription
fan_feedbackFan speeds: fan0-fan4
filament_switch_sensor filament_sensorFilament runout sensor state
load_aiAI print quality monitoring (waste detection)
heater_generic chamber_heaterChamber heater control
temperature_fan chamber_fanChamber cooling fan (carries the M141 maintain ceiling)
temperature_sensor chamber_tempChamber temperature sensor
motor_controlMotor ready state, cutter position
belt_mdl mdlx / belt_mdl mdlyBelt tension measurement
prtouch_v3Pressure-based Z probe
z_align / z_tiltZ axis alignment
custom_macroCustom macro management
fan_feedbackRPM feedback for all fans

The K2 chamber is controlled by the M141 macro, which coordinates two objects: heater_generic chamber_heater and temperature_fan chamber_fan. HelixScreen routes chamber sets through M141 S{temp} (rather than a raw SET_HEATER_TEMPERATURE), and the macro’s behavior depends on the setpoint:

  • M141 S0Off (heater target 0; cooling fan reset to its configured resting target, e.g. 35°C)
  • M141 S{≤40}Maintaining — holds a cooling ceiling via temperature_fan chamber_fan; the heater target stays 0
  • M141 S{>40}Heating — sets the heater_generic chamber_heater target

Because the heater target reads 0 while maintaining, HelixScreen synthesizes a canonical display target and mode rather than displaying the raw heater target. See MULTI_EXTRUDER_TEMPERATURE.md § Chamber Heating (M141) for the subject/binding details.

GCode Commands (from box_wrapper.so decompilation)

Section titled “GCode Commands (from box_wrapper.so decompilation)”
CommandDescription
BOX_EXTRUDE_MATERIAL TNN=T1ALoad filament from specified slot
BOX_RETRUDE_MATERIALUnload current filament back to CFS
BOX_RETRUDE_MATERIAL_WITH_TNN TNN=T1AUnload specific slot
BOX_EXTRUDER_EXTRUDE TNN=T1AFeed filament to extruder
BOX_MATERIAL_FLUSHPurge/flush filament
BOX_MATERIAL_CHANGE_FLUSHColor-change flush sequence
BOX_EXTRUSION_ALL_MATERIALSPrime all materials
SubcommandDescription
M8200 PPre-operation (prepare for change)
M8200 CCut filament
M8200 RRetract to CFS box
M8200 L I{n}Load slot n (0-15, auto-mapped to TnX)
M8200 WWaste detection
M8200 FFlush/purge
M8200 OEnd operation
CommandDescription
BOX_GET_BOX_STATEQuery overall CFS state
BOX_GET_RFID ADDR={n} NUM={n}Read RFID data for specific slot
BOX_GET_REMAIN_LEN ADDR={n} NUM={n}Query remaining filament length
BOX_GET_FILAMENT_SENSOR_STATEQuery filament sensor states
BOX_GET_HARDWARE_STATUSFull hardware status (RFID cards, humidity, eeprom, measuring wheel)
BOX_GET_BUFFER_STATEBuffer tube state
BOX_GET_VERSION_SNFirmware version and serial number
CommandDescription
BOX_ENABLE_CFS_PRINT ENABLE={0|1}Enable/disable CFS for printing
BOX_ENABLE_AUTO_REFILLToggle auto-refill (backup spool switching)
BOX_SET_BOX_MODESet CFS operating mode
BOX_SET_TEMPSet extrusion temperature
BOX_SET_PRE_LOADING ADDR={n} NUM={n} ACTION=RUNPre-load filament
BOX_START_PRINTSignal print start to CFS
BOX_END_PRINTSignal print end to CFS
BOX_ERROR_CLEARClear CFS error state
BOX_ERROR_RESUME_PROCESSResume after error
CommandDescription
BOX_GO_TO_EXTRUDE_POS (M1500)Move to purge station
BOX_MOVE_TO_SAFE_POS (M1499)Park at safe position
BOX_NOZZLE_CLEAN (M1501)Wipe nozzle on silicone strip
BOX_CUT_MATERIAL (M1502)Activate filament cutter
BOX_MOVE_TO_CUTMove to cut position

Use M8200 for manual load/unload operations. Creality’s BOX_LOAD_MATERIAL macro is buggy — it omits CR_BOX_PRE_OPT which is required before CR_BOX_EXTRUDE, causing key60: Internal error shutdowns.

CommandEffectUnderlying
M8200 PPrepare CFS for material changeCR_BOX_PRE_OPT
M8200 L I={slot}Load filament from slot (0-indexed)CR_BOX_EXTRUDE TNN=...
M8200 CCut filamentCR_BOX_CUT
M8200 RRetract filament (optional E={length})CR_BOX_RETRUDE
M8200 WWaste purgeCR_BOX_WASTE
M8200 FFlush (uses last TNN from L command)CR_BOX_FLUSH
M8200 OEnd material change operationCR_BOX_END_OPT

Load sequence: M8200 PM8200 L I=2M8200 FM8200 O Unload sequence: M8200 PM8200 CM8200 RM8200 O

Prerequisites: Printer must be homed (G28). CFS does not require nozzle heating for feed/retract — heating is only needed for purging at the nozzle.

Stock UI note: Creality’s display-server communicates with the CFS directly over RS-485 (/dev/ttyS5 at 230400 baud), bypassing Klipper entirely for load/unload. The GCode macros are primarily for automated print-time use.

Macro Sequences (from box.cfg — DO NOT use for manual load/unload)

Section titled “Macro Sequences (from box.cfg — DO NOT use for manual load/unload)”
MacroSequenceNotes
BOX_LOAD_MATERIAL TNN=T1AHeat → Cut → Retract → Extrude → Flush → ParkBUG: Missing CR_BOX_PRE_OPT → key60 crash
BOX_QUIT_MATERIALHeat → Cut → Retract → ParkSame issue
BOX_INFO_REFRESHPre-load → Get RFID → Get Remain LenSafe to use

CFS errors are reported as JSON with key8xx codes:

CodeError
key831RS-485 communication timeout
key834Parameter error
key835-key838Extrusion blockages (connections, sensor, gear)
key840Box state error
key841Cut sensor not detected
key843RFID read error
key844Pneumatic joint abnormal
key845Nozzle blocked
key847Empty printing, material enwind
key848Material break at connections
key849-key851Retraction errors
key853Humidity sensor error
key855Cut position error
key856No cutter detected
key857Motor load error
key858EEPROM error
key859Measuring wheel error
key860Buffer error
key861Left RFID card error
key862Right RFID card error
key863-key865Retraction/extrusion completion errors

Internal Classes (from Cython decompilation)

Section titled “Internal Classes (from Cython decompilation)”
ClassPurpose
MultiColorMeterialBoxWrapperMain Klipper module — GCode registration, get_status(), lifecycle
BoxStateTnn_map, Tnn_content, connection tracking, slot state
BoxActionRS-485 commands, RFID reads, motor control, sensor queries
BoxSavePersistence: resume_tnn, error state, save/restore across restarts
BoxCfgConfiguration from box.cfg (positions, velocities, temps)
ParseDataBinary protocol parser: RFID, remain_len, measuring_wheel, CRC8
CutSensorCutter hall sensor monitoring

The CFS exposes state through the standard Moonraker object query interface, similar to AFC and Happy Hare. Integration approach:

  1. Add CFS as a filament backend in AmsState — query box object, map T1-T4 units with A-D slots
  2. Map data fields:
    • color_value → slot color (strip leading 0, parse as hex)
    • material_type → lookup in material database (strip leading 1, match ID)
    • remain_len → remaining filament display
    • temperature / dry_and_humidity → per-unit environmental monitoring
    • state → connection status
  3. Commands: Use M8200 for load/unload (NOT BOX_LOAD_MATERIAL — see M8200 section above)
  4. Auto-detection: Add box to Moonraker object heuristics in printer_database.json

HelixScreen auto-detects K2 printers using heuristics from config/printer_database.json:

HeuristicConfidenceDescription
Hostname k285Hostname contains “k2”
box object90CFS module present (K2-specific)
motor_control object75K2-specific motor control module
fan_feedback object70K2-specific fan RPM feedback
load_ai object65AI print monitoring (K2-specific)
chamber_temp sensor70Chamber temperature sensor
Hostname creality60Hostname contains “creality”
CoreXY kinematics40CoreXY motion system
  • 480x1600 portrait framebuffer (K2 Max) — needs software rotation to landscape. Other K2 models may be 480x800.
  • Closed-source protocol — CFS communication relies on box_wrapper.cpython-39.so binary blob. Protocol has been reverse-engineered from strings but full reimplementation is not yet available.
  • Material database is cloud-fetched — The material database at /mnt/UDISK/creality/userdata/box/material_database.json is downloaded from Creality’s cloud. HelixScreen should include a fallback mapping for common material type codes.
  • Low CPU — Dual Cortex-A7 at ~57 BogoMIPS. Performance-sensitive features (bed mesh 3D, animations) may need throttling.
  • No curl — BusyBox wget only, no HTTPS support.
  • WiFi managed by platform hooks — The stock wifi-server is killed when HelixScreen takes over the display. Platform hooks (hooks-k2.sh) start wpa_supplicant directly using credentials at /etc/wifi/wpa_supplicant/wpa_supplicant.conf. WiFi configuration changes made via the stock UI are preserved.
  • Non-standard control sockethooks-k2.sh launches wpa_supplicant without -O, so the control socket lands at the ctrl_interface= from the stock conf — /etc/wifi/wpa_supplicant/sockets/wlan0 on K2 — not the usual /run/wpa_supplicant. The WiFi backend searches that location (and auto-detects any -O path from the live process), so network discovery works without manual symlinks. Firmware that uses yet another path can be pointed at it via HELIX_WPA_SOCKET_DIR. Surfaced by a community K2 Plus report.