-
Notifications
You must be signed in to change notification settings - Fork 61
Description
I am currently working with the PCA9685 and I find the restrictions that the current implementation offers a bit limiting.
- 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.
diozero/diozero-core/src/main/java/com/diozero/devices/PCA9685.java
Lines 275 to 291 in e03ad50
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); | |
} |
- 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".
diozero/diozero-core/src/main/java/com/diozero/devices/PCA9685.java
Lines 293 to 309 in e03ad50
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?