Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implement PWM generator logic #7231

Merged
merged 68 commits into from
Nov 20, 2020
Merged

Commits on Apr 19, 2020

  1. Re-implement PWM generator logic

    Add special-purpose PWM logic to preserve alignment of PWM signals for
    things like RGB LEDs.
    
    Keep a sorted list of GPIO changes in memory.  At time 0 of the PWM
    cycle, set all pins to high.  As time progresses bring down the
    additional pins as their duty cycle runs out.  This way all PWM signals
    are time aligned by construction.
    
    This also reduces the number of PWM interrupts by up to 50%.  Before,
    both the rising and falling edge of a PWM pin required an interrupt (and
    could shift arround accordingly).  Now, a single IRQ sets all PWM rising
    edges (so 1 no matter how many PWM pins) and individual interrupts
    generate the falling edges.
    
    The code favors duty cycle accuracy over PWM period accuracy (since PWM
    is simulating an analog voltage it's the %age of time high that's the
    critical factor in most apps, not the refresh rate).  Measurements give
    it about 35% less total error over full range at 20khz than master.
    
    @me-no-dev used something very similar in the original PWM generator.
    earlephilhower committed Apr 19, 2020
    Configuration menu
    Copy the full SHA
    2c010d6 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    122ca23 View commit details
    Browse the repository at this point in the history
  3. Adjust running PWM when analogWriteFreq changed

    Use fixed point math to adjust running PWM channels to the new
    frequency.
    earlephilhower committed Apr 19, 2020
    Configuration menu
    Copy the full SHA
    118103b View commit details
    Browse the repository at this point in the history
  4. Also preserve phase of running tone/waveforms

    Copy over full high/low periods only on the falling edge of a cycle,
    ensuring phase alignment for Tone and Servo.
    earlephilhower committed Apr 19, 2020
    Configuration menu
    Copy the full SHA
    5cd145e View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    4ce623d View commit details
    Browse the repository at this point in the history

Commits on Apr 20, 2020

  1. Turn off PWM on a Tone or digitalWrite

    Ensure both the general purpose waveform generator and the PWM generator
    are disabled on a pin used for Tone/digitalWrite.
    earlephilhower committed Apr 20, 2020
    Configuration menu
    Copy the full SHA
    3a6f6c1 View commit details
    Browse the repository at this point in the history

Commits on Apr 21, 2020

  1. Remove hump due to fixed IRQ delta

    A hump in the dueling PWMs was very prominent in prior pulls.
    
    The hump was caused by having a PWM falling edge just before the cycle
    restart, while having the other channel requesting a 1->0 transition
    just outside the busy-loop window of 10us. So it gets an IRQ for channel
    B 0->1, then waits 2..8us for the next PWM full cycle 0->1, and ends up
    returning from interrupt and not scheduling another IRQ for 10us...hence
    the horizontal leg of the bump...
    
    Reduce the minimum IRQ latency a little bit to minimize this effect.
    There will still be a (significantly smaller) hump when things cross, but
    it won't be anywhere near as bad or detectable.
    earlephilhower committed Apr 21, 2020
    Configuration menu
    Copy the full SHA
    27ee6f8 View commit details
    Browse the repository at this point in the history

Commits on Apr 22, 2020

  1. Speed PWM generator by reordering data struct

    Breaking out bitfields required a load and an AND, slowing things down
    in the PWM loop. Convert the bitfield into two separate natural-sized
    arrays to reduce code size and increase accuracy.
    earlephilhower committed Apr 22, 2020
    Configuration menu
    Copy the full SHA
    5faf6be View commit details
    Browse the repository at this point in the history

Commits on Apr 24, 2020

  1. Configuration menu
    Copy the full SHA
    94af195 View commit details
    Browse the repository at this point in the history

Commits on Apr 27, 2020

  1. Add error feedback to waveform generation

    Apply an error term to generated waveform phase times to adjust for any
    other ongoing processes/waveforms.  Take the actual edge generation
    times, subtract them from the desired, and add 1/4 of that (to dampen
    any potential oscillations) to the next similar phase of that waveform.
    
    Allows the waveform to seek its proper period and duty cycle without
    hardcoding any specific calibrations (which would change depending on
    the codepaths, compiler options, etc.) in the source.
    earlephilhower committed Apr 27, 2020
    Configuration menu
    Copy the full SHA
    1182cd0 View commit details
    Browse the repository at this point in the history
  2. Move _stopPWM and _removePWMEntry to IRAM

    Thanks to @dok-net for noticing these need to be in IRAM as they may be
    called by digitalWrites in an IRQ.
    earlephilhower committed Apr 27, 2020
    Configuration menu
    Copy the full SHA
    7ee7d19 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    c12e961 View commit details
    Browse the repository at this point in the history

