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

two wire cc cw with swapped polarity #4112

Open
florenso opened this issue Aug 20, 2024 · 16 comments
Open

two wire cc cw with swapped polarity #4112

florenso opened this issue Aug 20, 2024 · 16 comments
Labels
enhancement fixed in source This issue is unsolved in the latest release but fixed in master

Comments

@florenso
Copy link

Is your feature request related to a problem? Please describe.
i have a led strip that contains cold and warm leds, but it only has two wires.
image

Describe the solution you'd like
I want two pwm channels (cc, cw) that are never high at the same time. so that i have a option to configure this type of led strip.

Describe alternatives you've considered
Use the led strip with only warm or cold light.

Additional context
I know a lot of chips cant handle phase shifting, but if you support it only for the easy ones (esp32 for example) i would be verry happy! (because i already solderd one..., would be awsome to add this functionality)

@blazoncek
Copy link
Collaborator

You can resolve this using additional circuitry and stock WLED.

@florenso
Copy link
Author

what kind of circuitry?
i could add a xor circuitry to one of the pwm signals, but even they would be in the same phase...

@blazoncek
Copy link
Collaborator

blazoncek commented Aug 21, 2024

Differential output comes to mind. You do not need phase shifted output for that.
Please use WLED forum or Discord for help and support question.

@blazoncek
Copy link
Collaborator

Correction. Using H-bridge (a mandatory circuit in this case) will require phase shifted PWM.

@blazoncek
Copy link
Collaborator

@jw2013 claimed he had a working solution for phase shifted PWM and exactly the same use case.

@jw2013
Copy link

jw2013 commented Aug 22, 2024

That's correct, I also needed a solution to run 'polarity change LED strings' via WLED.
As @blazoncek mentioned, using a H-bridge is mandatory, and it needs to be controlled via phase shift PWM. That's the complicated part.
Back then, I got it working on ESP8266 only, using an interrupt handler. The relevant working code looks like this:

unsigned char busPwmIntRoutine1Pin1 = 255;
unsigned char busPwmIntRoutine1Pin2 = 255;
unsigned char busPwmIntRoutine1Value1 = 255;
unsigned char busPwmIntRoutine1Value2 = 255;

void ICACHE_RAM_ATTR busPwmIntRoutine1() {
    if ( digitalRead(busPwmIntRoutine1Pin1) ) {
      GPOC = 1 << busPwmIntRoutine1Pin2;
    }
    else {
      GPOS = 1 << busPwmIntRoutine1Pin2;
    }
}

void analogWriteCombined(unsigned char gpio1, unsigned char gpio2, unsigned char value1, unsigned char value2) {

  if ( (gpio1 == 0xFF) || (gpio2 == 0xFF) ) return;

  if ( (busPwmIntRoutine1Pin1 == gpio1) && (busPwmIntRoutine1Pin2 == gpio2)
    && (busPwmIntRoutine1Value1 == value1) && (busPwmIntRoutine1Value1 == value2) ) return;

  busPwmIntRoutine1Pin1 = gpio1;
  busPwmIntRoutine1Pin2 = gpio2;
  busPwmIntRoutine1Value1 = value1;
  busPwmIntRoutine1Value2 = value2;

  if ( (value1 == 0) || (value1 == 255) || (value2 == 0) || (value2 == 255) ) {
    detachInterrupt(digitalPinToInterrupt(gpio1));
    analogWrite( gpio2, value2 );
    analogWrite( gpio1, value1 );
    return;
  }

  unsigned int value = value1 + value2;

  if ( value < 253 ) {        // !!!D*RTY WORKAROUND: use overlap instead of gap

    unsigned int overlap = 253 - value;

    analogWrite( gpio1, value1+overlap );
    analogWrite( gpio2, overlap );

    attachInterrupt(digitalPinToInterrupt(gpio1), &busPwmIntRoutine1, FALLING);
  }
  else if ( value > 255 ) {

  }
  else {

    analogWrite( gpio1, value1 );
    digitalWrite( gpio2, LOW );

    attachInterrupt(digitalPinToInterrupt(gpio1), &busPwmIntRoutine1, CHANGE);
  }
}

Later I found that there also exists a phase shift PWM API for ESP8266 only, but I never rewrote the WLED code (more below).

