Skip to content

Weird PCA9685 restrictions. #223

@AnonymousMonkeyNo12

Description

@AnonymousMonkeyNo12

I am currently working with the PCA9685 and I find the restrictions that the current implementation offers a bit limiting.

  1. private setPWM function
    Currently, you can basically pass an "on/off ratio" and diozero will turn the signal on at the start of the duty cycle and turn it off after the ratio. This makes it so that you can not offset the start of the signal from the start of the duty cycle. This is because the setPWM function is private and is only called through helpers that limit it.

private void setPwm(int channel, int on, int off) throws RuntimeIOException {
validateChannel(channel);
validateOnOff(on, off);
// Logger.debug("channel: {}, on: {}, off: {}", Integer.valueOf(channel),
// Integer.valueOf(on),
// Integer.valueOf(off));
// TODO Replace with writeWordData()?
// device.writeWordData(LED0_ON_L + 4 * channel, (short) on);
// device.writeWordData(LED0_OFF_L + 4 * channel, (short) off);
device.writeByteData(LED0_ON_L + 4 * channel, on & 0xFF);
device.writeByteData(LED0_ON_H + 4 * channel, on >> 8);
device.writeByteData(LED0_OFF_L + 4 * channel, off & 0xFF);
device.writeByteData(LED0_OFF_H + 4 * channel, off >> 8);
// SleepUtil.sleepMillis(50);
}

  1. opinionated validateOnOff function
    The validate function enforces that "off" must be smaller than "on", which is not at all necessary for the PCA9685 (See section 7.3.3 on page 16 of the doc https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf ). This makes it so that you can not implement "Example 2" from the same document, page 17. The semantics of the function are also not quite correct, because according to the documentation diagram, "off" is always after "on" despite "off" having a smaller value than "on".

private static void validateOnOff(int on, int off) {
if (on < 0 || on > MAX_VALUE) {
throw new IllegalArgumentException(String.format("Error: on (" + on + ") must be 0.." + MAX_VALUE));
}
if (off < 0 || off > MAX_VALUE) {
throw new IllegalArgumentException(String.format("Error: off (" + off + ") must be 0.." + MAX_VALUE));
}
// Off must be after on
if (off < on) {
throw new IllegalArgumentException("Off value (" + off + ") must be > on value (" + on + ")");
}
// Total must be < 4096
if (on + off > MAX_VALUE) {
throw new IllegalArgumentException(String.format("Error: on (%d) + off (%d) must be < %d",
Integer.valueOf(on), Integer.valueOf(off), Integer.valueOf(MAX_VALUE)));
}
}

(Examples 3 and 4 on page 18. might also not be possible in the current implementation, but I didn't think about them yet)


Why it matters:

Currently if I set 16 LED strips to half brightness, they all turn on and off in sync, causing a voltage peak and inducing a loud pieping/buzzing in a power supply.

To mitigate the noise, it is recommended to stagger the signals. For optimal staggering, some signals need their on cycle to cross a duty cycle, thus having an off before an on.


My proposal would be to:

  • make setPWM public
  • remove the "off must be after on" validation

I also don't quite understand what the InternalPwmOutputDeviceInterface is there for and whether I'd have to modify that. It seems to be shared by a lot of similar devices, but when I use the PCA9685, the functions calls do not go through that interface (and the name suggests it is for internal use?)

Should I do a PR or is there a reason that I am not seeing for why those two aspects are this way?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions