How to use 9 independent PWM outputs

I have designed a sculpture that incorporates three independent RGB LEDs. I based the circuitry around the photon only to find out that only 7 PWM pins can output individual signals. I really do not want to change micro-controller because I have another sculpture with RGB lighting powered by a photon and I want to keep the same platform.

Is there anyway to unlock all 9 PWM outputs so that they are seperate? Would I be able to create a PWM function within the code to convert a standard pin into a PWM pin?

My project only has three independent RGB LEDs (taking up 9 pins), and only uses the default tinker app as its input.

@bionboy, will you be changing the PWM at fast intervals? The reason I ask is that some time ago, I created a softw PWM library which you can find on the web IDE. It allows you to use any GPIO pin as a PWM output.

Otherwise, there is no way to get extra “hardware” PWM pins on the Photon. Another approach would be to use a multi-channel PWM board like this one from Adafruit:

1 Like

Yes, I was just about to recommend peekay123’s library and the Adafruit PCA9685 board. They work great with the Photon!

1 Like

The PWM channels will be changed periodically by the user through the tinker application so your library seems like it would work fine. I have little experience dealing with the smartphone end of photon projects and it seems like if I use your library I would have to create my own layout.

@bionboy, unfortunately there are no scenarios where you won’t have to modify the phone app.

@peekay123, would this link be the best way to learn how to create such an app?
how-to-build-a-product/mobile-app

@bionboy, it is a good start!

Just for completeness, since the other suggestions seem nicer:

There is, but it’d involve some “hacking”.

You can also use the three RGB LED GPIOs via the bottom solder pads on your Photon.

See here https://docs.particle.io/datasheets/photon-datasheet/#pin-out-diagrams
And here https://docs.particle.io/datasheets/photon-datasheet/#recommended-pcb-land-pattern-photon-without-headers-

1 Like

I wrote a quick code to test the sculpture once it is built. I would appreciate it if you could take a look.

#include "SoftPWM/SoftPWM.h"
   
//rgb channels for the 3 rgb leds
const int r0 = D0;
const int g0 = D1;
const int b0 = D2;
const int r1 = D3;
const int g1 = A4;
const int b1 = A5;
const int r2 = WKP;
const int g2 = RX;
const int b2 = TX;

int rstate0;
int gstate0;
int bstate0;
int rstate1;
int gstate1;
int bstate1;
int rstate2;
int gstate2;
int bstate2;

randomSeed(analogRead(A0));

void setup() {
    
    //set pwm pins as outputs
    pinMode(r0,OUTPUT);
    pinMode(g0,OUTPUT);
    pinMode(b0,OUTPUT);
    pinMode(r1,OUTPUT);
    pinMode(g1,OUTPUT);
    pinMode(b1,OUTPUT);
    pinMode(r2,OUTPUT);
    pinMode(g2,OUTPUT);
    pinMode(b2,OUTPUT);

    //set initial state of pwm outputs
    rstate0 = random(255);
    gstate0 = random(255);
    bstate0 = random(255);
    rstate1 = 0;
    gstate1 = 0;
    bstate1 = 0;
    rstate2 = 0;
    gstate2 = 0;
    bstate2 = 0;

    //begin softPWM and set fade time
    SoftPWMBegin();
    SoftPWMSetFadeTime(ALL,100,100);

    //turn all pins off
    SoftPWMSet(r0, 0);
    SoftPWMSet(g0, 0);
    SoftPWMSet(b0, 0);
    SoftPWMSet(r1, 0);
    SoftPWMSet(g1, 0);
    SoftPWMSet(b1, 0);
    SoftPWMSet(r2, 0);
    SoftPWMSet(g2, 0);
    SoftPWMSet(b2, 0);
}
  
void loop() {

    //set pwm output values
    SoftPWMSet(r0,rstate0);
    SoftPWMSet(g0,rstate0);
    SoftPWMSet(b0,rstate0);
    
    SoftPWMSet(r1,rstate1);
    SoftPWMSet(g1,rstate1);
    SoftPWMSet(b1,rstate1);
    
    SoftPWMSet(r2,rstate2);
    SoftPWMSet(g2,rstate2);
    SoftPWMSet(b2,rstate2);

    //shift pwm states
    rstate2 = rstate1;
    gstate2 = rstate1;
    bstate2 = rstate1;
    
    rstate1 = rstate0;
    gstate1 = rstate0;
    bstate1 = rstate0;
    
    rstate0 = random(255);
    gstate0 = random(255);
    bstate0 = random(255);
    
    delay(10000);
}

Are there any issues with the pins I used or my use of the library?

@bionboy, have you tried it? That’s the best way to know!

I would but unfortunately the circuitry completion depends on the progress of the sculpture. Because of this I can’t test it at this moment.
Does the SoftPWM function work on all pins (such as RX, TX, and WKP)?

Yes, it should.

I’d vote for using arrays for the pins and colors which would enable you to use indexes and loops for setup and control.
AND I think you don’t want to use the red state on all your colors :wink:
Typical copy-paste issue, which happens less likely when using indexes and loops too.

2 Likes

@ScruffR Thanks for the coding tip! I am obviously a bit out of practice.

If anyone is curious here is my revised code:

#include "SparkIntervalTimer/SparkIntervalTimer.h"
#include "SoftPWM/SoftPWM.h"

uint8_t chan[9] = {D0, D1, D2, D3, A4, A5, WKP, RX, TX};    //rgb channels for the 3 rgb leds

uint8_t state0[3];
uint8_t state1[3];
uint8_t state2[3];

void setup() {
for (int i = 0; i < 9; i++){        //set pwm pins as outputs
    pinMode(chan[i], OUTPUT);
}

for (int i = 0; i <3; i++){         //set initial state of pwm outputs
    state0[i] = 0;
}
for (int i = 0; i <3; i++){
    state1[i] = 0;
}
for (int i = 0; i <3; i++){
    state2[i] = 0;
}

SoftPWMBegin();                     //begin softPWM and set fade time
SoftPWMSetFadeTime(ALL,100,100);

for (int i = 0; i < 9; i++){        //turn all pins off
SoftPWMSet(chan[i], 0);
}
}

void loop(){
randomSeed(analogRead(A0));

for (int i = 0; i < 3; i++){        //set pwm output values
SoftPWMSet(chan[i],state0[i]);
}
for (int i = 0; i < 3; i++){
SoftPWMSet(chan[i + 3],state1[i]);
}
for (int i = 0; i < 3; i++){
SoftPWMSet(chan[i + 7],state2[i]);
}

for (int i = 0; i < 3; i++){        //shift pwm states
state2[i] = state1[i];
}
for (int i = 0; i < 3; i++){
state1[i] = state0[i];
}
for (int i = 0; i < 3; i++){
state0[i] = random(255);
}

delay(10000);
}

I’d take it even further to :wink:

#include "SparkIntervalTimer/SparkIntervalTimer.h"
#include "SoftPWM/SoftPWM.h"

uint8_t chan[3][3] = {{D0, D1, D2}, {D3, A4, A5}, {WKP, RX, TX}}; 
uint8_t state[3][3];

void setup() {
  SoftPWMBegin();                     //begin softPWM and set fade time

  for (int i = 0; i < 3; i++){        //set pwm pins as outputs
    for(int c = 0; c < 3; c++)
    {
      pinMode(chan[i][c], OUTPUT);
      SoftPWMSet(chan[i][c], state[i][c] = 0);
    }
  }

  SoftPWMSetFadeTime(ALL,100,100);
}

void loop(){
  randomSeed(analogRead(A0));

  for (int i = 0; i < 3; i++){        //set pwm pins as outputs
    for(int c = 0; c < 3; c++)
    {
      SoftPWMSet(chan[2-i][c], state[2-i][c]);
      if (i < 2)
        state[2-i][c] = state[2-i-1][c];
      else
        state[2-i][c] = random(255);
    }
  }

  delay(10000);
}

3 Likes

I was wondering if you could nest arrays and was looking it up as you posted this. Thanks again @ScruffR!

1 Like

These are called multi dimensional arrays.

2 Likes