No announcement yet.

SoftPWM vs analogWrite

  • Filter
  • Time
  • Show
Clear All
new posts

    SoftPWM vs analogWrite

    Hi Greig,

    Today I sort of solved a problem that's been bugging me with the Arduino plugin for a while, but which has sat on the back burner.

    I am using my Arduino to send PWM dimming control to meanwell LDD-H constant current LED drivers.

    One of the specifics of this driver is that it requires a PWM signal between 100Hz and 1kHz. In my testing I've found going over the 1kHz upper limit seems to cause no issue, but going under the 100Hz lower limit introduces a noticeable and irritating flicker.

    When I dim using an Arduino being controlled by the HS3 plugin I get exactly this flicker. For a long while I couldn't understand why, as to the best of my knowledge the PWM pins of an Arduino operated well above 1kHz.

    Tonight I finally understand, it's the PWM library being used. Rather than call "analogWrite", which would set a PWM duty cycle on a hardware PWM pin, the plugin is using the SoftPWM library instead.

    The advantage of SoftPWM is pretty clear:

    - It enables the PWM fade function
    - It allows any pin to be set as a PWM output, not just the "hardware" PWM pins.

    BUT, the default frequency of SoftPWM is only 30Hz, fine for a small diode perhaps, definitely not fine for overhead lighting.

    The library allows for higher frequencies to be set using SoftPWMBegin(). I see this being used in the ino file,under EEPROMSetup. But, if I try to insert a value in the parenthesis, the plugin behaves strangely after upload:

    - "Full" and "Off" are reversed, and the slider acts in reverse.
    - The flicker is still present, as if the config change made no difference to the frequency.

    I've 'sort of' solved the issue as I said, by replacing "SoftPWmSet" with "analogWrite" in the p case statement under Data Input. This actually works and I can now dim without flicker, hooray!

    What I miss out on though, is the PWM fade time. All dimming changes happen instantly and can be a little jarring. There is no smooth transition, which for domestic lighting, is a pretty desirable feature.

    So, my question, is it at all possible to configure SoftPWM for a base frequency above 100Hz? If so, where should I put this and what am I doing wrong?

    I'm using an Arduino Mega 2560 with an Ethernet shield (5100).

    Thanks for your time.

    That describes exactly my issue. I also see this flickering and definitely I would like to retain the fade in/out for light. So if the frequency can be increased that would be very helpful to avoid the fairly strong flickering.


      I was looking into this again as the flicker is rather annoying. Basically, it makes dimming useless. Since the plugin uses the SoftPWM library I also looked at that code. It turns out there is a SOFTPWM_OCR which be default is set to 130 resulting in 60Hz switching. So I decreased this down to 65 which should double the frequency to 120Hz. However, I haven't noticed any difference. I did some more googling and people claim that if the default value results in flickering then something else is going on the code that uses the library (interrupts and such). Has anybody any idea if that is correct and if so how it can be fixed? Or has somebody found a solution that allows the fade in/out.

      Edit: So I commented some stuff out from the loop function that I don't need. It got to the point where I literally removed everything so that the loop function is EMPTY as in void loop(){}. Yet the plugin still does what it is supposed to do including the flickering. I guess the SoftPWM library does everything with timers/interrupts but how can the plugin even receive commands to modify PWM pins? Once I figure that out I can try to remove what I don't need there.


        Hi mulu , what are you trying to dim, an AC socket with an off the shelf lightbulb? Or a DC driver?

        If the latter (which is what I do) something you might consider is switching to hardware PWM (ie calling analogWrite), and using a script to perform dimming operations. This is what I eventually did, the script essentially loops, increasing/decreasing in 1% increments and putting a ~30ms sleep in between each loop.

        This works just fine, though the downsides are:

        - More complexity in event creation, though once you've written the script once, passing in different variables for device ID and target value isn't too bad.
        - Reduced number of pins available for use, as not every pin on an Arduino can perform hardware PWM/analogWrite(). On a AT2560 Mega, I believe only 10 pins can be used this way. (Ethernet shield prevents use of some)


          I am controlling LED strip lights. The script sounds interesting. I didn't think it would be fast enough to do fade in/out but I guess you got it to work,. Would you mind sharing the script? Having said that, it probably won't work for me because I have a nano.which only has 6 PWM pins and on top of that I can't even access all of those. So I really need to get this to work in software which should be very doable. I might have to write my own software but since the Arduino plugin already has this functionality I really hopped that some optimizations can be done to make it work properly as others seem to have the same issue. Haven't seen any input from the plugin owner.


            Ok, I have this another shot and finally got it working. No changes to the Arduino code from the Arduino plugin is necessary. Instead I had to edit the SoftPWM.cpp file. I previously tried to change the frequency with no effect. Turns out the Arduino Nano is an F_CPU so I edited the wrong part. I exchanged

            #define SOFTPWM_FREQ 60UL with
            #define SOFTPWM_FREQ 100UL.

            So this worked if my fade in/out time was less than about 2100 but above that the light would turn on/off instantly. It turns out that when increasing the frequency the step size increase became 0 when in fact it shouldn't be less than 1. So in the function SoftPWMSetFadeTime I replaced

            fadeAmount = 255UL * (SOFTPWM_OCR * 256UL / (F_CPU / 8000UL)) / fadeUpTime;


            fadeAmount = 255UL * (SOFTPWM_OCR * 256UL / (F_CPU / 8000UL)) / fadeUpTime;
            if (fadeAmount <= 0)
            fadeAmount = 1;

            Note, there are two places in this function where this needs to be done. Once for the fade-in time and once for the fade-out time.