How-To: Modify Marlin to control a laser with an SKR Pro

Here’s a how-to on getting a diode laser going with an SKR PRO and Ryan’s Marlin fork firmware.

I’m using dual endstops, so the following is based on https://github.com/Allted/Marlin/tree/V1CNC_SKR_Pro_Dual

There are three ways you can control a laser via G-code:

  1. Using the fan control to instead control the laser via M106 and M107 fan speed commands. Often re-assigning the high voltage fan pin to a logic voltage pin (via Marlin)
  2. Using the spindle speed M3/M4 for laser control. Instead of controlling spindle speed via M3, you control laser power.
  3. Using spindle speeds integrated into the G1 move commands. The “S” parameter of the G1 move command can be used to control laser power during that move.

Lightburn seems to support all of the above.

Number 3 above seems to run the smoothest for me. The others seemed to have a lot of stuttering.

For either method I’ll use the PWM output pin available on the 14 pin “EXPANSION-1” header, pin 4, a.k.a top row, 2nd from the left when the USB is pointing at you. This pin is also known as PC9. The logic pins on the STM32 are 3.3V. 3.3V was enough to fire my banggood laser, though I think it’s officially rated for 5V inputs.


I assume you know how to build firmware and get it to the board. Try building without any changes before you attempt any of the following.

First thing is it seems the STM32 platform has no good way for Marlin to determine if a pin is PWM capable or not. If you start enabling pins for laser you might get the following sort of compile/build error:

Compiling .pio/build/BIGTREE_SKR_PRO/src/src/HAL/STM32/HAL.cpp.o
In file included from /Users/rob/.platformio/packages/framework-arduinoststm32/cores/arduino/Arduino.h:48,
                 from Marlin/src/HAL/STM32/../shared/Marduino.h:36,
                 from Marlin/src/HAL/STM32/HAL.h:28,
                 from Marlin/src/HAL/STM32/HAL.cpp:25:
/Users/rob/.platformio/packages/framework-arduinoststm32/cores/arduino/pins_arduino.h:254:51: error: missing binary operator before token "("
  254 | #define digitalPinHasPWM(p)         (pin_in_pinmap(digitalPinToPinName(p), PinMap_PWM))
      |                                                   ^
Marlin/src/HAL/STM32/fastio.h:83:33: note: in expansion of macro 'digitalPinHasPWM'
   83 | #define PWM_PIN(P)              digitalPinHasPWM(P)
      |                                 ^~~~~~~~~~~~~~~~
Marlin/src/HAL/STM32/../../inc/SanityCheck.h:2912:12: note: in expansion of macro 'PWM_PIN'
 2912 |     #elif !PWM_PIN(SPINDLE_LASER_PWM_PIN)
      |            ^~~~~~~

What worked for me is to just disable PWM pin checking in Marlin by changing Marlin/src/HAL/STM32/fastio.h

diff --git a/Marlin/src/HAL/STM32/fastio.h b/Marlin/src/HAL/STM32/fastio.h
index c17901fa9..4c31818f3 100644
--- a/Marlin/src/HAL/STM32/fastio.h
+++ b/Marlin/src/HAL/STM32/fastio.h
@@ -80,7 +80,8 @@ void FastIO_init(); // Must be called before using fast io macros
 #define IS_INPUT(IO)
 #define IS_OUTPUT(IO)

-#define PWM_PIN(P)              digitalPinHasPWM(P)
+#define PWM_PIN(P) true
+#define NO_COMPILE_TIME_PWM

 // digitalRead/Write wrappers
 #define extDigitalRead(IO)    digitalRead(IO)

This issue may also have fixed it: https://github.com/MarlinFirmware/Marlin/pull/18539 …but Ryan hasn’t pulled that change into his fork yet.

Now, onto configuring pins for laser control.

Method 1 - M106/M107

If your laser can take 12V on it’s PWM control input maybe you don’t need to switch to a pin that is 5V and use the FAN0 output as-is.
Change the fan 0 pin in Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h

diff --git a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
index 42e3f1fac..3896da35f 100644
--- a/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
+++ b/Marlin/src/pins/stm32f4/pins_BTT_SKR_PRO_common.h
@@ -230,7 +230,7 @@
 #define HEATER_1_PIN                        PD14  // Heater1
 #define HEATER_2_PIN                        PB0   // Heater1
 #define HEATER_BED_PIN                      PD12  // Hotbed
