Miron Vranješ Product Manager 💡 ⋅ Pilot ✈️ ⋅ Tinkerer 🔬

Compiling Custom Marlin Firmware for Ender 3 v2 with BLTouch

It’s hard to find good tutorials online for how to roll your own Marlin firmware for the Ender 3 v2. It’s actually so easy that anyone can do it! This is a quick guide that takes you through the entire process step-by-step. If this feels overwhelming, I recommend using some of the excellent pre-compiled firmware available.

  1. Get a few important tools:
    1. Git: You don’t need Git, as you can download the source code directly, but it’s nice to have because then you can just pull the latest changes every few weeks and recompile.
    2. VS Code: This is the editor where you’ll make your changes. Simply download it here.
    3. PlatformIO: This is the VS Code extension that compiles the Marlin firmware. You can install it with these simple instructions.
    4. Auto Build Marlin: This is an optional VS Code extension that makes things even simpler to build. You can install it with these simple instructions.
  2. Get the source code.
    1. With Git: Open up a terminal, navigate to the folder you want and type git clone https://github.com/MarlinFirmware/Marlin.git, which will create a new folder called Marlin with all the source code. Navigate to the folder and type in git checkout bugfix-2.0.x to switch to the nightly branch where the Ender 3 v2 is currently supported.
    2. Without Git: Just download the bugfix-2.0.x branch directly and unzip it somewhere.
  3. Open the main Marlin folder in VS Code. Simply go to File -> Open and then find the main folder you either cloned or unzipped.
  4. Configure the platformio.ini file, which is in the main Marlin folder. You just need to change the default_envs (you’ll see it near the top) by writing: default_envs = STM32F103RET6_creality.
  5. You now need to configure the Configuration.h and Configuration_adv.h files for the Ender 3 v2. The examples for the Ender 3 v2 are here. Download them, then navigate to Marlin/Marlin/ (the folder called Marlin inside the main Marlin folder) and completely replace the Configuration.h and Configuration_adv.h that are there.
  6. Almost done! We now just want to do a couple of tweaks. This is really easy, I promise. If you ever wonder what a certain section does, you can read the documentation for Configuration.h here and Configuration_adv.h here. We won’t need to further modify Configuration_adv.h in this tutorial. In VS Code, open up Configuration.h and make the following changes to enable BLTouch (you can just search for the names):
    1. In #define DEFAULT_AXIS_STEPS_PER_UNIT you can change your e-steps default from 93 (it’s the 4th number).
    2. If you want, enable #define S_CURVE_ACCELERATION by removing the //.
    3. You should have all 5 wires of the BLTouch connected to the port rather than using the Z-Stop like older Ender 3 versions. You should disable #define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN by adding // in front of it.
    4. Enable #define USE_PROBE_FOR_Z_HOMING by removing the //.
    5. Enable #define BLTOUCH by removing the //.
    6. Change #define NOZZLE_TO_PROBE_OFFSET { 10, 10, 0 } to the settings for the printed mount. If you use this one from Thingiverse, change to #define NOZZLE_TO_PROBE_OFFSET { -42, -10, 0 }.
    7. You can increase #define XY_PROBE_SPEED 3000 to 10000 to make things a bit faster.
    8. You can enable M48 if you want: #define Z_MIN_PROBE_REPEATABILITY_TEST by removing the //.
    9. Enable #define DELAY_BEFORE_PROBING 200 by removing // and change to 100 to keep things snappy.
    10. I like to change the bed size to #define X_BED_SIZE 230 and #define Y_BED_SIZE 230.
    11. Enable #define AUTO_BED_LEVELING_BILINEAR by removing //. You could also use #define AUTO_BED_LEVELING_UBL.
    12. You can enable #define RESTORE_LEVELING_AFTER_G28 so you don’t have to re-enable bed leveling after homing.
    13. You can enable #define G26_MESH_VALIDATION to let you print quick bed leveling test patterns. Set the variables below it to whatever settings you normally use.
    14. If you’re using bilinear, you can change the amount of points to use (e.g., 3x3 or 5x5) by modifying #define GRID_MAX_POINTS_X 3 to 5 or more.
    15. Enable #define Z_SAFE_HOMING by removing //.
    16. If you want to change your default temps, you can change the variables under #define PREHEAT_1_LABEL "PLA".
  7. If you want to mess with the LCD, you can open up dwin.cpp in Marlin/Marlin/src/lcd/dwin/. I modified #define MACHINE_SIZE "220x220x250" to "230x230x250" and you can also mess with some stuff like #define CORP_WEBSITE_E.
  8. Save all the changes, click on the “M” button on the left-hand side for the Auto Build Marlin extension and then click the little hammer icon to build. Check some stuff:
    1. Firmware should be “Marlin bugfix-2.0.x”.
    2. Machine Name should be “Ender-3 V2” with “Cartesian 230x230x250mm with Heated Bed (1)”.
    3. Environments should be “STM32F103RET6_creality”.
  9. The firmware file is located in a hidden folder in the main Marlin folder. Enable hidden folders and navigate to Marlin/.pio/build/STM32F103RET6_creality/. You’ll see a file called firmware-[date]-[time].bin where [date] and [time] changes depending on when you build it. This is handy because the Ender 3 v2 will ignore firmware if it has the same name.
  10. Copy the firmware file to an SD Card, put it in the Ender 3 v2, and turn it on. The LCD screen should be black for a bit and then it should boot up with your new firmware!