As motor drivers, depending on the voltage, I used either DRV8833 (3V to 10V) or DRV8871 (6.5V to 45V).
Most polarity change LED strings use 31V, I assume that's also the case for you?

It would also be possible to use darlington drivers like L293D and L298D, but those are ancient and cause a big voltage drop.

It's funny that the question came up today, as right now I'm working on a completely different approach, that will be portable, and supports more channels:

https://www.wemos.cc/en/latest/d1_mini_shield/hr8833_motor.html (3V to 10V)
https://www.wemos.cc/en/latest/d1_mini_shield/at8870_motor.html (6.5V to 38V)

OOTB, those motor shields are only usable via the LOLIN_I2C motor library, which does not expose the functionality required for phase shift PWM. So I started to develop my own firmware for the onboard microcontroller STC8H1K08, to make it behave similar to the PCA9685 :-)

I already got some working code. If others are interested, I'll consider making this open source.
BTW: The same motor drivers, using that firmware, could also drive non-addressable RGBW LED strips, with phase shift functionality included. Just saying ;-)

@jw2013
Copy link

jw2013 commented Aug 22, 2024

The 'official' way to create a phase locked PWM can be found here, at least for ESP8266:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_waveform.h
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_waveform_phase.cpp

IIRC, one needs to call enablePhaseLockedWaveform(), to make the linker use core_esp8266_waveform_phase instead of core_esp8266_waveform_pwm.

@blazoncek
Copy link
Collaborator

There are currently two people interested into this @PaoloTK and @DedeHai.

@blazoncek
Copy link
Collaborator

@DedeHai & I have a POC ready (untested). If you want a binary, contact me on Discord.

@jw2013
Copy link

jw2013 commented Aug 24, 2024

The video below shows an AT8870 motor shield (custom firmware), connected to a polarity change fairy light.
Please excuse the quality, it's running at 240 Hz (240 Hz * 255 microsteps = 61200 interrupts per second), still my cellphone records a lot of flickering. Looks perfect for the human eye though :-)

VID_20240824_141347561_neu.mp4

@jw2013
Copy link

jw2013 commented Aug 24, 2024

Just tested the idea on a (analog) 12V RGBW strip, 5m with 108 LEDs/m. Works perfectly, too.
Now going to read #4107 regarding a proper implementation as a bus.
IMG_20240824_230328114

@blazoncek
Copy link
Collaborator

@jw2013 you may want to check bus-config branch to use future implementation. @PaoloTK was also instructed to do so.

That branch already includes PWM phase shifting POC by @DedeHai though it is currently flawed but does work.

@DedeHai
Copy link
Collaborator

DedeHai commented Aug 25, 2024

working (but not final) implementation:
#4115

@jw2013
Copy link

jw2013 commented Aug 25, 2024

@blazoncek, referring to https://github.com/Aircoookie/WLED/blob/bus-config/wled00/bus_manager.cpp#L687

The existing Bus classes are hardcoded in the BusManager::add() method.
How would I correctly add support for an I2C based PWM bus, which does not use any pins, but makes use of the global 'Wire' instance?

  1. by extending the implementation of BusPwm, to also cover I2C, based on the BusConfig? or
  2. by creating a new Bus class, e.g. BusWire?

Regarding the settings_leds.html and const.h, I'd like to use something like that:

<option value="75">I²C Polarity</option>
<option value="76">I²C White</option>
<option value="77">I²C CCT</option>
<option value="78">I²C RGB</option>
<option value="79">I²C RGBW</option>

@blazoncek
Copy link
Collaborator

@jw2013 that's something similar like @netmindz is doing with hub75 support.
bus-config branch is supposed to provide that in the future. ATM it is still a POC waiting for enhancements.

Other parts of WLED currently require at least one GPIO to be allocated to function properly.

But this has nothing to do with this issue so please open a new one. Better yet, join discussion on Discord.

@blazoncek
Copy link
Collaborator

@florenso please use bus-config branch and report if the LEDs are working.
You will need to enable "Phase shift" in settings. And make sure you have short-circuit protection (i.e. fuse) in place just in case.

@blazoncek blazoncek added the fixed in source This issue is unsolved in the latest release but fixed in master label Nov 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement fixed in source This issue is unsolved in the latest release but fixed in master
Projects
None yet
Development

No branches or pull requests

4 participants