Please or Register to create posts and topics.

PWM Problem with G codes


I recently got a K40 CO2 machine, and I compiled the SuperGerbil to work over a STM32F103C8. Everything seems to work fine with the PWM, except when I use, for example, the G1 code to move the head. What happens is that the PWM is very low, even setting the maximum power using the S255. What I did to check it works correctly is:

1- After reset, it is homing OK. In "Capture1" you can see the Laser Enable from the power source (green trace) and the PWM (blue trace)
2- Then I send M3. Same oscilloscope capture, since the spindle is S0 by default
3- Then I send S1. In "Capture2" you can see the PWM, where I defined the SPINDLE_PWM_MIN_VALUE to get the minimum laser ionization. The "Capture 3" shows the PWM of the S250 command. For these tests I set the laser mode off ($32=0), and the S-value max set to 255 ($30=255)

So, at this point we already know the PWM is working. Next steps:

4- Then I send "G1 X10 S128 F100". So I would expect the laser to move 10mm with a PWM of 50%. But What I get is a PWM even lower than the SPINDLE_PWM_MIN_VALUE! See "Capture4". I thought it might be the power adaptation because of the acceleration, but it keeps the same PWM all the entire 10mm, moving really slow at 2mm/s. I tried to debug the code, but I couldn't.

As fas as I could check, the PWM is calculated in the method "spindle_compute_pwm_value", of the file "spindle_control.c", in line:

pwm_value = (SPINDLE_PWM_TYPE)floorf((rpm - settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;

so, unless "rpm" becomes negative, I don't understand how the PWM can be lower than SPINDLE_PWM_MIN_VALUE...

The strange thing is that when I send a M3 command, the PWM jumps to 50% like expected. I hope it's just a configuration issue, but it's getting me crazy.

Have you any idea about what it might be happening?


Uploaded files:
  • Capture1.png
  • Capture2.png
  • Capture3.png
  • Capture4.png

Hi, the PWM is 16 bits and not 8 bits. So may be that's where the problem is. Set $30 = e.g. 1000 and repeat the scope tests.


cheers, Paul

Hi Paul,

Thanks for you fast response. I already did the test, but I just went back to 255 when it didn't work, because the original code was written in 8 bits, so I just wanted to make sure there was no truncated values in the way.

Actually, just as a comment, the default SPINDLE_PWM_FREQUENCY  in "cpu_map.h" was 10kHz, but with the timer working @ 1MHz (prescaler of 71) there are just 100 different values available in the TIM1->CCR1 register (i.e. AAR register), making it even worse than a 8 bits PWM. Since the rpm in a laser module has no meaning, I just set the PWM frequency to 500Hz (to get 2000 different values, almost 11 bits of resolution), and then I also set $30=2000 to match it. So, I have 2000 different real power states. Despite all this, I also tried the default 10kHz PWM frequency, and there is the same problem.

Anyway, I'm just trying to simplify as maximum as possible to test it, but I run out of ideas 🙁  I'm gonna try to debug the code, it would be really helpful to know which rpm value I receive in the "spindle_compute_pwm_value" method, but I have problems with CooCox and the ST-Link GDB server... I guess I can use the same USB serial port to send data in debug mode, since for these simple tests I'm just using Realterm instead of LightBurn.


Hi Paul,

I found the problem, but I don't understand which version I got... The problem was:

uint16_t spindle_pwm; // uint8_t spindle_pwm;

I don't know why, I had a version where the spindle_pwm was set as uint8_t. I see your code is OK, I will download your code and readapt it for my machine, since I don't know what else might be wrong.

Thank you,

User registration or Edit user profile