Commits on Apr 28, 2020

  1. Configuration menu
    Copy the full SHA
    143b6ae View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    a783621 View commit details
    Browse the repository at this point in the history
  3. Adjust for random 160MHZ operation

    The WiFi stack sometimes changes frequency behind our backs, so ESP's
    cycle counter does not count constant ticks.
    
    We can't know how long it's been at a different than expected frequency,
    so do the next best thing and make sure we adjust any ESP cycles we're
    waiting for by the current CPU speed.
    
    This can lead to a blip in the waveform for 1 period when the frequency
    toggles from normal, and when it toggles back, but it should remain
    for the intervening periods.
    
    Should avoid a lot of LED shimmering and servo errors during WiFi
    connection (and maybe transmission).
    earlephilhower committed Apr 28, 2020
    Configuration menu
    Copy the full SHA
    ad3076c View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    dc32961 View commit details
    Browse the repository at this point in the history
  5. Subtract constant-time overhead for PWM, add 60khz

    PWM has a constant minimum time between loops with a single pin, so pull
    that time out of the desired PWM period and shift the center of the PWM
    frequency closer to the desired without any dynamic feedback needed.
    
    Enable 60khz PWM, even though it's not terribly useful as it causes an
    IRQ every ~8us (and each IRQ is 2-3us).  The core can still run w/o WDT,
    but it's performance is about 5x slower than unloaded.
    earlephilhower committed Apr 28, 2020
    Configuration menu
    Copy the full SHA
    ec62ee3 View commit details
    Browse the repository at this point in the history
  6. Configuration menu
    Copy the full SHA
    a41890b View commit details
    Browse the repository at this point in the history

Commits on Apr 29, 2020

  1. Remove constant offset to PWM period

    analogWrite doesn't know about the change in total PWM cycles, so it is
    possible for it to send in a value that's beyond the maximum adjusted
    PWM cycle count, royally messing up things.  Remove the offset.
    
    Also, fix bug with timer callback functions potentially disabling the
    timer if PWM was still active.
    earlephilhower committed Apr 29, 2020
    Configuration menu
    Copy the full SHA
    42bbede View commit details
    Browse the repository at this point in the history
  2. Remove volatiles, replace with explicit membarrier

    Volatiles are expensive in flash/IRAM as well as in runtime because they
    introduce `memw` instructions everywhere their values are used.
    
    Remove the volatiles and manually mark handshake signals for
    re-read/flush to reduce code and runtime in the waveform generator/PWM.
    earlephilhower committed Apr 29, 2020
    Configuration menu
    Copy the full SHA
    79a7f7d View commit details
    Browse the repository at this point in the history
  3. Consolidate data into single structure

    Save IRAM and flash by using a class to hold waveform generator state.
    Allows for bast+offset addressing to be used in many cases, removing
    `l32r` and literals from the assembly code.
    earlephilhower committed Apr 29, 2020
    Configuration menu
    Copy the full SHA
    cbff7a3 View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    4196bf8 View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    14f4416 View commit details
    Browse the repository at this point in the history
  6. Configuration menu
    Copy the full SHA
    2002a5d View commit details
    Browse the repository at this point in the history
  7. Configuration menu
    Copy the full SHA
    5b1f288 View commit details
    Browse the repository at this point in the history
  8. Reduce PWM size by using 32b count, indexes

    Byte-wide operations require extra instructions, so make index and count
    a full 32-bits wide.
    earlephilhower committed Apr 29, 2020
    Configuration menu
    Copy the full SHA
    f42696c View commit details
    Browse the repository at this point in the history
  9. GP16O is a 1-bit register, just write to it

    Testing indicates that GP16O is just a simple 1-bit wide register in the
    RTC module.  Instead of |= and &- (i.e. RmW), use direct assignment in
    PWM generator.
    earlephilhower committed Apr 29, 2020
    Configuration menu
    Copy the full SHA
    2b0dde4 View commit details
    Browse the repository at this point in the history
  10. Configuration menu
    Copy the full SHA
    b0e818f View commit details
    Browse the repository at this point in the history

Commits on May 3, 2020

  1. Increase PWM linearity in low/high regions

    By adjusting the PWM cycle slightly to account for the fixed time
    through the compute loop, increase the linear response near the min and
    max areas.
    earlephilhower committed May 3, 2020
    Configuration menu
    Copy the full SHA
    dfaa9ce View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    3909ada View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    413cd17 View commit details
    Browse the repository at this point in the history
  4. Fix clean-waveform transition, lock to tone faster

    New startWaveform waveforms were being copied over on the falling edge
    of the cycle, not the rising edge.  Everything else is based on rising
    edge, so adjust accordingly.
    
    Also, feedback a larger % of the error term in standard waveform
    generation.  Balances the speed at which it locks to tones under
    changing circumstances with it not going completely bonkers when a
    transient error occurs due to some other bit.
    earlephilhower committed May 3, 2020
    Configuration menu
    Copy the full SHA
    07f5ff1 View commit details
    Browse the repository at this point in the history

