Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.arch.embedded > #29137

Re: Poor man's PWM

From David Brown <david.brown@hesbynett.no>
Newsgroups comp.arch.embedded
Subject Re: Poor man's PWM
Date 2020-01-28 11:29 +0100
Organization A noiseless patient Spider
Message-ID <r0p2ea$h28$1@dont-email.me> (permalink)
References <r0o0mu$c6l$1@dont-email.me>

Show all headers | View raw


On 28/01/2020 01:53, Don Y wrote:
> With "few" intensity levels desired, I plan to drive LED
> with a crude PWM signal directly from an IRQ (i.e., push
> bits out a hardware port at each IRQ).
> 
> But, instead of having N different times at which the IRQ
> might be signalled (for the N+1 different duty cycles) in
> each refresh interval, I plan on having log2(N) times, each
> delimiting an period "twice" as long as the previous.  This
> keeps the hardware cheaper than dirt and minimizes the
> real-time load on the processor.
> 
> [There are (refresh_rate * log2(N)) IRQs each second instead
> of (refresh_rate * N) IRQs -- though the *instantaneous* IRQ
> rate varies considerably]
> 
> Then, at the level above the driver, build a schedule for which
> intervals to activate the LED.
> 
> E.g., for each level: turn the LED on in intervals:
> 0   None
> 1   1
> 2   2
> 3   1&2
> 4   4
> 5   1&4
> 6   2&4
> ...
> N   All
> 
> What problems might I encounter with this approach?  (I'm
> mainly worrying about visual artifacts)

It sounds doable, but complicated.  I think you'd need a good many
different intensity levels before this would pay off - the overhead of
tracking and setting the different time intervals won't make sense until
you are using a huge number of levels.  And if you wanted a huge number
of levels, you'd be using a better quality method of generating the PWM
signal that doesn't have as much jitter.

As far as processor load goes, there are two key points.  One is the
worst case rate of the IRQs - and that is determined by the lowest
digit, and will be the same for a regular pulse or for this complex
scheme.  The other is the amount of processor work done in each IRQ, and
that will be massively more than with a simple system, outweighing it in
total work until you have a huge number of levels.

Let me guess some numbers - and you can correct them if they are
inappropriate.

Pick a refresh frequency of 100 Hz, which is fast enough that you won't
see blinking even if you move your eyes quickly.  We'll have 16 levels,
which is more than enough for normal circumstances.

That puts your timer interrupt at 1600 Hz - not an onerous burden for
most systems.  And being a regular timer interrupt, you can use the same
tick for other purposes, unlike your specialised one.

Below is a simple example.  It can easily be modified to have different
pattern types (minimise switching, or spread the on/off time evenly
within the cycle), different mapping between logical levels and total
duty cycle (to better suit the visual brightness impression), multiple
leds, etc.



#include <stdint.h>

enum { levels = 16 };

_Static_assert(levels <= 16, "Pattern type needs to suit levels");
typedef uint16_t pattern_t;
static const pattern_t patterns[levels + 1] = {
    0x0000,
    0x0001, 0x0101, 0x0841, 0x1111, 0x2491, 0x4949, 0x54a9, 0x5555,
    0xab55, 0xb5b5, 0xdb6d, 0xdddd, 0xf7bd, 0xfdfd, 0xfffd, 0xffff
};

static int ledLevel;
void setLedLevel(int level) {
    if (level < 0) level = 0;
    if (level >= levels) level = levels;
    ledLevel = level;
}

extern void ledOn(void);
extern void ledOff(void);

static pattern_t stepper = 1;
static const pattern_t last_step = (1u << (levels - 1));
void ledTimerInterrupt(void) {
    pattern_t pattern = patterns[ledLevel];
    if (pattern & stepper) {
        ledOn();
    } else {
        ledOff();
    }
    if (stepper == last_step) {
        stepper = 1;
    } else {
        stepper = stepper << 1;
    }
}

Back to comp.arch.embedded | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-27 17:53 -0700
  Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-27 19:29 -0800
    Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-28 20:11 -0700
      Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-28 20:11 -0800
  Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-28 11:29 +0100
    Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-28 20:34 -0700
      Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-28 20:32 -0800
      Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-29 12:53 +0100
  Re: Poor man's PWM Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2020-01-28 14:43 +0100
    Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-28 12:03 -0800
    Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-28 20:54 -0700
      Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-28 21:54 -0800
        Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-29 00:17 -0700
          Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-28 23:40 -0800
            Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-29 00:54 -0700
            Re: Poor man's PWM Paul Rubin <no.email@nospam.invalid> - 2020-01-29 00:04 -0800
              Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-29 02:17 -0700
        Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-29 13:21 +0100
          Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-29 09:51 -0800
            Re: Poor man's PWM Paul Rubin <no.email@nospam.invalid> - 2020-01-29 10:07 -0800
              Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-29 10:14 -0800
                Re: Poor man's PWM Paul Rubin <no.email@nospam.invalid> - 2020-01-29 10:28 -0800
                Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-29 11:40 -0800
                Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-30 10:25 +0100
                Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-30 08:06 -0800
                Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-30 21:21 +0100
                Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-30 15:08 -0800
                Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-31 01:17 +0100
                Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-01-30 17:21 -0800
                Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-31 10:59 +0100
                Re: Poor man's PWM Rick C <gnuarm.deletethisbit@gmail.com> - 2020-02-01 10:18 -0800
            Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-30 10:20 +0100
              Re: Poor man's PWM Tom Gardner <spamjunk@blueyonder.co.uk> - 2020-01-30 10:13 +0000
          Re: Poor man's PWM Paul Rubin <no.email@nospam.invalid> - 2020-01-29 09:57 -0800
            Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-30 10:29 +0100
      Re: Poor man's PWM Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2020-01-29 16:34 +0100
  Re: Poor man's PWM Dimiter_Popoff <dp@tgi-sci.com> - 2020-01-28 17:39 +0200
    Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-28 19:58 -0700
      Re: Poor man's PWM Dimiter_Popoff <dp@tgi-sci.com> - 2020-01-29 18:54 +0200
  Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-01-29 00:17 -0700
    Re: Poor man's PWM David Brown <david.brown@hesbynett.no> - 2020-01-29 13:39 +0100
      Re: Poor man's PWM Paul Rubin <no.email@nospam.invalid> - 2020-01-29 10:08 -0800
  Re: Poor man's PWM Don Y <blockedofcourse@foo.invalid> - 2020-04-27 20:13 -0700

csiph-web