analogWrite weirdness on MDBT42Q

Posted on
  • Hey there!

    Just wanted to post a message about some funkiness I noticed with analogWrites on the MDBT42Q - there's a pretty solid chance I'm just misunderstanding some of the docs so apologies in advance if thats the case!

    Doing an analogWrite with just the pin & value (between 0 & 1) works fine, albeit with some flickering when trying to update the value every 100ms but likely because its software PWM, so that comes with the territory.

    The weirdness I noticed was with some of the options:

    • If I've already set the pinMode to "output", passing an options object to analogWrite ignores the value and sets the pin to 100% on, regardless of whats in it

    • If I've not already set the pinMode, passing an empty options object, or an options object containing forceSoft: false or soft: true/false to analogWrite ignores the value and sets the pin to 100% on.

    • If I've not already set the pinMode, passing an options object just containing forceSoft: true to analogWrite allows me to set the value to either 0 or 1, any number in between is interpreted as a 0

    I'm 50/50 on if I've just badly misinterpreted what the options object is for, but I wanted to ask just in case this isn't expected behavior :)

  • Do you think you could post up some example commands with what happens? It doesn't sound right but it might be something to do with the way you're using the options object...

    By default analogWrite on the MDBT42Q should use hardware PWM, and there shouldn't be flicker. For example:

    setInterval(function() {
    // pulsing LED - no flicker
    // calling pinMode(LED1,"output") stops PWM but the next call works fine

    And for software:

    // works fine:
    // some flicker:
    // stops output
    // works again

    But I did encounter some issues when not specifying a frequency, so perhaps that could be the problem? If so it's something I can look at fixing in a firmware update

  • I think my issue might've been with doing too many PWMs at once - I'm doing a very slow fade by PWMing 10 LED strips through a bank of mosfets (MDBT42Q pins D22, D20, D19, D18, D17, D25, D26, D27, D28, D29), if I do more than 3 with:

    analogWrite(<PIN>, 0.1, {freq:100,soft:false} );

    I get an Uncaught Error: "No free Hardware PWMs. Try not specifying a frequency, or using analogWrite(pin, val, {soft:true}) for Software PWM"

    If I try forcing software PWM, if I try with more than 7 outputs like this:

    analogWrite(<PIN>, 0.1, {freq:100,forceSoft:true} );

    I get an Uncaught InternalError: Timeout on Utility Timer

    however, just doing an analog write without an options object for all of the pins allows me to write to all of them but with a bit of a flicker to it. I'm running the LED strips with a 24v supply & I'm doing low-side switching with a bank of mosfets, but I'm powering the MDBT42Q with a separate 5v power supply with a common ground reference, so I guess there's also chance that theres some noise between my supplies.

    I'm going to do a bit of digging and see if I can narrow down where the slight flicker is coming from, hopefully its just my code running a little inefficiently or a power supply thing :)

    Thanks for getting back to me so quick, apologies for being slower to reply!

  • Ahh - ok, that makes a lot more sense! I think there are a few issues:

    • If you've got multiple PWMs on the same timer hardware then when setting the new value, the main counter value can get reset and you get flicker
    • Currently espruino is lazy at choosing timers, and if you specify a frequency it doesn't even try and find a timer with the same frequency
    • You can only have a max of 7 software PWMs - also the more you have the more likely things are to be a bit flickery

    I'll see what I can do about the first two in a firmware update, however I think you could probably do ok for now by using three hardware PWMs and 7 software?

  • Ok, if you try a 'cutting edge' build now then I think you should find hardware PWM is a lot better. I've actually been having trouble reproducing any flicker with it even before, but the new code should be a lot better.

    The default PWM frequency is 1000Hz for hardware, 50Hz for software - but even if you specify a frequency for hardware PWM now you should be able to use all 12 available PWM channels

  • Tried the cutting-edge build but still seeing a tiny bit of a flicker, but I'm happy with that being an inefficiency in my code rather than a problem with PWM on the MDBT42Q. I appreciate you getting a build out so fast, and I'm totally down with sharing my code if you wanted to try and reproduce what I was seeing :)

    I dropped in a PCA9685 to handle the PWM control of my LED strips to free up the MDBT42Q and all is looking great now

  • Hi all,
    I am seeing the same thing after updating to cutting edge. I am using just one PWM for driving servo and updating value periodically (feedback from a pot tied to adc). The jitter with default hardware timer is massive. After selecting software is smaller, around 50us but that still means servo doesnt settle completely. Also once in a while it spikes to even bigger value.
    I used the code from one of the examples for servos:

    function setServo(pin,pos) {
     if (pos<0) pos=0;
     if (pos>1) pos=1;
     analogWrite(pin, (1+pos) / 50.0, {freq:20, forceSoft:true});

    Ideally I would like to be able to use hardware timers as they shouldnt jitter if the timer doesnt reset or something. You can see that when you dont update periodically the PWM then its rock solid.
    I am planning to use a servo, few dc motors and a stepper so its going to be an issue.

    Is there any other way with more low level control to update PWM's values?


    note: I did check without adc feedback with hardcoded pwm value so it doesnt come from the pot.

  • Thanks - I'll look into this. Just did a quick check and:

    function onTimer() {
    var i;
    setInterval(function() {
      if (i) {
        i = undefined;
      } else i = setInterval(onTimer,10);
    }, 1000);

    You'd expect the LED to stay the same brightness. If you don't specify a frequency then it's fine so I assume that it's resetting the frequency even when there's no need.

    Is there any other way with more low level control to update PWM's values?

    Yes, there is - you could actually look at the nRF52832 reference manual and then poke values directly into the timer peripheral after it is set up.

    Hopefully I'll be able to get this fixed pretty quickly though.

  • Thanks Gordon for having a look into it. I looked through the API reference and figured maybe I could use peek/poke if I am stuck. I am not under any pressure. Just checking all the functionality before I start designing PCB for my little project.
    I am using USB scope for probing signals. Great for home labs, it has waveform generator and other useful stuff digikit.
    My guess is that the analogWrite function sets more than just updating the duty cycle value and it resets the timer. Maybe selecting option for frequency is doing that. For that servo I need to use around 20ms anyway.
    I saw there are some modules available for driving motors so I will test them all and see. I am curious about the stepper motor driver for nrf52.

  • Ok, that was dumb - I did the fix originally but didn't commit it to the master branch so it didn't end up in cutting edge builds.

    If you try it now it should all be sorted.

  • cool, that was super fast :))))) I will give it a go and let you know. Thanks again!

  • Updated to cutting edge (v2.06.128) and its perfect. Servo can settle now. Thanks again Gordon for super fast fix. Video of the scope capture attached.

    1 Attachment

  • Great, thanks for checking it out! I'm just gutted I didn't actually properly commit the fix I did a month ago!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

analogWrite weirdness on MDBT42Q

Posted by Avatar for consolenaut @consolenaut