This workflow contains configuration settings, software dependencies,
and application notes for building and flashing
Klipper Firmware
Klipper firmware
on Ender3 V3 SE
3D printer.
Introduction
The Klipper
firmware is designed to run on resource constrained
consumer grade 3D printers. The firmware is capable of splitting
its workload between the system board and an external hardware.
The local workload consists of running real-time low-level stepper-motor commands and managing sensor data.
The external hardware is expected to handle computationally intensive tasks. Motion planning, kinematics calculations, and other resource hogging tasks are offloaded by the firmware to the external device. Communication between the external device and the Klipper firmware is carried out via USB,UART, or CAN protocols.
Klipper's client-server like firmware architecture opens up possibilities for implementing advanced 3D printing features and squeezing performance out of consumer grade printers. It should be noted, however, the performance gain is still bounded by the printer hardware capabilities.
Requirements
The software and hardware requirements are,
- A Linux machine running
GNU/Guix
,git
, andLitDoc
is expected. - A copy of distroconfig project with its root directory added
to
LITDOC_PATH
environment variable. - A 3D printer(Ender 3 V3 SE)
- 4GB - 8GB SD card for flashing the firmware
Installation
First, grab a copy of the Klipper
firmware source code,
git clone https://github.com/klipper3d/klipper.git
Switch to the source directory,
cd klipper
And build the firmware by running this workflow(document),
guix ld klipper-firmware
If all goes well, the Klipper firmware should be available
under klipper/out
directory.
./out
|_ klipper.bin
|_ klipper.elf
|_ ...
klipper.bin
is the binary file, which contains
a memory mapped image of the firmware.
To flash the klipper.bin
file to an SD card,
first the card needs to be formatted using FAT32
file format. In general, it is recommended to use
a 4GB - 8GB SD card with 32KB cluster size. This can be done
using a graphical tool such as gparted
or a shell command.
sudo mkfs.fat /dev/[DEVICE NAME] -s 64 -F 32
The device name, [DEVICE NAME],
can be identified using
lsblk
command first without inserting the SD card
and after to resolve its name.
Once the device is formatted, copy the klipper.bin
file
to the SD card.
cp ./out/klipper.bin /media/[DEVICE-NAME]
To flash the Ender 3 V3 SE
board, first turn off the printer
and insert the SD card. Leave the printer on for approximately
30 seconds until the firmware is installed. After the wait,
turn off the printer again and remove the SD card before powering
it back up. If the firmware is successfully installed, on the
next power up a blank blue screen should be visible instead of
the stock Marlin firmware UI.
Build Instruction
This section details the build instruction used by this workflow.
First clone the Klipper repository as specified in the installation
section. Then run the build using litdoc
as shown below,
guix ld klipper-firmware
The build command spawns a GNU/Guix container environment, configures the Klipper source for cross-compilation, and finally builds the firmware binaries.
The part that instruct LitDoc
to spawn a container is specified using a LitDoc
container.opt
source block
A container.opt
is a LitDoc source block, which is used for passing command-line arguments to
guix package
and guix shell
commands.
--container
We also add --emulate-fhs
and --writable-root
options to the block
to enable emulation of a standard Linux file-system structure with write
permission. This will ensure build tools that depend on these features
behave as expected.
--emulate-fhs
--writable-root
Software packages required by the build process are specified using
a manifest block. For the Ender3 V3 SE
the required manifest specification
is,
(use-modules (guix packages)
(guix profiles)
(gnu packages commencement)
(gnu packages embedded) ;; arm-none-eabi-toolchain
(gnu packages cross-toolchain) ;; gcc-cross-avr-toolchain
(gnu packages base) ;; binutils coreutils make
(gnu packages version-control) ;; git
(gnu packages bash) ;; bash
(gnu packages python));; python-2.7 python-3.10
(packages->manifest (list
binutils
coreutils
gnu-make
bash
git
gcc-toolchain
gcc-cross-avr-toolchain
(make-arm-none-eabi-toolchain-7-2018-q2-update)
(make-newlib-nano-arm-none-eabi-7-2018-q2-update)
python-2.7
python-3.10))
To prepare the source code for cross-compilation run
make menuconfig
This is an interactive configmenu based script. The script is
used to generate printer board specific hardware configuration
settings. For the Ender3 V3 SE
printer the configuration menu
collects the following parameters,
Configuration Key | Configuration Value |
---|---|
Micro-controller Architecture | STMicroelectronics STM32 |
Processor Model | STM32F103 |
Bootloader Offset | 28KiB |
Communication Interface | Serial (on USART1 PA10/PA09) |
The collected information is used to generate a firmware build configuration file shown below,
CONFIG_LOW_LEVEL_OPTIONS=y
# CONFIG_MACH_AVR is not set
# CONFIG_MACH_ATSAM is not set
# CONFIG_MACH_ATSAMD is not set
# CONFIG_MACH_LPC176X is not set
CONFIG_MACH_STM32=y
# CONFIG_MACH_HC32F460 is not set
# CONFIG_MACH_RPXXXX is not set
# CONFIG_MACH_PRU is not set
# CONFIG_MACH_AR100 is not set
# CONFIG_MACH_LINUX is not set
# CONFIG_MACH_SIMU is not set
CONFIG_BOARD_DIRECTORY="stm32"
CONFIG_MCU="stm32f103xe"
CONFIG_CLOCK_FREQ=72000000
CONFIG_SERIAL=y
CONFIG_FLASH_SIZE=0x10000
CONFIG_FLASH_BOOT_ADDRESS=0x8000000
CONFIG_RAM_START=0x20000000
CONFIG_RAM_SIZE=0x5000
CONFIG_STACK_SIZE=512
CONFIG_FLASH_APPLICATION_ADDRESS=0x8007000
CONFIG_STM32_SELECT=y
CONFIG_MACH_STM32F103=y
# CONFIG_MACH_STM32F207 is not set
# CONFIG_MACH_STM32F401 is not set
# CONFIG_MACH_STM32F405 is not set
# CONFIG_MACH_STM32F407 is not set
# CONFIG_MACH_STM32F429 is not set
# CONFIG_MACH_STM32F446 is not set
# CONFIG_MACH_STM32F765 is not set
# CONFIG_MACH_STM32F031 is not set
# CONFIG_MACH_STM32F042 is not set
# CONFIG_MACH_STM32F070 is not set
# CONFIG_MACH_STM32F072 is not set
# CONFIG_MACH_STM32G070 is not set
# CONFIG_MACH_STM32G071 is not set
# CONFIG_MACH_STM32G0B0 is not set
# CONFIG_MACH_STM32G0B1 is not set
# CONFIG_MACH_STM32G431 is not set
# CONFIG_MACH_STM32G474 is not set
# CONFIG_MACH_STM32H723 is not set
# CONFIG_MACH_STM32H743 is not set
# CONFIG_MACH_STM32H750 is not set
# CONFIG_MACH_STM32L412 is not set
# CONFIG_MACH_N32G452 is not set
# CONFIG_MACH_N32G455 is not set
# CONFIG_MACH_STM32F103x6 is not set
CONFIG_MACH_STM32F1=y
CONFIG_HAVE_STM32_USBFS=y
CONFIG_HAVE_STM32_CANBUS=y
# CONFIG_STM32F103GD_DISABLE_SWD is not set
CONFIG_STM32_DFU_ROM_ADDRESS=0
# CONFIG_STM32_FLASH_START_2000 is not set
# CONFIG_STM32_FLASH_START_5000 is not set
CONFIG_STM32_FLASH_START_7000=y
# CONFIG_STM32_FLASH_START_8000 is not set
# CONFIG_STM32_FLASH_START_8800 is not set
# CONFIG_STM32_FLASH_START_9000 is not set
# CONFIG_STM32_FLASH_START_10000 is not set
# CONFIG_STM32_FLASH_START_800 is not set
# CONFIG_STM32_FLASH_START_1000 is not set
# CONFIG_STM32_FLASH_START_4000 is not set
# CONFIG_STM32_FLASH_START_0000 is not set
CONFIG_STM32_CLOCK_REF_8M=y
# CONFIG_STM32_CLOCK_REF_12M is not set
# CONFIG_STM32_CLOCK_REF_16M is not set
# CONFIG_STM32_CLOCK_REF_20M is not set
# CONFIG_STM32_CLOCK_REF_24M is not set
# CONFIG_STM32_CLOCK_REF_25M is not set
# CONFIG_STM32_CLOCK_REF_INTERNAL is not set
CONFIG_CLOCK_REF_FREQ=8000000
CONFIG_STM32F0_TRIM=16
# CONFIG_STM32_USB_PA11_PA12 is not set
CONFIG_STM32_SERIAL_USART1=y
# CONFIG_STM32_SERIAL_USART1_ALT_PB7_PB6 is not set
# CONFIG_STM32_SERIAL_USART2 is not set
# CONFIG_STM32_SERIAL_USART2_ALT_PD6_PD5 is not set
# CONFIG_STM32_SERIAL_USART3 is not set
# CONFIG_STM32_SERIAL_USART3_ALT_PD9_PD8 is not set
# CONFIG_STM32_CANBUS_PA11_PA12 is not set
# CONFIG_STM32_CANBUS_PA11_PB9 is not set
# CONFIG_STM32_MMENU_CANBUS_PB8_PB9 is not set
# CONFIG_STM32_MMENU_CANBUS_PD0_PD1 is not set
CONFIG_SERIAL_BAUD=250000
CONFIG_USB_VENDOR_ID=0x1d50
CONFIG_USB_DEVICE_ID=0x614e
CONFIG_USB_SERIAL_NUMBER="12345"
CONFIG_WANT_ADC=y
CONFIG_WANT_SPI=y
CONFIG_WANT_SOFTWARE_SPI=y
CONFIG_WANT_I2C=y
CONFIG_WANT_SOFTWARE_I2C=y
CONFIG_WANT_HARD_PWM=y
CONFIG_WANT_BUTTONS=y
CONFIG_WANT_TMCUART=y
CONFIG_WANT_NEOPIXEL=y
CONFIG_WANT_PULSE_COUNTER=y
CONFIG_WANT_ST7920=y
CONFIG_WANT_HD44780=y
CONFIG_WANT_ADXL345=y
CONFIG_WANT_LIS2DW=y
CONFIG_WANT_MPU9250=y
CONFIG_WANT_ICM20948=y
CONFIG_WANT_THERMOCOUPLE=y
CONFIG_WANT_HX71X=y
CONFIG_WANT_ADS1220=y
CONFIG_WANT_LDC1612=y
CONFIG_WANT_SENSOR_ANGLE=y
CONFIG_NEED_SENSOR_BULK=y
CONFIG_CANBUS_FREQUENCY=1000000
CONFIG_INLINE_STEPPER_HACK=y
CONFIG_HAVE_STEPPER_OPTIMIZED_BOTH_EDGE=y
CONFIG_WANT_STEPPER_OPTIMIZED_BOTH_EDGE=y
CONFIG_INITIAL_PINS=""
CONFIG_HAVE_GPIO=y
CONFIG_HAVE_GPIO_ADC=y
CONFIG_HAVE_GPIO_SPI=y
CONFIG_HAVE_GPIO_I2C=y
CONFIG_HAVE_GPIO_HARD_PWM=y
CONFIG_HAVE_STRICT_TIMING=y
CONFIG_HAVE_CHIPID=y
CONFIG_HAVE_BOOTLOADER_REQUEST=y
Notice, the generated configuration is independent of the
hardware/software the build is running on. The configuration
can be reused for subsequent builds. This is especially
useful when generating build configurations non-interactively.
Therefore, save the build configuration for future reference to
a file. For example, ${LITDOC_CACHE_DIR}/klipper-firmware/etc/e3v3se.config
To reuse the configuration make sure the file can be accessed
within the build container. This is done by adding to container.opt
block
a file --expose
option.
--expose=${LITDOC_CACHEDIR}/klipper-firmware/etc/e3v3se.config=/opt/klipper-firmware/config/e3v3se.config
Any subsequent build that does not introduce a hardware change can now be configured using,
#!/usr/bin/env sh
make clean
make distclean
cp "/opt/klipper-firmware/config/e3v3se.config" .config
make olddefconfig
Once the source code is configured for cross-compilation
the firmware can be built by running make
.
make V=1
If all is good, the build should generate the Klipper firmware binary for the
Ender3 V3 SE
. A copy of the firmware binary file should be available under
the output directory, ./out
.