-#define FAN_PIN                             PC8   // Fan0
+#define FAN_PIN                             PC9   // Fan0
 #define FAN1_PIN                            PE5   // Fan1
 #define FAN2_PIN                            PE6

Method 2 - M3/M4 control

I believe the method below will work for this as well

Method 3 - G1 move spindle speed control.

I think you have to pick an enable pin or you’ll get errors, I picked PC1, though I don’t use it.

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 725f39201..c90a5784f 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -2835,9 +2835,11 @@
  * See https://marlinfw.org/docs/configuration/laser_spindle.html for more config details.
  */
 //#define SPINDLE_FEATURE
-//#define LASER_FEATURE
+#define LASER_FEATURE
 #if EITHER(SPINDLE_FEATURE, LASER_FEATURE)
-  #define SPINDLE_LASER_ACTIVE_HIGH     false  // Set to "true" if the on/off function is active HIGH
+  #define SPINDLE_LASER_ENA_PIN PC1
+  #define SPINDLE_LASER_PWM_PIN PC9
+  #define SPINDLE_LASER_ACTIVE_HIGH     true   // Set to "true" if the on/off function is active HIGH
   #define SPINDLE_LASER_PWM             true   // Set to "true" if your controller supports setting the speed/power
   #define SPINDLE_LASER_PWM_INVERT      false  // Set to "true" if the speed/power goes up when you want it to go slower

@@ -2931,7 +2933,7 @@
       /**
        * Include laser power in G0/G1/G2/G3/G5 commands with the 'S' parameter
        */
-      //#define LASER_MOVE_POWER
+      #define LASER_MOVE_POWER

       #if ENABLED(LASER_MOVE_POWER)
         // Turn off the laser on G0 moves with no power parameter.

I don’t claim to be a laser expert, but the above seemed to get me rolling enough to burn a raster image of when I tortillaed my poor cat Cooter.

4 Likes

Can you tell us what laser you are using?

Thanks.

After watching: https://youtu.be/3Qz-uDx9PhA I bought one of those. https://www.banggood.com/450nm-5W-Laser-Engraving-Module-Blue-Light-With-TTL-Modulation-p-1337358.html?cur_warehouse=USA

I hesitate to recommend it since it’s a bit dangerous in that if you don’t ground the input pin (leave it floating) the thing turns on full blast. Even connected to the SKR Pro pin at logic 0 it won’t turn off, you have to have a ~2.2K pulldown resistor to ground at all times. Also the dot pattern is more of a dash than a dot (zoom in on the cat in the tortilla). Supposedly overrated (power) lasers do that.

Do you know if your starting firmware will work with the 2209 drivers. My starting firmware is:

https://github.com/V1EngineeringInc/MarlinBuilder/releases/download/505/V1CNC_SkrPro_Dual_2209-2.0.6.1-src.zip

and of course it is different than your example.

I tried starting with your firmware but I need a little more clarification.

If I was going to setup the firmware exactly like you, I would only change code from method three and ignore everything else?

Look for:

#define X_DRIVER_TYPE  TMC2209
#define Y_DRIVER_TYPE  TMC2209
#define Z_DRIVER_TYPE  TMC2209
#define X2_DRIVER_TYPE TMC2209
#define Y2_DRIVER_TYPE TMC2209
//#define Z2_DRIVER_TYPE A4988
//#define Z3_DRIVER_TYPE A4988
//#define Z4_DRIVER_TYPE A4988
#define E0_DRIVER_TYPE TMC2209

in Marlin/Configuration.h. That driver is Ryan’s default for the SKR boards

Is this correct?

Secondly, once the modifications to the firmware are made, do you have to use light burn to verify they are working if you are using method 3? (To clarify you cannot use the touchscreen laser menu to bump the fan percentage up and down correct?)

I believe that’s correct. I don’t think the fan control would work to tweak the laser, right. You could enter manual gcode in the TFT GUI if you have one, or create your own gcode file for testing. I think I have one that burns a little square, I’ll try to find it later.