What happens if you give a negative PWM value to analogWrite()?

To understand what happens when you give a negative PWM value to analogWrite we need to look into how the Arduino deals with negative numbers, and how those are used in the PWM function. The following contains some binary logic terms that you may not be familiar with, so I am sorry if I am about to confuse you – I will try not to.

The Arduino’s integer data type is 32 bits in total. The Arduino handles negative integers using the “two’s complement” method. That is a very common way to depict negative numbers in computers.

Let’s look at an example sketch:

int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup() {
  // declare pin 9 to be an output:
  pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
  // set the brightness of pin 9:
  analogWrite(led, brightness);
  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;
  // reverse the direction of the fading at the ends of the fade:
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount;
  }
  // wait for 30 milliseconds to see the dimming effect
  delay(20);
}

When you modify your sketch so that the “if” block looks like this:

if (brightness == 255) { fadeAmount = -fadeAmount ; }

… you are causing the brightness variable to change like this (you can “trace” this by hand, i.e. by running the sketch on paper, or inserting a Serial.println(brightness) statement inside the loop):

0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,255,250,245,240,235,230,225,220,215,210,205,200,195,190,185,180,175,170,165,160,155,150,145,140,135,130,125,120,115,110,105,100,95,90,85,80,75,70,65,60,55,50,45,40,35,30,25,20,15,10,5,0,-5,-10,-15,-20,-25,-30,-35,-40,-45,-50,-55,-60,-65,-70,-75,-80,-85,-90,-95,-100,-105,-110,-115,-120,-125,-130,-135,-140,-145,-150,-155,-160,-165,-170,-175,-180,-185,-190,-195,-200,-205,-210,-215,-220,-225,-230,-235,-240,-245,-250,-255,-260,-265,-270,-275,-280,-285,-290,-295,-300,-305,-310,-315,-320,-325,-330,-335,-340,-345,-350,-355,-360,-365,-370,-375,-380,-385,-390,-395,-400,-405,-410,-415,-420,-425,-430,-435,-440,-445,-450,-455,-460,-465,-470,-475,-480,-485,-490,-495,-500,-505,-510,-515,-520,-525,-530,-535,-540,-545,-550,-555,-560,-565,-570,-575,-580,-585,-590,-595,-600

You can see that brightness starts at zero as expected, goes up to 255, then starts counting down, again as expected. However, fadeAmount will never change sign again because there is no condition for that. So it will continue as negative one, and brightness will continue decreasing.

The PWM is only 8 bits, so it will only be able to use the first byte of the brightness variable (which is an int, therefore has 16bits/two bytes in it).

For example, -300 is “1111111011010100”, and the first byte is “11010100”, which is the value that the PWM register will use to control the brightness of the LED. Then, we have -305, which is “1111111011001111”, of which the PWM segment is “11001111” etc.

The effect of all these changes done quickly is the LED fading off and then turning on quickly.

Every time the brighness variable becomes -255 (1111111100000001) or one of its multiples, the PWM register will contain only the “00000001” part, and the LED will be almost off. The next value, -255 – 10 = -265 is “1111111011110111”. The PWM part of this binary is “11110111” at which the LED is almost completely turn on.

And the cycle continues for ever.

Don’t be discouraged if it isn’t, you may need to read it a couple of times. Here’s a two’s complement calculator to help you with some experiments.