Arduino programming guide series
PWM and buffer overflow
What happens if you write a PWM value that is larger than the maximum value that the Arduino's analogWrite() function can accommodate? This is an interesting case of "buffer overflow".
The Arduino Uno is able to produce Pulse Width Modulation signals via pins 3, 5, 6, 9, 10, and 11. With PWM, you can approximate analog output programmatically and do things like fade an LED on and off or control the speed of a motor.
PWM values and register bits
In the Atmega328 (the chip that powers the Arduino Uno), the register that is used by the PWM function has a resolution of 8 bits. This gives you a total of 256 possible "analog" output levels, from 0 to 255.
If you attach an LED to a PWM-capable pin, you can drive it to 256 different brightness levels, from totally off (PWM value "0") to totally on (PWM value "255").
And if you attach a motor, you can drive it to 256 different speed levels.
Why 256? because the register contains 8 bits, and a binary number with 8 bits can be one of 2 ^ 8 = 256.
You can set a PWM value by using the analogWrite(pin, value) instruction.
So, analogWrite(3, 125) would set pin 3 to value 125.
How to overflow the PWM register
Now, here is where it gets interesting.
What happens if we set analogWrite to a value bigger than 255? Say, 256?
Let's think about this for a minute.
If the PWM value is 255, the binary version is 11111111 (total is 8 bits) is stored in the PWM register (feel free to use this calculator for such binary to decimal conversions). A connected LED would light up in maximum brightness.
Let's add 1 to the register, and make the PWM value 256.
The binary version of 256 is 0000000100000000 (total is 16 bits) since now we need two bytes to represent this value.
But, the Arduino (in reality, its Atmega328P chip) can only fit the first byte in its PWM register, the one in green.
The effect of PWM register overflow
The second byte will overflow and "disappear" (the red part).
So, what is actually stored in the PWM register is 00000000. This is decimal "0", which means that your LED is turned off.
In other words, analogWrite(3, 0) and analogWrite(3, 256) would have the exact same effect on an LED or a motor.
Add another "1" to the register, and the PWM value now is 257.
The binary version of 257 is 0000000100000001. The byte in green is stored in the PWM register, and the rest (in red) disappears. In the register now the decimal value "1" is stored.
The lesson to take home is that although you can set the PWM value in analogWrite to any decimal you like, only the first byte of this number will fit in the PWM register.
The rest will overflow and disappear.
New to the Arduino?
Arduino Step by Step Getting Started is our most popular course for beginners.
This course is packed with high-quality video, mini-projects, and everything you need to learn Arduino from the ground up. We'll help you get started and at every step with top-notch instruction and our super-helpful course discussion space.
Jump to another article
3. Focus on the type parameter in "println()"
4. "0" or "A0" when used with analogRead()?
5. What is the "_t" in "uint8_t"?
6. Save SRAM with the F() macro
7. What is the gibberish in the Telnet output?
9. Confusing keywords? follow the source code trail
10. The interrupt service routine and volatile variables
11. The problem with delay() and how to fix it
12. How to deal with the millis rollover
13. Can you use delay() inside Interrupt Service Routine?
15. A closer look at line feeds and carriage returns
16. Understanding references and pointers
17. Simple multitasking on the Arduino
19. Concurrency with the Scheduler library on the Arduino Due and Zero
20. Bitshift and bitwise OR operators
21. What is a "static" variable and how to use it
22. Understanding the volatile modifier
23. Optiboot, a free upgrade for your Arduino
Done with the basics? Looking for more advanced topics?
Arduino Step by Step Getting Serious is our comprehensive Arduino course for people ready to go to the next level.
Learn about Wifi, BLE and radio, motors (servo, DC and stepper motors with various controllers), LCD, OLED and TFT screens with buttons and touch interfaces, control large loads like relays and lights, and much much MUCH more.