PCA9685-Arduino
PCA9685-Arduino copied to clipboard
[Feature Request] Dynamic phase balancer to remove LED flickering/channel update hiccup
I'm trying to create a fade in/out effect with a LED strip and found an interesting "bug". It leads to a noticeable LED flickering when I change PWM duty value quite often (dozens of time per second). It seems to be related to default phase balancer method used in this library.
Here's a minimal code to notice the issue using oscilloscope:
PCA9685 pwmController;
void setup() {
Wire.begin();
Wire.setClock(400000);
pwmController.resetDevices();
pwmController.init(B000000);
pwmController.setPWMFrequency(1511);
pwmController.setChannelPWM(8, 2048);
}
void loop() {
pwmController.setChannelPWM(4, 2700);
delay(1000);
pwmController.setChannelPWM(4, 3300);
delay(2000);
}
Just to clarify what's going on here:
- Yellow line represents the issue on channel 4
- Cyan line is channel 8 and it shows internal cycle of PCA9685 (fall at 0, rise at 2048)
- White vertical line is aligned with start of cycle
- Violet&blue lines represent I2C communications
On the left side we observe previous settings of duty=3300, which (using default PCA9685_PhaseBalancer_Linear
) leads to phaseBegin: 1024, phaseEnd: 228
. I2C transfer in the middle changes this to duty=2700, which is phaseBegin: 1024, phaseEnd: 3724
for channel 4. However, PCA9685 does not apply all the changes on the next cycle. Instead it drops channel at desired time and keeps it off up to end of the cycle. Starting from next cycle it behaves normally.
As I mentioned above, when I change PWM duty frequently to achieve a fade effect – this leads to flickering.
As I discovered, this issue could be avoided by setting balancer to PCA9685_PhaseBalancer_None
, but I'd like to know if there's a way to keep phase balancing enabled and get rid of this issue at the same time.
Wow, I am going to have to spend some time reading in-full here, but I first wanted to thank you for your very detailed bug report and accompanying scope readout. I'll see what I can do.
So just to test a few things with you to narrow this down...
First, have you tried different mode parameters? You may try turning off the default totem-pole mode, or turning off the default ONACK mode. These might help out, but might not either.
Second, are you sure you need to use that high of a PWM frequency? Reason being is that, despite approaching the limit for this chipset, the prescaler value that winds up getting used at that high of frequency is almost always going to be the minimum (raw pre-scaler value of 3), and you could be seeing the after-effects of hardware lag.
I want to say that this isn't necessarily a library issue as you can see in your scope readout that the i2c line goes and communicates the change in PWM setting during the last high duty cycle, and then just abruptly stops. By that time index, the change in PWM setting has already been delivered to the chipset registers, and from then on, the chipset is in full control of what happens next.
So because of what I was reading into, I wanted to also mention that the library as of version 1.2.12 was using TOTEM_POLE mode as default for output driving (which enables an external NPN (or PNP, if INVRT mode set) driver that needs to exist on the board the PCA9685 is placed on - most do, some don't), and this has been changed in the most recent 1.2.13 to not use any init mode flags per default. This was because I've been hit with that same issue before, and one line from the datasheet in particular stood out at me: From datasheet Table 6. subnote [1]: "Some newer LEDs include integrated Zener diodes to limit voltage transients, reduce EMI, and protect the LEDs, and these -MUST BE- driven only in the open-drain mode to prevent overheating the IC" - would this maybe apply to your LED strip? :S
But I still contend that this may be a hardware issue, or some sort of setup issue, and I'm still going through the datasheet to see if there is anything I can find that would lead to a solution for ya. From what I can tell though, the library does its job and communicates over i2c to the IC and the IC should have the new phase values at the end of that transmission, and swap over to using it on the next cycle, but alas... I continue digging.
I'm going to do some more testing in the next couple of hours, just a quick reply so far.
Currently I am using a board like this. It seems to expose PCA9685 as is, adding only an in-line 220 Ohm resistor on each output. I connect some outputs to an external NPN MOSFET to drive a 24V LED strip, but it does not influence the issue (I've tried without FETs too).
I have scanned through the datasheet and it doesn't describe what should happen at the moment of switching in much detail. However, I've tried both ONACK and ON STOP modes – but it makes no visible difference.
One thing is a bit strange: I expected that ON STOP mode will lead to later moment of change. However, according to this scope screenshot I got yesterday, in ON STOP mode changes are applied in-cycle, without waiting for the cycle to end.
(on this shot we see a change from duty=4085 to duty=4094, both are nearly full on, with tiny spikes that could be seen - and a noticeable cycle in off-state)
P.S. Regarding your last changes – I don't think that making mode = 0x0
default value is a good idea. According to datasheet the default value for OUTDRV is 1 (totem pole output). Setting MODE2 register to 0x0 makes it open-drain output, which could break some existing code (and probably burn some hardware too).
I've tried it with a number of lower frequencies down to 24 Hz, and it's always the same. I also tried the open drain mode and it did not change anything.
Finally I came to a conclusion that I'm asking for too much. Let me illustrate it on the following scope shot:
It might look as a seamless change from duty=3300 to duty=1300. But it's probably not that seamless. The first OFF period (red arrow) is much longer that subsequent ones (green arrows).
The ideal behavior for PCA9685 in this case would probably be like this:
– add an extra ON pulse (drawn here in red). However, this would lead to 3 toggles (off-on-off) during one cycle (marked by green rectangle), which is probably not what this chip is capable of.
Long time no talk, alas, I return with an update...
So basically, software Linear phase balancing isn't going to work as originally intended, and phase balancing is now, as of v1.2.15, by default disabled. This is because the problem of software phase balancing is actually fairly tricky to get right and the best I've been able to track down after thinking about it and coding on this library on/off for a while now has been to simply back off the spacing from 256 steps between channels to just 16 steps. I hope this gives enough of a small shift for a lot of various applications it would ever be used in, but even then the problem is that when the module shifts from begHighPhase < endHighPhase to endHighPhase < begHighPhase, channel updates hiccup - and this is defined, just barely, on the Datasheet in Figure 11 (registers updated in cycle 1 are updated in cycle 3).
Looking around the web I have started seeing a very similar pattern emerging whereby the phase balancing is just not working, period, and people on websites have been (correctly) advising to put it manually to None.
But to be honest, as long as you have a decoupling capacitor on the V+ rail, 10v 1F, then the ground bounce/voltage spike on PWM channel change should be fairly minimal and the datasheet seems pretty confident that the only situation where that may come up is when the PCA9685 board is powering a bunch of devices connected to it.
I swear also that I heard, at one point in time, that this module actually does the phase shifting for us, and I don't know where I heard that from, but I could had sworn I read it somewhere. I don't have the frequency analyzer to compare two separate inputs however, so I cannot test to see if that's true or not. If you wanted to try it with your stuff I would love to know the results of such, but that's fine if you've moved on.
Anyways, going to leave this ticket up and rename the title one more time to a feature request for a dynamic software phase balancer that avoids the Figure 11 nonsense.
Also, check out the new version if you have a chance. :)
NR