-
Notifications
You must be signed in to change notification settings - Fork 136
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
PWM Output Reconfigures the Clock Too Often For Smooth Ramping of Duty Cycles #73
Comments
FYI, I put together a fix that addresses this by refactoring away the PHY pieces of RaspberryPWM into an unfortunately named RaspberryPHY class. This is a semi-singleton, which is passed into the RaspberryPWM during init, which uses it to get at the hardware register addresses rather than doing it itself. My early testing says that the flicker from rapid changes to the duty cycle is gone (24, 50 and 100 times a second), and I can control both channels simultaneously, also without inducing flicker. I haven't tested the pattern writing side of it though. If you have guidelines on how to test that against regressions, I'll take a look. There does seem to be some interesting interactions when I use 480Hz as my PWM freq, and updating rapidly with my test LED strip which causes some new form of flicker at around 6% duty cycle. So I'm not sure it's entirely ready, but it's still a big improvement from the behavior I was seeing last night. |
Just wanted to give an update on this. I’ve been using the changes for the last ~3 weeks to drive aquarium lighting without any real issues. The 480Hz issue seems to be limited to the strip I was using for testing and not my actual lighting. I’ve only been testing PWM frequencies up to about 3kHz and there is some code I know needs to be fixed around the highFreqSampleReduction behavior. If you wouldn’t mind, I’d like your eyes on the pull request so we can discuss the changes more concretely? |
Yes, every time a PWM is started at the moment the control register (PWM CTL) is cleared disabling the PWM if it's currently active. It shouldn't be possible to set a different set of frequency parameters for the second channel without stopping everything first. My idea at the time was to force the configuration of both signals at the same time if both were needed, but this was more the result of an hard requirement for multiple PWMPatterns than anything else (when the PWM engine is used in FIFO mode with more than one channel the data needs to be put in an interleaved fashion in the queue... so, both signals must be configured at the same time). If I recall correctly (it was some time ago, should have documented the process ;) ) at the time the implementation with the DIV obtained from the desired frequency was the one that resulted in a better signal (from low to high frequencies, regardless of the size of the slots of the M/S algorithm and with all the cycles looking the same with somewhat minimal jitter) when checked with an oscilloscope. Hmm, at 480Hz with a PLLD of 500MHz and a DIVI of 2, how many M/S slots are you using to generate 6%? It feels like it could be a value too big to be able to generate a stable signal. |
Sure open it. |
The timing would be 520,833 in range and 31,250 in data. It was interesting because it only occurs when doing a rapid ramp from 0% to 100% over about 5 seconds, with that particular light strip. If I hold the duty cycle in the offending range, it looks fine. Slow ramps through the range also work fine. I'll be honest, I didn't think about this approach all that much, since I had been using pigpio prior to converting the project to Swift. But I also think I hadn't tried it with pigpio at 480Hz with that particular light strip. I was doing mostly 1.5-3kHz at that point with the hardware PWM. |
So, I figured out that my code was very likely not calculating the range correctly, I've fixed it with a new commit in the PR. I think. I've got an oscilloscope on the way so I can confirm that it actually calculates the range properly. But it does explain the odd behavior I was seeing. Asking for 480Hz and getting 120Hz would make flicker easier to see at lower duty cycles. That said, I have kinda started working on a different library. I was looking to refactor some of the code to make it easier to maintain and understand what's happening at the lower levels, but it started to be clear that I would get a usable version of that refactor faster if I started clean and ported what I could instead. |
I’ve confirmed the bug did exist, it was putting the frequency at 1/4th what it should have been, and confirmed that the latest commit in the PR outputs the expected frequency. |
Board Type
Raspberry Pi Zero / 3B
Operating System
Raspian Stretch
Swift Version
Swift 3.1.1
Description
I've been using pigpio in Python to use the hardware PWM outputs to drive LEDs while also dimming them. That worked fine, and I got a nice smooth ramp from 0% to 100% duty cycle that looked good.
Because of perf issues with Python on the Zero with the rapid changes to the duty cycle needed, I gave SwiftyGPIO a shot, and it also works very well, but the behavior of killing and reconfiguring the clock every time the PWM frequency or dutycycle is changed causes unwanted flashing and flickering.
There also appears to be an issue where turning on one PWM channel turns the other off, possibly because of this clock change?
I've forked the repo so I can put together a revised implementation, which would be loosely based on how pigpio handles the clock, which makes this smooth updating of the duty cycle possible. The key difference is that pigpio configures the clock once with a fixed divisor of 2 for the PLLD clock. By using M/S mode, it can create any frequency up to (PLLD / 2) Hz without having to reinitialize the clock. My plan is to implement a similar behavior in the RaspberryPWM class where it can initialize the clock once for both PWM channels.
Unfortunately, if I wanted to avoid too many changes, it would probably require a lazy Singleton so that the different RaspberryPWM instances can store and share the clock state data independent of a specific pin/channel.
The PWM pattern code would be left alone if possible.
The text was updated successfully, but these errors were encountered: