INPUT_PULLUP documentation is inconsistent

The documentation description of behavior when switching from pinMode() OUTPUT to INPUT is inconsistent.

The pinMode() page states
"Additionally, the INPUT mode explicitly disables the internal pull-up." I believe this is the correct description.

https://docs.arduino.cc/language-reference/en/functions/digital-io/pinMode/

However, the Digital Pins page contradicts this stating
"This works in the other direction as well, and an output pin that is left in a HIGH state will have the pullup resistors set if switched to an input with pinMode()."
https://docs.arduino.cc/learn/microcontrollers/digital-pins/

Additionally, the Analog Input Pins also contradicts the pinMode() page
"Similarly if the pin has been set to HIGH as an output, the pull-up resistor will be set, when switched back to an input."

https://docs.arduino.cc/learn/microcontrollers/analog-input/

It would be helpful to have all three of these pages describe the effect of switching to INPUT pinMode() the same way with regard to pullup resistor behavior. In particular, when pinMode() is set to INPUT, then the pullup resistor is disabled, regardless of the pin’s previous state when it was in OUTPUT mode.

edit: fixed links by removing trailing ’\’

The \ breaks the link.

Of course: thats what the INPUT-PULLUP is for.
If you need to be explicit about the connections perhaps you should look at using the data and data direction registers.

I agree, those pages seem to contradict.

Have you had time to verify, by experimentation, which description is in fact correct?

I don't know if anyone here has access to change the pages, if anyone I guess maybe @pert .

Or look at the code

void pinMode(uint8_t pin, uint8_t mode)
{
  uint8_t bit = digitalPinToBitMask(pin);
  uint8_t port = digitalPinToPort(pin);
  volatile uint8_t *reg, *out;

  reg = portModeRegister(port);
  out = portOutputRegister(port);

  if (mode == INPUT) {
    *reg &= ~bit;   // Set as input
    *out &= ~bit;   // Disable pull-up
  } else if (mode == INPUT_PULLUP) {
    *reg &= ~bit;   // Set as input
    *out |= bit;    // Enable pull-up
  } else { // OUTPUT
    *reg |= bit;    // Set as output
  }
}

a7

The code posted by @alto777 confirms, as suspected, that the pinMode() documentation is the correct one and the other two are incorrect.

Just for the fun of it, I did connect a 560k resistor to ground on both D10 and A0 and confirmed that when switching from an OUTPUT mode pin driven HIGH to mode INPUT, the pin correctly goes LOW (i.e. the internal pullup resistor is disabled).

It depends on the controller. Some AVR implement a hack that turns on the pullup resistor if HIGH is written to an INPUT pin. That hack also can affect switching between modes.

Where the "hack" is a "hardware feature."
This feature is generally not present in other controllers, and the Arduino core software are ... not at all consistent... about whether they try to provide compatibility for the hack in the digitalWrite() implementation. :frowning:

I understand the ‘hack’ of writing HIGH to a digital input, but that is tangential to the issue I have raised with incorrect documentation. To keep this thread on track, I would like to see the documentation changed to consistently describe the effect of switching to INPUT pinMode() with regard to the pullup resistor behavior.

What happens upon digital writes to INPUTs after that is a separate issue. If you feel the documentation is not properly representative of that behavior, it should be covered in another thread.

Thanks for your report @johni2. You can report problems or suggest enhancements to the documentation content via the technical support contact form:

https://www.arduino.cc/en/contact-us

That will be the best way to bring the matter to the attention of the people at Arduino who maintain the documentation.

Of course discussion about the documentation content is always welcome here on Arduino forum, but the documentation team do not closely monitor this very busy forum, so they may not see reports made here.

Switching between input and output is not a common operation. pinMode() is assumed to be used once for a pin in setup() and unchanged afterwards. Any unexpected behavior can occur when changing the pin mode later again.

How about three state logic? And charlieplexing?

And a parallel data bus being switched from write to read (like display shields with the MCUFRIEND pinouts).

Such approaches will work or even not work on certain controllers. No need to mention the behavior of each MPU.

That's another feature of microprocessors, not for microcontrollers. If you need such a bus then use a Mega with a 2560 family controller that implements such a bus in hardware.

Switching to tristate pinMode(pin, INPUT) will do fine, if the output was HIGH there will be a short period where the output will be held HIGH weakly by the pullup resistor before the it goes really tristate.
For switching to output use functions like these:

void switchToHigh(uint8_t pin) {  // to prevent temporary LOW on pin
  digitalWrite(pin, HIGH);        // prepare Output Register
  pinMode(pin, OUTPUT);           // set to Output Mode
}

void switchToLow(uint8_t pin) {  // to cover all cases
  digitalWrite(pin, LOW);        // prepare Output Register
  pinMode(pin, OUTPUT);          // set to Output Mode
}

This works on the standard AVR (UNO R3, MEGA2560), not on megaAVR (UNO WIFI R2, Nano Every), other boards I don't know.

What a strange statement.

Parallel data buses are definitely used in microcontrollers. Whether it’s controlled by software or hardware.

Parallel displays. External Sram. External FIFO chips. Cameras etc…

Inside yes, outside not. Problem is outside, not inside.

Sure, those are times to switch GPIO between input and output. But I think "not common" is still fair... (Although, isn't the LED array on Uno R4 WiFi, and probably Uno Q, CharliePlexed?)

Indeed uncommon. Not for the side of the microcontroller, but for the connected circuitry. It's deemed so much uncommon that in the Arduino Nano Every it's impossible to switch between output mode and input mode without the risk of unwanted pulses, and Arduino doesn't seem to care or they would have corrected it by now. Anyway, I use direct register access instead of Arduino Language (also saves 4µs per statement).

Then you obviously never had to port a project to a newer controller. The Arduino firmware allows to run the same code on different boards, really a great job :slight_smile:

My only suggestion to the pinMode() documentation were a comment that switching pin modes after setup() opens up a can of worms, different for each controller.

So... just as bad as using direct register access, eh ? :slight_smile:

It'd be nice if there were "advanced" versions of some core functions, with greater flexibility and more exact documentation.