That should be it. You can configure your BL Touch using this excellent guide from a fellow Redditor. In general, you can use M119 to check the status of the BL Touch and play around with M280 P0 S10 to deploy, M280 P0 S90 to retract, and M280 P0 S60 and M280 P0 S160 to enter/exit test mode.

If you want to use the fancy UBL vs. just bilinear, enable it per the instructions above. You then need to make some changes:

  1. UBL enables you to do a very detailed leveling and then adjust it quickly with each print. You can also use OctoPrint to set this up, basically the sequence to wire up to a command is:

    M140 S60 ; Warm bed to 60C.
    M190 S60 ; Wait until bed is warm so we're more accurate.
    G28 ; Home XYZ.
    G29 P1 ; Do automated probing of the bed.
    G29 P3 ; Fill in the rest.
    G29 S1 ; Save UBL mesh points to EEPROM in Slot 1.
    G29 F 10.0 ; Set Fade Height for correction at 10.0 mm.
    G29 A ; Activate the UBL System.
  2. You should be able to wire up the “Level” button in the LCD to do the same thing. Just open up dwin.cpp, find queue.inject_P(PSTR("G28O\nG29")); and change it to queue.inject_P(PSTR("M140 S60\nM190 S60\nG28\nG29 P1\nG29 P3\nG29 S1\nG29 F10\nG29 A"));.
  3. Now that you have the main leveling done, you want to do a quick 3-point level before each print in Cura’s settings:

    ; Ender 3 Custom Start G-code
    M140 S{material_bed_temperature_layer_0} ; Set Heat Bed temperature`
    M190 S{material_bed_temperature_layer_0} ; Wait for Heat Bed temperature`
    M104 S160; start warming extruder to 160`
    G28 ; Home all axes
    G29 A ; Activate the UBL System.
    G29 L1 ; Load UBL
    G29 J ; Quick 3-point level
    G29 F10.0 ; Fade to 10mm
    G92 E0 ; Reset Extruder
    M104 S{material_print_temperature_layer_0} ; Set Extruder temperature
    G1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position
    M109 S{material_print_temperature_layer_0} ; Wait for Extruder temperature
    G1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed
    G1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line
    G1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little
    G1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line
    G92 E0 ; Reset Extruder
    G1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed
    ; End of custom start GCode

Hope this helps!

I originally published this as a Reddit post.