Commits on May 4, 2020

  1. Configuration menu
    Copy the full SHA
    539d0d4 View commit details
    Browse the repository at this point in the history
  2. Reduce IRAM by pushing more work to _setPWM

    Simply mark pins as inactive, don't adjust the ordered list until the
    next _startPWM call (in IROM).
    earlephilhower committed May 4, 2020
    Configuration menu
    Copy the full SHA
    df51b21 View commit details
    Browse the repository at this point in the history

Commits on May 5, 2020

  1. Fix typo in PWM pin 1->0 transition

    Actually check the pin mask is active before setting the PWM pin low.
    D'oh.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    867b181 View commit details
    Browse the repository at this point in the history
  2. Combine cleanup and pin remove, save 50 bytes IROM

    The cleanup (where marked-off pins are removed from the PWM time map)
    and remove (where a chosen pin is taken out of the PWM map) do
    essentially the same processing.  Combine them and save ~50 bytes of
    code and speed things up a tiny bit.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    f757778 View commit details
    Browse the repository at this point in the history
  3. Remove unused analogMap, toneMap

    Save ~100 bytes of IROM by removing the tone/analog pin tracking from
    the interface functions.  They were completely unused.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    9424090 View commit details
    Browse the repository at this point in the history
  4. Save IRAM/heap by adjusting WVF update struct

    The waveform update structure included 2 32-bit quantities (so, used
    8 * 17 = 136 bytes of RAM) for the next cycle of a waveform.
    
    Replace that with a single update register, in a posted fashion.  The
    logic now sets the new state of a single waveform and returns
    immediately (so, no need to wait 1ms if you've got an existing waveform
    of 1khz).  The waveform NMI will pick up the changed value on its next
    cycle.
    
    Reduces IRAM by 40 bytes, and heap by 144 bytes.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    c8b53ef View commit details
    Browse the repository at this point in the history
  5. Don't duplicate PWM period calculation

    Let the waveform generator be the single source of truth for the PWM
    period in clock cycles.
    
    Reduces IRAM by 32 bytes and makes things generally saner.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    e6b7aa1 View commit details
    Browse the repository at this point in the history
  6. Factor out common PWM update code

    Replace repeated PWM update logic with a subroutine, and move the
    PWMUpdate pointer into the state itself.  Reduces IROM and IRAM,
    removes code duplication.
    
    Also remove single-use macros and ifdef configurable options as the
    IRAM and IROM impact of them are now not very large.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    28645ff View commit details
    Browse the repository at this point in the history
  7. Configuration menu
    Copy the full SHA
    3ee638c View commit details
    Browse the repository at this point in the history
  8. Clean up old comments

    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    174d19e View commit details
    Browse the repository at this point in the history
  9. Configuration menu
    Copy the full SHA
    a910eae View commit details
    Browse the repository at this point in the history
  10. Fix regression when analogWrite done cold

    Lost an `initTimer()` call in a refactoring, resulting in the core
    hanging forever while waiting for the NMI which will never happen.
    
    Re-add as appropriate.
    earlephilhower committed May 5, 2020
    Configuration menu
    Copy the full SHA
    179b9d6 View commit details
    Browse the repository at this point in the history

Commits on May 6, 2020

  1. Save 16b of IRAM by not re-setting edge intr bit

    Per @dok-net, drop the rewrite of the edge trigger flag in the timer
    interrupt register.  It's set on startup and never cleared, so this is
    redundant.  Drops ~16 bytes of IRAM.
    earlephilhower committed May 6, 2020
    Configuration menu
    Copy the full SHA
    e44171f View commit details
    Browse the repository at this point in the history

Commits on May 7, 2020

  1. Allow on-the-fly PWM frequency changes

    When PWM is running and analogWriteFreq is called, re-calculate the
    entire set of PWM pins to the new frequency.  Preserve the raw
    numerator/denominator in an unused bit of the waveform structure to
    avoid wasting memory.
    earlephilhower committed May 7, 2020
    Configuration menu
    Copy the full SHA
    7fe9a2d View commit details
    Browse the repository at this point in the history

Commits on May 8, 2020

  1. Adjust for fixed overhead on PWM period

    Pulls the actual PWM period closer to the requested one with a simple,
    0-overhead static adjustment.
    earlephilhower committed May 8, 2020
    Configuration menu
    Copy the full SHA
    e7cb533 View commit details
    Browse the repository at this point in the history
  2. Fix value reversal when analogWrite out of range

    Silly mistake, swapped high and low values when checking analogWrite for
    over/under values.  Fixed
    earlephilhower committed May 8, 2020
    Configuration menu
    Copy the full SHA
    083560d View commit details
    Browse the repository at this point in the history

Commits on May 9, 2020

  1. Configuration menu
    Copy the full SHA
    e421d81 View commit details
    Browse the repository at this point in the history

Commits on May 10, 2020

  1. Don't optimize the satopWaveform call

    Save a few bytes of IRAM by not using -O2 on the stopWaveform call.  It
    is not a speed-critical function.
    earlephilhower committed May 10, 2020
    Configuration menu
    Copy the full SHA
    5be4961 View commit details
    Browse the repository at this point in the history

Commits on May 13, 2020

  1. Configuration menu
    Copy the full SHA
    051008a View commit details
    Browse the repository at this point in the history

Commits on May 18, 2020

  1. Adjust PWM period as fcn of # of PWM pins

    Results in much closer PWM frequency range over any number of PWM pins,
    while taking 0 add'l overhead in IRAM or in the IRQ.
    earlephilhower committed May 18, 2020
    Configuration menu
    Copy the full SHA
    6692418 View commit details
    Browse the repository at this point in the history

Commits on Jun 4, 2020

  1. Configuration menu
    Copy the full SHA
    606c5cd View commit details
    Browse the repository at this point in the history

Commits on Jun 6, 2020

  1. Fix occasional Tone artifacts

    When _setPWMFreq was called the initial PWM mask was not set to 0
    leading to occasional issues where non-PWM pins would be set to 1
    on the nextPWM cycle.  Manifested itself as an overtone at the PWM
    frequency +/-.
    earlephilhower committed Jun 6, 2020
    Configuration menu
    Copy the full SHA
    524f047 View commit details
    Browse the repository at this point in the history
  2. Reduce CPU usage and enhance low range PWM output

    Borrow a trick from esp8266#7022 to exit the busy loop when the next event is
    too far out.  Also reduce the IRQ delta subtraction because it was
    initially not NMI so there was much more variation than now.
    
    Keep the PWM state machine active at a higher prio than the standard
    tone generation when the next edge is very close (i.e. when we're at
    the max or min of the range and have 2 or more near edges).  Adds a
    lot of resolution to the response at low and high ranges.
    
    Go from relative to absolute cycle counts in the main IRQ loop so that
    we don't mingle delta-cycles when the delta start was significantly
    different.
    earlephilhower committed Jun 6, 2020
    Configuration menu
    Copy the full SHA
    361d4a2 View commit details
    Browse the repository at this point in the history

Commits on Jun 7, 2020

  1. Configuration menu
    Copy the full SHA
    975fe12 View commit details
    Browse the repository at this point in the history
  2. Update min IRQ time to remove humps in PWM linearity

    Keep PWM error <2.0% on entire range, from 0-100%, and remove the
    hump seen in testC by fixing the min IRQ delay setting.
    earlephilhower committed Jun 7, 2020
    Configuration menu
    Copy the full SHA
    9e48706 View commit details
    Browse the repository at this point in the history
  3. Remove minor bump at high PWM frequencies

    The IRQ lead time was a tiny bit undersized, causing IRQs to come back
    too late for about .25us worth of PWM range.  Adjust the constant
    accordingly
    earlephilhower committed Jun 7, 2020
    Configuration menu
    Copy the full SHA
    565f21f View commit details
    Browse the repository at this point in the history

Commits on Jun 8, 2020

  1. Undo the 160->80 frequency adjust

    Since the adjustment for when a 160mhz compile is running at 80mhz
    is giving bad behavior, simply remove it and revert to old behavior.
    earlephilhower committed Jun 8, 2020
    Configuration menu
    Copy the full SHA
    272dc9d View commit details
    Browse the repository at this point in the history

Commits on Jul 13, 2020

  1. Configuration menu
    Copy the full SHA
    8f9af5d View commit details
    Browse the repository at this point in the history

Commits on Aug 23, 2020

  1. Configuration menu
    Copy the full SHA
    2961933 View commit details
    Browse the repository at this point in the history

Commits on Aug 29, 2020

  1. Configuration menu
    Copy the full SHA
    e5afab0 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    e5ba217 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    f911754 View commit details
    Browse the repository at this point in the history

Commits on Oct 26, 2020

  1. Configuration menu
    Copy the full SHA
    1b34278 View commit details
    Browse the repository at this point in the history

Commits on Nov 20, 2020

  1. Merge branch 'master' of https://github.com/esp8266/Arduino into realpwm

    Includes patches to allow side-by-side existance of the two versions and
    a slight change such that the #define ..._PWM is unneeded (i.e. allow
    existing makefiles/scripts/etc. to get expected behavior w/o any changes
    on their part).
    earlephilhower committed Nov 20, 2020
    Configuration menu
    Copy the full SHA
    55e8abb View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    4cc3d8a View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    a353909 View commit details
    Browse the repository at this point in the history