PWM question for the experts here..

I am in need of some way to change a PWM signal coming from my Arduino.
The firmware only allows for PWM settings from 0-255.
What I want to accomplish is this:
With the 0 as the lowest value and 255 the highest for the incoming PWM signal I want to change it to a "smaller bandwidth".
Ok, your are confused according to my crystal ball...
The connected device (here a powerful laser) starts to work at PWM values of 6.
The hardware limit is at around 180 as otherwise the tube will overpower and could be damaged.
But I would like to be able to convert the full input signal to a range equal to being 6 the lowest and let's say 16 the highest.
So the original 0 should, after the conversion, equal to 5, just be sure the laser is off.
And the original 255 should equal to 16.

It seems to be a quite simple task but either my brain does not work today or my friend Google does not like me anymore.
I tried to search through the Marlin firmware but could not find anything simple and obvious to make thes changes directly in the firmware.
So I need something that I can implement into the firmware or something I can put on a little UNO or so that sits between the big Arduino and the laser.

sort by: active | newest | oldest

Use the blink program you can change the duty cycle as well as the frequency.

The code you want to change is the delay (1000);

Then add the pot control.

Downunder35m (author) 1 year ago

Just so you can all see the results of the hard work, check my new Ible.
With the code changes the level of control over the laser power is just incredible.

Downunder35m (author) 1 year ago

First: Thanks everyone for the good ideas!
Second: With all this input I was able locate the offending code in the program.

Josehf with his delay hit me while searching through the code.
Found a quite simple piece of code that limits the input range for the duty cycle.
From there it was just changing a few lines of code to use the analogWriteResolution instead of the old code for a testrun.
This worked quite well on the connected LED but it flickered badly when I added some movement commands - same timers used :(
So now it is simplyfied by a total change of the input limitations and the following calculations for the PWM signal.
Thanks to Turnkey Tyranny for documented it so well and keeping these changes as an option without changing too much code.
But without the feedback from you guys I would still be searching through lines of code, so well done! :)

rickharris1 year ago

You mean you want to scale the signal so that 0 demand =5 output and

255 demand = 180 output?

you can do this with a simple error check before issuing the PWM command

Example: If demand=<5 then PWM=5 (this covers 0 to 5 which will now do nothing but issue a PWM demand of 5

At the other end If demand =>180 then PWM=180 so the actual output will always be between 5 and 180 with slightly reduced resolution.

I must have missed something here.

Downunder35m (author)  rickharris1 year ago

That sounds nice too :)
Does that mean, if I find that code, that with the demand I can literally keep the full pwm resolution but slightly reduced or is it just a "cut off" so to speak?
If working that seems to be the easiest way of manipulating the code for what I need.
Just need to figure out if there are and unused M commands left in Marlin that I can misuse for the limiting values.

I don't think you missed something, I think you could be spot on - if I understand it correctly today.
Only 40° and finnished a 8 hour shift in a factory that was close to 40 before breakfast.
Talking celsius here in case anyone wonders why I was hot and not freezing ;)
So brain is only working at half power here LOL

with my suggestion the output will never go under 5 or over 180 BUT for the first 5 units of demand nothing happens i.e. 5 becomes the 0,1,2,3,4,5

and after 180 nothing happens but i think that is what you want.

I would add that this is why I dislike the Arduino, the users become reliant on existing libraries of routines without necessarily understanding how they work.

The Picaxe system for may purposes is much more accessible.

It has automatic PWM output built in to the firmware and their version of basic is just so much more accessible and intuitive. A logical check such as I have proposed is an obvious way to set upper and lower limits (actually there is even a command to do that but the logic is simple anyway)


readadc, c.1,b1 ' reads the value of input c.1 into word variable B1 (8 bits)

if B1=<5 then B1=5 ' sets B! lower limit

if B1=>180 then B1=80 'sets B1 upper limit

pwm C.4,B1,20 'send 20 pwm bursts out of pin 4

goto start 'loop back to start

The 08M2 costs £1.80 in the UK and can doo the above (and a lot more.

Ausi distributer


-max-1 year ago

Umm, I know what you mean, you only need the PWM signal to map between 6% and 16%, while maintaining the full ADC resolution of the arduino. The PWM generators are actually physical hardware bits, I am not sure if any software can change their range. However, you might be able to to create a software PWM with digitalwrite and delay commands.

Doing that, you may consider replacing the digitalWrite command entirely as it does a lot more than just change the state of a pin, and is notoriously slow. Google the exact ATmega chip you are using and see if you can write to the output registers directly in assembly. You'll need to know what register to shift bits of data into. Be mindful though that the code you write will have to be exceptionally fast, depending on the frequency of PWM. The code below should work on a ATmega8, ATmega168, and presumably a ATmega328.

PORTD = B10101000;

That will sets digital pins 7,5,3, all HIGH simultaneously.

Downunder35m (author)  -max-1 year ago

Your first sentence said it all, could not find the right words ;)
Marlin uses the standard hardware stuff for the PWM generation, GRBL on the other hand uses 0-1000 or in some modded version 0-10000 as the PWM range for spindle control - which is basically the same thing as it drives the laser.

I like your idea of the analog conversion of the Arduino signal, if that could be adapted to do what I want, two pots for low and high level are all that is needed.
A one time calibration for the engraving stuff and if normal operation is required I can disable the enterie analog section with a switch.
But doing it directly in the Marlin code would be even better but I already spent quite a few hours searching through the code to find where the PWM originates so I route it to a custom digital write that can be adjusted.

Will have to do some digging on the weekend, map the Ramps connections used to the actual pins on the arduino and search through the code from there.
Being modified for laser operations it would not surprise me that I did not find anything last.
Realised that it might actually be part of the modified code and if that is the case it is no wonder I am unable to find it in the Marlin parts.
Would like to mark your two answers as similar good but will leave the topic open a bit longer for discussion.
Brainstorming is always better with more than one brain ;)

I personally would go for a discrete mixed-domain hardware solution since you want to use digital signals and get analog outputs. However, I'm not very, well... competent... when it comes to software voodoo. :( I can do the basics, but not anything hugely complicated in a reasonable timeframe lol! I'll stick with what I know lol!

If you get a proper I2C DAC for your microcontroller, you could wire it's output directly in place of the one pot in that analog PWM generator. Because you are converting things over to a voltage value between 0 and 5V, it would be easy to use some resistor divider networks to "map" the values into what you need. The math might be a little hairy but it is not too bad.

You can even make your own R2R DAC if you have a billion resistors!

Just make sure to use an osciloscope to verify that it works correctly. They are tedious to build! But amazingly simple!
-max-1 year ago

If you just want to map values between 0-----255 and limit the range to 5----16, the map(a,b,c,d); function may be useful.

-max-1 year ago

You know what!? Nah, who needs arduino! Op amps, ramp wave oscillator, comparator, and a closed loop analog controller for the WIN! :D


With this, there is no worries about being limited to 255 steps of resolution, analog circuitry is infinitely precise!*

I think something is wrong with your description. Do you mean input range 5..16= output 0..180 ?