Crashing when sending analogwrite value above zero

I have a very strange problem, which I wonder if someone might be able to offer some insight into.

I wrote a program to control the color of an RGB LED depending on the status of a variable. The anodes are connected to digital outputs 3, 5 & 6 on my Uno, the cathode is connected to digital output 9. My code sets 3, 5 & 6 to HIGH, while 9 is set to LOW.

Using analogwrite on these four pins allows me to control the mix of RGB to set a desired colour mix, and control the overall brightness of the LED by writing a value to the cathode on pin 9. (When one particular status is set, I want the LED brightness to fade up and down quite quickly, and using a PWM pin as a sink seemed like a sensible approach.)

This all worked beautifully.

However, today I added a RF receiver to the project, as I want to control the state of the LED remotely, and I'm using the VirtualWire library. Again, this all works beautifully, unless I analogwrite anything but zero to pin 9 (ie. full LED brightness), in which case the Uno crashes instantly. If I stick to writing zero to pin 9, I can mix the RGB values to my heart's content and the project functions perfectly over RF with no issues.

I've scraped through the VW library and can't find any clashes with anything in there which might be trying to use the same pin. The default pins are 10, 11 and 12 - I'm not touching those pins for anything other than the RF module.

Any ideas?

Thought you might say that... here it is:

#include <VirtualWire.h>

uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;

#define RED 3
#define GREEN 5
#define BLUE 6
#define GNDPIN 9

int playerstatus = 3;

// define colour for different light states

int outColor [] = {
  50, 0, 0};
int inColor [] = {
  80, 255, 0};
int playColor [] = {
  240, 255, 245};

// define variables for rgb colors and set to zero

int r_val = 0;
int g_val = 0;
int b_val = 0;

int led_GNDPIN_val = 0;
int GNDPIN_fade_direction = 0;

// timer variables

unsigned long led_timer1;
unsigned long led_timer2;
unsigned long led_timer3;
unsigned long rx_timer1;

// pace of light fading

int led_fadeDelay = 1;
int led_flashDelay = 5;




void setup() {

  Serial.begin(9600);

  // set up the RF receiver
  vw_set_ptt_pin(8);
  vw_set_ptt_inverted(true); // Required for DR3100
  vw_set_rx_pin(11);
  vw_set_tx_pin(12);
  vw_setup(4000);  // Bits per sec
  pinMode(13, OUTPUT);

  vw_rx_start();       // Start the receiver PLL running

  // set up the pins for the RGB LED

  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  pinMode(RED, OUTPUT);
  pinMode(GNDPIN, OUTPUT);
  digitalWrite(GREEN, HIGH);
  digitalWrite(BLUE, HIGH);
  digitalWrite(RED, HIGH);
  digitalWrite(GNDPIN, LOW);

  // set up timer variables

  led_timer1 = millis();
  led_timer2 = millis();
  led_timer3 = millis();
  rx_timer1 = millis();

}


void loop() {

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
      if(buf[0]=='1'){
        playerstatus = 1;
      }  
      if(buf[0]=='2'){
        playerstatus = 2;
      }
      if(buf[0]=='3'){
        playerstatus = 3;
      }
      
      digitalWrite(13,1);
      rx_timer1 = millis();
    }

  if (millis() > (rx_timer1 + 100)) {
    digitalWrite(13,0);
  }

  setstatuscolor();
  
  Serial.println(millis());
}




// SETS THE COLOUR OF THE LED DEPENDING ON THE VALUE IN 'playerstatus'
// 1 = out of the hand but in the game
// 2 = in the hand but not my turn
// 3 = my turn to play

void setstatuscolor() {

  if (playerstatus == 1) {

    if (millis() > (led_timer1 + led_fadeDelay)) {
      if (r_val < outColor[0]) {
        r_val ++;
      } 
      else if (r_val > outColor[0]) {
        r_val --;
      }
      if (g_val < outColor[1]) {
        g_val ++;
      } 
      else if (g_val > outColor[1]) {
        g_val --;
      }
      if (b_val < outColor[2]) {
        b_val ++;
      } 
      else if (b_val > outColor[2]) {
        b_val --;
      }

      if (millis() > (led_timer3 + led_flashDelay)) {
        if (led_GNDPIN_val > 0) {
          led_GNDPIN_val --;
        }
        led_timer3 = millis();
      }

      led_timer1 = millis();
    }
  } 


  else if (playerstatus == 2) {

    if (millis() > (led_timer1 + led_fadeDelay)) {
      if (r_val < inColor[0]) {
        r_val ++;
      } 
      else if (r_val > inColor[0]) {
        r_val --;
      }
      if (g_val < inColor[1]) {
        g_val ++;
      } 
      else if (g_val > inColor[1]) {
        g_val --;
      }
      if (b_val < inColor[2]) {
        b_val ++;
      } 
      else if (b_val > inColor[2]) {
        b_val --;
      }
      if (millis() > (led_timer3 + led_flashDelay)) {
        if (led_GNDPIN_val > 0) {
          led_GNDPIN_val --;
        }
        led_timer3 = millis();
      }

      led_timer1 = millis();
    }
  } 


  else if (playerstatus == 3) {

    if (millis() > (led_timer1 + led_fadeDelay)) {
      if (r_val < playColor[0]) {
        r_val ++;
      } 
      else if (r_val > playColor[0]) {
        r_val --;
      }
      if (g_val < playColor[1]) {
        g_val ++;
      } 
      else if (g_val > playColor[1]) {
        g_val --;
      }
      if (b_val < playColor[2]) {
        b_val ++;
      } 
      else if (b_val > playColor[2]) {
        b_val --;
      }
      led_timer1 = millis();
    }

    if (r_val == playColor[0] && g_val == playColor[1] && b_val == playColor[2]) {

      if (millis() > (led_timer3 + led_flashDelay)) {

        if (GNDPIN_fade_direction == 0 && led_GNDPIN_val > 0) {
          led_GNDPIN_val = (led_GNDPIN_val - 1);
        } 
        else {
          GNDPIN_fade_direction = 1;
        }

        if (GNDPIN_fade_direction == 1 && led_GNDPIN_val < 200) {
          led_GNDPIN_val = (led_GNDPIN_val + 1);
        } 
        else {
          GNDPIN_fade_direction = 0;
        }

        led_timer3 = millis();

      }

    }



  }


  analogWrite( RED, r_val );
  analogWrite( GREEN, g_val );
  analogWrite( BLUE, b_val );
  analogWrite( GNDPIN, led_GNDPIN_val );

}

Best I can think is that pin 9 PWM might be using a timer that the VW library uses.

You could try implementing soft-PWM on pin 9 but really the way it works isn't an even change on the RGB pins.

GoForSmoke - I think you could be right. The VW library does do all sorts of weird things with timers, I had no idea these used specific PWM pins.

The RF transmitters and receivers don't require PWM pins so I'll try moving these and drop the cathode onto one of those.

Thanks for your help.

ArduinJoe:
GoForSmoke - I think you could be right. The VW library does do all sorts of weird things with timers, I had no idea these used specific PWM pins.

The RF transmitters and receivers don't require PWM pins so I'll try moving these and drop the cathode onto one of those.

Thanks for your help.

I'm just guessing. Different PWM pins are tied to different timers as far as I remember so check!.
You'll run out of timers before you run out of PWM pins.

You might try soft-PWM where your code uses millis() to turn the pin HIGH and LOW without a dedicated timer but for all the cycles that would use it's probably better to just change the RGB values in a small fraction of a millisecond.

Using analogwrite on these four pins allows me to control the mix of RGB to set a desired colour mix, and control the overall brightness of the LED by writing a value to the cathode on pin 9. (When one particular status is set, I want the LED brightness to fade up and down quite quickly, and using a PWM pin as a sink seemed like a sensible approach.)

Are there any resistors in those LEDs.

This all worked beautifully.

No it didn't did you look at the signals on a scope.
You are using two lots of PWM and they are going to beat causing intermittent operation. While it might sound a good idea it is not.

I'm using the VirtualWire library.

Does this by any chance use one of the timers used by the PWM on pin 9?

Are there any resistors in those LEDs.

Yes, I have a 220R between each of output pins and the anodes. I wanted three so I can change them around to improve white balance when RGB values are 255, 255, 255.

No it didn't did you look at the signals on a scope.
You are using two lots of PWM and they are going to beat causing intermittent operation. While it might sound a good idea it is not.

I used my eyes, which function pretty well! The LED was doing exactly what I wanted it to do, and it looked pretty sweet. I have left it running and switching between different colour modes, flashing, fading for many hours with no issue. What would a scope tell me that my eyes don't?

Does this by any chance use one of the timers used by the PWM on pin 9?

I believe it does use timer1, which defaults to pin 9.

Ha! Switched the LED cathode to pin 11 and the RX/TX pins to 7 and 8. All working good again!

Thanks for your help folks, wouldn't have ever figured that out on my own.

used my eyes, which function pretty well!

No you have a lot to learn. Can you eyes spot ringing? Can they spot jagged rise times. Your eyes have 30HZ filter on them they will not see anything faster.

I assume you are of the school of if it looks fine it is fine. Well electronics dosn't work like that. A scope can see problems that you will miss and head them off at the pass. Have you tested all combinations of of duty cycle?
Well you haven't because there are over 65,000 of them.

LOL, how about bypass caps on the led pins?

On the Uno:

timer0 - 1024us period - millis(), delay(), micros() and PWM pins 5 & 6
timer1 - 2040us period - PWM pins 9 & 10,
timer2 - 2040us period - PWM pins 11 & 3

Using timer1 and timer2 on the same LED will lead to dependencies
on the initial phase of the timers since they are clocked in unison. Bad plan,
you don't need to PWM both ends of an LED, and driving 3 LEDs from one
pin sounds like you may well be overloading it (40mA absolute max per pin)

Grumpy_Mike:

used my eyes, which function pretty well!

No you have a lot to learn. Can you eyes spot ringing? Can they spot jagged rise times. Your eyes have 30HZ filter on them they will not see anything faster.

I assume you are of the school of if it looks fine it is fine. Well electronics dosn't work like that. A scope can see problems that you will miss and head them off at the pass. Have you tested all combinations of of duty cycle?
Well you haven't because there are over 65,000 of them.

Chuckle

If there's one thing I've learned in life, it's that we all have much to learn.

I'm more of the school of Move Fast And Break Things. I'll be dead long before I've investigated 65,000 combinations of duty cycle, so I'll carry on making lights flash in a colourful way. If I fry a few two-dollar microchips along the way, so be it!

MarkT:
Bad plan,
you don't need to PWM both ends of an LED, and driving 3 LEDs from one
pin sounds like you may well be overloading it (40mA absolute max per pin)

At a risk of contradicting myself on the fried chips, this sounds like advice worth heeding - I'll test the current being sunk into the pin and rethink if you're correct. There's a roundabout way to do the same thing with more complex code.

Again, thanks for your practical help folks - it's much appreciated.

I'll be dead long before I've investigated 65,000 combinations of duty cycle, so I'll carry on making lights flash in a colourful way.

That is my point, a scope would have told you this, your eyes would have not.
If you are not willing to take advice then why ask for it in the first place?

:roll_eyes:

Stuck my meter across the sink pin, and it's drawing (sinking?) 21ma with R, G and B LEDs at full brightness with no PWM.

Let the next phase begin...