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

Support PWM phase shifts on ESP8266 #4165

Open
wants to merge 6 commits into
base: 0_15
Choose a base branch
from

Conversation

willmmiles
Copy link
Collaborator

Use the phase-locked soft PWM from the Arduino core to implement the same PWM phase output as ESP32s are using. The soft PWM code is vendored in, as it was previously, to add the NMI workaround from #4035. Testing revealed a need for additional tweaks to support adjusting relative signal phase without a stop/restart cycle (which interlocks with the NMI twice) so I've added that here too.

Completes #4034.

This PR includes a logic change that also affects ESP32:

  • For multi-pin buses, the second and subsequent pin's active periods are always arranged after the first pin. This is to ensure that we aren't trying to change signals that need to occur in the past.

I've tested this with an ESP8266 and an ESP32-WROVER using a scope to check for regressions. Additional testing would be greatly appreciated.

Finally: while this code does its best replicate the 2-channel CW/WW output pattern intended for H-bridge usage, I still wouldn't recommend using one with ESP8266. There isn't (currently) a way to atomically update several pins phase at once, leading to the possibility of overlap while an update is being applied.

Use the phase-locked soft PWM from the Arduino core to implement the
same PWM phase management as ESP32s are using.  The soft PWM code is
vendored in, as it was previously, to add the NMI workaround from Aircoookie#4035.

Completes Aircoookie#4034
- Better phase updates without dropping samples
- Make second pin duty cycle always after first, even inverted
@DedeHai DedeHai self-requested a review October 2, 2024 17:53
@DedeHai
Copy link
Collaborator

DedeHai commented Oct 2, 2024

What I found when testing H-bridge boards (intended for motor use) is that on an ESP32 you have to set PWM to "slowest" with dithering enabled for it to have the best range. One board which is just made from transistors is way too slow for even that, it can maybe handle 1kHz at best and the crossover protection we implemented is still too fast: the crossover delay would have to be increased by a factor of 5 or so. Boards with proper ICs on them already have internal crossover protection so they are safe (I still managed to kill one at 2A at 40kHz though.

@willmmiles
Copy link
Collaborator Author

The interesting thing about the soft PWM implementation on ESP8266 is that it has extremely high precision - "on" and "off" times are essentially specified to the exact CPU clock cycle (so the effective "bit depth" is log2(80MHz/frequency)) - but poor accuracy (can be delayed by microseconds). For the "normal" 880Hz PWM frequency used on ESP8266, that's about 16 bits of depth, though it'll get dicier when you're very close to all-off or all-on. Since it's based on the NMI - the highest priority interrupt - the delays are only a problem if you've got independent channels running. Phase locked outputs only get in to trouble if there are very short gaps between them, hence the fairly large dead time value I put in.

In retrospect, this PR is the "lamest" possible approach, with the smallest changes to the PWM code from the Arduino core. It phase-locks the signals for each bus, but doesn't try to synchronize between busses -- this could lead to inaccuracies on multi-output systems if the timings end up being very close together. The PWM core could instead be rewritten to use a shared "base" frequency, storing the timings and phase offsets for each channel, which could potentially be faster and more accurate for PWM signals like we use, but at the cost of generality.

@blazoncek
Copy link
Collaborator

@willmmiles IMO we only need to have phase locked (and synchronised) PWM outputs on a single bus (i.e. 2 channel PWM bus). There is no (justifiable) need to have all buses synchronised.

@willmmiles
Copy link
Collaborator Author

@willmmiles IMO we only need to have phase locked (and synchronised) PWM outputs on a single bus (i.e. 2 channel PWM bus). There is no (justifiable) need to have all buses synchronised.

I agree that there's no functional requirement for phase-locking between buses. However I also think it might be more CPU efficient to do so -- guaranteeing that transition edges line up as often as possible could mean fewer timer interrupts, particularly back-to-back ones.

@blazoncek
Copy link
Collaborator

I would assume not many people have ESP8266 utilizing it as a 5 output PWM White controller.
Most often it will be used as RGB, RGBW, RGB+CCT or CCT only controller.

And even if used as 5 output PWM White controller that's only 5 pixels worth of processing. For anything else we can just suggest to replace ESP8266 with ESP32.

That's just an idea if it is worth the effort in pursuing it further. IMO it is better to spend time elsewhere.

@willmmiles
Copy link
Collaborator Author

That's just an idea if it is worth the effort in pursuing it further. IMO it is better to spend time elsewhere.

Agreed! I mention it mostly for completeness, and in case someone's searching in the future. In hindsight it probably would've been faster to develop it that way from the start, but the solution presented in this PR should work well enough for all practical use cases.

@willmmiles willmmiles changed the title Draft: Support PWM phase shifts on ESP8266 Support PWM phase shifts on ESP8266 Oct 19, 2024
In some cases it was possible for the computed phase shift to skip
a cycle.  Update the shift calculation logic to prevent this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants