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

Maximum PWM channels in use at one time #121

Open
briancampo opened this issue Oct 29, 2020 · 7 comments
Open

Maximum PWM channels in use at one time #121

briancampo opened this issue Oct 29, 2020 · 7 comments

Comments

@briancampo
Copy link

First off, thanks so much for this project!!

I'm trying to control several PWM channels concurrently and seem to have hit a max of 4 in use at any one time. Granted this is on a RasPi 4, but hoping you may be able to help or give some insight on some challenges with this board. I've tried a few different scenarios and get some mixed results depending on the scenario. The most peculiar is this...

I ramp up the PWMDutyCycle from 0 to 500 (range is 1000) across 5 total channels. The ramp is done sequentially with each channel ramping up to 500 via a while loop with a delay based on the duration of the ramp. When it hits 500 I end the loop and leave the channel at 500 and move on to the next. When I reach the 5th channel it does not send a signal, and what is more peculiar is that as it rises the other channels PWMDutyCycle begins to drop and when the 5th channel reaches 500 all channels are at 0 observed duty cycle. When running an led array it appears as all lights completely dark.

I can interchange the order of the channel being ramped up and it is always the 5th channel that causes this behavior.

When I try to ramp the PWMDutyCycle of the channels concurrently I can only get 3 channels working at one time before I get anomolous behavior, although different. When I try 4 or more channels concurrently I get blinking of the lights at a low duty cycle (~200) and as the duty cycle increases the PWM output goes to 0 for all channels once the duty cycle reaches around 250.

Not sure if the GPIO channels in use matter but the ones I have used for most of my testing are: 5, 6, 13, 19, 26

Let me know if any other info would be helpful..

@fivdi
Copy link
Owner

fivdi commented Oct 30, 2020

I am not aware of anything that would restrict the number of GPIOs that can use PWM to four.

What would help is an example program that is complete and as short as possible that can be used to reproduce the problem. Without such an example program I probably can't provide any help.

@briancampo
Copy link
Author

Thanks for the super quick response. Below is a very basic implementation that is also exhibiting the issues I'm seeing. Strangely with simpler script I am seeing the first issue happen when the third channel starts ramping up. Works fine with two.

When I run all three channels simultaneously I am getting the strange flicker. On the below just remove the startDelay incrementer and you should see.

import { Gpio } from 'pigpio';

async function sleep(delay: number) {
  return new Promise(resolve => setTimeout(resolve, delay));
}

async function gpioTest(job) {
  const { targetIntensity, channel, duration, pin, startDelay } = job;
  await sleep(startDelay);
  let currentIntensity = channel.getPwmDutyCycle();
  const brighten = currentIntensity <= targetIntensity;
  const modifier = brighten ? 1 : -1;
  const steps = (targetIntensity - currentIntensity) * modifier;
  const delay = duration / steps;
  let currentStep = 0;
  while (brighten ? (currentIntensity < targetIntensity) : (targetIntensity < currentIntensity)) {
    brighten ? currentIntensity++ : currentIntensity--;
    channel.pwmWrite(currentIntensity);
    currentStep++;
    const progress = Math.floor(currentStep / steps * 100);
    // job.progress(progress);
    console.info(`Set PWM duty to ${currentIntensity} on channel ${pin}`, '   ChannelProcessor');
    // if (currentIntensity === targetIntensity) {
    //   this.cleanupJob(job);
    // }

    await sleep(delay - 10);  //TODO if this is too long of a delay we could create another while to run and update progress
  }
}

function createChannel(pin: number) {
  const gpio = new Gpio(pin, { mode: Gpio.OUTPUT, pullUpDown: Gpio.PUD_DOWN });
  gpio.pwmWrite(0);
  gpio.pwmFrequency(200);
  gpio.pwmRange(1000);
  return gpio;
}

async function run() {
  let startDelay = 0;
  const jobs = [6, 4, 22].map(pin => {
    const channel = createChannel(pin);
    // startDelay += 12 * 1000;              //<<<<< comment this for simultaneous
    return { channel, pin, startDelay, targetIntensity: 500, duration: 10 * 1000 };
  });
  await sleep(5 * 1000);
  jobs.map(async job => await gpioTest(job));
  await sleep(60 * 1000);
}
run();

@fivdi
Copy link
Owner

fivdi commented Oct 31, 2020

I can't reproduce the error. The below JavaScript program which is a slightly modified version of the above TypeScript program was used but in theory this shouldn't make a difference. Note that the program here used GPIOs 16, 20 and 21 rather than 6, 4 and 22.

This is what I see when the program is run:

  • The three LEDs remain off for about five seconds
  • Over a period of about five seconds the three LEDs turn from fully off to approx. half brightness by slowly increasing the brightness
  • The LEDs remain at approx. half brightness for about one minute
  • The three LEDs are turned off or fully on (probably depends on the current state of the GPIOs just before program termination)
  • The program terminates
  • At no point is there any flicker

The test was performed on a Raspberry Pi 4 using Raspberry Pi OS (32-bit) Lite:

$ uname -a
Linux raspberrypi 5.4.51-v7l+ #1333 SMP Mon Aug 10 16:51:40 BST 2020 armv7l GNU/Linux

Here are some additional details related to the setup:

$ node --version
v14.11.0
$ pigpiod -v
71
$ npm list | grep pigpio
/home/pi/pigpio
└─┬ [email protected]
const Gpio = require('pigpio').Gpio; // <=== ********** CHANGED *******

async function sleep(delay) { // <=== ********** CHANGED *******
  return new Promise(resolve => setTimeout(resolve, delay));
}

async function gpioTest(job) {
  const { targetIntensity, channel, duration, pin, startDelay } = job;
  await sleep(startDelay);
  let currentIntensity = channel.getPwmDutyCycle();
  const brighten = currentIntensity <= targetIntensity;
  const modifier = brighten ? 1 : -1;
  const steps = (targetIntensity - currentIntensity) * modifier;
  const delay = duration / steps;
  let currentStep = 0;
  while (brighten ? (currentIntensity < targetIntensity) : (targetIntensity < currentIntensity)) {
    brighten ? currentIntensity++ : currentIntensity--;
    channel.pwmWrite(currentIntensity);
    currentStep++;
    const progress = Math.floor(currentStep / steps * 100);
    // job.progress(progress);
    console.info(`Set PWM duty to ${currentIntensity} on channel ${pin}`, '   ChannelProcessor');
    // if (currentIntensity === targetIntensity) {
    //   this.cleanupJob(job);
    // }

    await sleep(delay - 10);  //TODO if this is too long of a delay we could create another while to run and update progress
  }
}

function createChannel(pin) { // <=== ********** CHANGED *******
  const gpio = new Gpio(pin, { mode: Gpio.OUTPUT, pullUpDown: Gpio.PUD_DOWN });
  gpio.pwmWrite(0);
  gpio.pwmFrequency(200);
  gpio.pwmRange(1000);
  return gpio;
}

async function run() {
  let startDelay = 0;
  const jobs = [16, 20, 21].map(pin => {// <=== ********** CHANGED *******
    const channel = createChannel(pin);
    // startDelay += 12 * 1000;              //<<<<< comment this for simultaneous
    return { channel, pin, startDelay, targetIntensity: 500, duration: 10 * 1000 };
  });
  await sleep(5 * 1000);
  jobs.map(async job => await gpioTest(job));
  await sleep(60 * 1000);
}
run();

Questions:

  • Does the JavaScript program work for you?
  • Does removing the call to console.info() change the behaviour of the program at runtime?
  • Is there any other software running on the Raspberry Pi that could be blocking the Node.js program?

@fivdi
Copy link
Owner

fivdi commented Nov 8, 2020

@briancampo were you able to make any progress here?

@briancampo
Copy link
Author

@fivdi ,

Initially I was getting the same result when running your .js code as when I ran the .ts code. That got me thinking that maybe the issue is that I am sending the signal to drive some MeanWell LDDs which provide power to some high power LED arrays. I went back to my breadboard with bulb type LEDs and it seems to be ok.

With that I tried rebuilding everything (new drivers, new wiring, new LEDs, new Pi load, and a bare bones install. My Pi is running only node (via NVM), pigpio, Python and Python3, and Raspbian core with all updates avaialble as of 11/4. With this I am able to get 6 of the 8 channels I need running without issue, but when I try to bring in any additional channels I run into the previous issues. I tried a variety of different combos and rewiring to different channels to see if I could isolate anything but seem to come back to this.

Right now I'm trying to wire in an I2C PWM MC (PCA 9685) to see if I can rule out the software pwm or anything on the software suite as the issue, or if there might be something somewhere in the driver that is causing the issue.

Will follow up with what I get when I run the I2C controller.

Thanks again for the help and for checking in.

@ChrisCates
Copy link

ChrisCates commented Aug 14, 2021

@briancampo, @fivdi,

I'm having the same issue.
I'm trying to run 12 servos concurrently. Can only directly run 4 at a time.

Very doubtful it has anything to do with pigpio library itself, but instead an issue with the amount of amperes the RPi can tolerate.

Running servos with a separate power supply.
Have added shrink wrap on servo pins just in case leads are touching each other.

Still no avail.

I've been scouring the internet all over for a solution and to figure out how to mitigate this capacitor issue.
Will update you if I find a proper solution.

@ChrisCates
Copy link

@briancampo, @fivdi,

Another update here.

Turns out it's servo related.

Mind you, trying to run 12 servos concurrent can have some latency issues.
I found having a small 10ms delay before each servoWrite command helps improve latency issues.

Looks like my issue was completely hardware related. Not software.

Cheers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants