6

This is admittedly a cross-post from LED fade malfunction (random flash) but I can't get an answer on the Arduino forum.

I was mucking around with some very basic code and I noticed that when repeatedly holding an LED at 0 brightness for 1 second and then fading in to full brightness, a small flash would occasionally happen at the beginning of each fade (seemingly random).

int led = 11;
int brightness = 0;

void setup()  
{ 
  pinMode(led, OUTPUT);
} 


void loop()  
{ 
  if(brightness >= 256) //checks if brightness has passed 255, resets to 0
  {
    analogWrite(led, 255);
    brightness = 0; 
  }
  analogWrite(led, brightness);
  if(brightness == 0)
    {
      delay(1000); //LED off for 1 second
    }

  brightness+=1; //increment brightness
  delay(20);
}

So, the thing that has me completely perplexed is that I can use a different piece of code (below) and the flash goes away!

int i = 0;
int led = 11;

void setup()
{
  pinMode(led,OUTPUT);
}

void loop()
{
analogWrite(led, i);
delay(6);
if(i%256 == 0)
{
  i = 0 ;
  delay(1000);
}
i++;
}

Has anyone got any clue as to why this would happen? Both programs have basically the same code, except for that i is reset to 0 in the first program whereas in the second, i keeps incrementing past 255 so that analogWrite 'overflows.' I think it must be a firmware, (or maybe a software?) problem.

There is a video on youtube of it happening here, Arduino - fading LED problem.

5
  • 2
    Try removing analogWrite(led, 255); as it's quite useless, given that two lines below it, it is set back to 0. Can't see anything really wrong with the code (other that a bit of a weird order).
    – Gerben
    Commented Nov 20, 2015 at 14:44
  • 1
    In your second code, change delay(6) to delay(20) - does the flash appear? You've got the second code rolling round three times faster than the first code (ignoring the 1-second delay, of course), so the random flash is probably undetectable. As for why there's a flash at all... no idea. Commented Nov 20, 2015 at 17:31
  • @Gerben That is true... :) Will do
    – Adrian
    Commented Nov 20, 2015 at 23:03
  • @CharlieHanson I have tried increasing the delay and it doesn't have any effect. I can still detect the flash with the 6 second delay. I have now got a good answer/explanation as to why it happens on the Arduino forum.
    – Adrian
    Commented Nov 20, 2015 at 23:06
  • Oops, I meant 6 millisecond delay.
    – Adrian
    Commented Nov 22, 2015 at 4:53

1 Answer 1

4

According to the links you provide from the arduino.cc forum the question is more or less answered. If not that important, just avoid analogWrite(led,0) and make it analogWrite(led,1)

if you still want that analogWrite(led,0), I've tested your code with the advice and it seems to work OK when changing the register manually:

#include "wiring_private.h"

int led = 11;
int brightness = 0;

void setup()
{
  pinMode(led, OUTPUT);
}


void loop()
{
  if (brightness >= 256) //checks if brightness has passed 255, resets to 0
  {
    brightness = 0;
    sbi(TCCR2A, COM2A1);
    OCR2A = 0; // set pwm duty
  }

  analogWrite(led, brightness);
  if (brightness == 0)
  {
    delay(1000); //LED off for 1 second
  }

  brightness += 1; //increment brightness
  delay(20);
}

Edit: to explain what those "strange codes" are

I'm not very expert in this field to explain how exactly this works but basically sbi is function defined in a macro by Atmel (?), it stands for "set bit in" and is used to change registers of ATmega chips. So basically what I did was change register defined by the macro TCCR2A (why? because it is the register that controls PWM in pin 11) and pass the bitmask COM2A1 (this is a mode of compare defined in datasheet) and OCR2A is a register used to store the compare value that defines duty cycle. Imagine a counter that every time it receives a tick from a signal clock it compares the value of the counter with the value stored in OCR2A and it sets the pin high or low if that value as been passed or not (more or less like this, depending on the mode stored on TCCR2A).

But in fact I've not done some black magic. I just looked into the code of analogWrite() and that is the way they use to set a value of PWM in pin 11:

void analogWrite(uint8_t pin, int val)
{
    // We need to make sure the PWM output is enabled for those pins
    // that support it, as we turn it off when digitally reading or
    // writing with them.  Also, make sure the pin is in output mode
    // for consistenty with Wiring, which doesn't require a pinMode
    // call for the analog output pins.
    pinMode(pin, OUTPUT);
    if (val == 0)
    {
        digitalWrite(pin, LOW);
    }
    else if (val == 255)
    {
        digitalWrite(pin, HIGH);
    }
    else
    {
        switch(digitalPinToTimer(pin))
        {

...

          #if defined(TCCR2A) && defined(COM2A1)
            case TIMER2A:
                // connect pwm to pin on timer 2, channel A
                sbi(TCCR2A, COM2A1);
                OCR2A = val; // set pwm duty
                break;
          #endif
...

}

So basically I just used that info to set the register to zero, as suggested from the arduino.cc forum link that you have.

If you want to know more about PWM in Arduino, this site has a lot of info and explains a lot of the modes of registers also.

6
  • Thanks @Personagem, I will test it, but could you please explain the use of sbi, TCCR2A, COM2A1, and OCR2A. Also, considering that wiring_private.h is of the included header files in the Arduino directory, is it necessary to include it?
    – Adrian
    Commented Nov 20, 2015 at 23:14
  • Also, how do you learn how to use these libraries in the first place??
    – Adrian
    Commented Nov 20, 2015 at 23:20
  • 1
    @Adrian I've edit to explain a bit of those codes and arduino IDE complains if I do not made that include. I'm not really an expert but if you want to dig in, the datasheet of atmega is your friend. This should be used in kinda of advanced way. What arduino.cc team did ( and that is the real beauty that change a bit everyone's world) was create simple functions that don't need typical user to dig into datasheets and some registers settings. They kinda made simple what could be hard for not so experienced people. However if you really need you can look at all code in github of arduino
    – brtiberio
    Commented Nov 21, 2015 at 0:00
  • 1
    Wouldn't analogWrite(led,1) accomplice a similar effect to sbi(TCCR2A, COM2A1);OCR2A = 0;? I.e, setting the duty cycle to a very low value, just before setting the output to LOW. That would make it a lot more readable.
    – Gerben
    Commented Nov 21, 2015 at 13:35
  • 1
    yes it does, I've suggested that in first sentence. But in case he really wanted for any reason or just curiosity this should be the way. In fact the problem relies on how analogWrite function handles values of 0 and 255 without changing the registers
    – brtiberio
    Commented Nov 21, 2015 at 13:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.