All Arduino boards have GPIO pins with digital and analog capabilities. The Arduino pinMode() function determines how the pins will operate. A surprise might be that in some cases it is not necessary to use it. And when you do, pinMode() may not always work the way you expect. This post outlines how the Arduino pinMode() function works and when you should (or not should) use it.
Arduino pinMode() scope
This post focuses on the 8-bit AVR Arduino boards such as the Uno, Mega, and Leonardo. The processors on these boards are the ATmega328, ATmega2560, and ATmega32u4, in that order. For the most part, this information does apply to non-AVR and 32-bit Arduino variants. When in doubt, double check with the Arduino Reference pages for details to specific platforms.
On power-up, all pins initialize as a digital high-impedance INPUT. This state reduces the chance of short circuits, especially if they become OUTPUTs later. One downside to this approach is it could leave some devices, like MOSFETs, floating. You should pull the gate of a MOSFET high or low using a pull-up or pull-down resistor.
For boards with a built-in LED, there is an exception. For most boards, this is Pin 13. On power-up, the main chip runs a special program called the bootloader. The primary purpose of the bootloader is to listen to the serial pins to see if there is new code to load into PROGMEM. The bootloader flashes the built-in LED. This action temporarily configures the pin as an OUTPUT. Once finished, bootloader returns the LED’s pin to the INPUT state. Usually, this is not a concern, and you could probably continue to use the pin as a regular I/O pin.
Something you need to consider: can your circuit tolerate the LED Pin temporarily becoming an OUTPUT? Can it also tolerate that pin toggling between HIGH and LOW? Even though there are buffer circuits on most boards, an additional 1k current limiting resistor may be a good idea, just in case.
Analog Input pins are used to measure a voltage. Sometimes I see people use Arduino’s pinMode() to configure it as an INPUT. However, this is not necessary, for two reasons.
- pinMode() sets up a pin for use as a digital input, not analog input.
- When calling analogRead(), it reconfigures the Analog Pin for “input.”
Analog Input pins are unique because they connect to an analog multiplexer, which connects to the single analog-to-digital converter (ADC). So for analogRead() to work, the multiplexer has to be configured first. This automatic step eliminates the need to call pinMode() on analog pins.
Analog Output (PWM)
Unlike digitalRead(), which can be used on both INPUT and OUTPUT, analogWrite() only works for OUTPUT. (Read this article if you did not know digitalRead() could be used on digital OUTPUTs.) analogWrite() works on pins which support Pulse-Width Modulation (PWM), so it only makes sense to use it as an OUTPUT. That being the case, like analogRead(), analogWrite() automatically sets the pin to OUTPUT when called.
The Arduino IDE 1.0.1 added a new pinMode() mode: INPUT_PULLUP. Adding this mode changed the default behavior of pinMode()’s INPUT. In case you are porting code or still using an older version of the Arduino library, here is what changed.
Before 1.0.1, when pinMode() is called with INPUT the current state of the PORTx is used to determine whether the pull-up resistor would be enabled or not.
1.0.1 and Later
Starting with 1.0.1, if pinMode() is called with INPUT, the internal pull-up resistor is explicitly disabled. However, when pinMode() is called with INPUT_PULLUP, the pull-up will be enabled. You can still override the state of the pin after pinMode() has been called by using digitalWrite(), like in pre-1.0.1.
So when it comes down to it, when do you use Arduino pinMode()? The only time you MUST call pinMode() is to set up a pin for use as a digital OUTPUT. As a best practice, if you plan to use a pin as a digital INPUT or analog OUTPUT (PWM), you should call pinMode() in setup(), even though it is optional. That way when you, or someone else, reads your code, you quickly see the pins in use.