Can write an INPUT HIGH but not LOW ?

defragster

Senior Member+
I made an error with #defines and ended up re-using the same pin for two functions one INPUT and one OUTPUT. This won't work obviously and my simplified code demonstrates this error, in the first two lines. It was subtly mixed in with other stuff I need to clean up - but moving it from three working boards with a unique array of pins to a fourth board the change crept in.

The code below shows anomalous behavior it seems to me that made debugging it not what it first seemed it would be. Second post to follow doing this on LED_BUILTIN pin acts differently

Intro: I set up an OUTPUT pin to LOW. ( Correct ) The same pin is then set out INPUT. ( Error )

Logically: Given the pin is now INPUT I would expect any attempt to write to the pin to be ignored.

Problem: The code below shows the pin will take a digitalWrite(LED_BUILTIN, HIGH); but not a corresponding digitalWrite(LED_BUILTIN, LOW);

Question: Is there any reason to expect or consider this behavior normal, or is it a bug?

Sample: Code below demonstrates the problem. I put in a 10 sec wait between the three steps as the LED_BUILTIN changes to match the pin 3 value as read for confirmation.

Code:
#define THREE 3
[B]#define FOUR 3[/B]    // This represents the coding error I made
elapsedMillis aTime;
void showstatus( String info );

void setup() {
  Serial.begin(9600);
  while (!Serial && (millis () <= 5000)) ;  // Wait for Serial to come online
  Serial.println("\n\n\nHello Out & In Error");
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(THREE, OUTPUT);
  digitalWrite(THREE, LOW);
[B]  pinMode(FOUR, INPUT);[/B]
  showstatus( " setup() : user err OUTPUT redefined INPUT " );
}

void loop() {
  if ( aTime >= 10000 && aTime <10001) {
    showstatus( " loop() NO CHANGE" );
    delay(2); // prevent re-entry this millisecond
  }
  if ( aTime >= 20000 && aTime <20001) {
    digitalWrite(THREE, HIGH);       // set INPUT HIGH - WORKS
    showstatus( " loop() Set INPUT HIGH - THIS WORKS ???" );
    delay(2); // prevent re-entry this millisecond
  }
  if ( aTime >= 30000 && aTime <30001) {
    digitalWrite(THREE, LOW);        // set INPUT LOW - FAILS
    showstatus( " loop() Set INPUT LOW - THIS FAILS ???" );
    delay(2); // prevent re-entry this millisecond
  }
}

void showstatus( String info ) {
  Serial.print(info);
  Serial.print(" time at: ");
  Serial.println(aTime);
  digitalWrite(LED_BUILTIN, digitalRead( THREE ));
  if ( digitalRead( THREE ) )   Serial.print("       INPUT pin THREE reads HIGH ");
  else   Serial.print("       INPUT pin THREE reads LOW ");
  Serial.println();
}
 
Update:

Cleanup: I thought the sample code could be shorter if I went right to the LED_BUILTIN pin, and it saved a few lines

Problem1: The digitalWrite(LED_BUILTIN, HIGH); set the pin to an ODD not fully lit state, and in fact reads as LOW

Problem2: The digitalWrite(LED_BUILTIN, LOW); does set the pin LOW and the LED goes off

Code:
#define LED LED_BUILTIN
#define NOT_LED LED_BUILTIN    // This represents the coding error I made
elapsedMillis aTime;
void showstatus( String info );

void setup() {
  Serial.begin(9600);
  while (!Serial && (millis () <= 5000)) ;  // Wait for Serial to come online
  Serial.println("\n\n\nHello Out & In Error");
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  pinMode(NOT_LED, INPUT);
  showstatus( " setup() : user err OUTPUT redefined INPUT " );
}

void loop() {
  if ( aTime >= 10000 && aTime <10001) {
    showstatus( " loop() NO CHANGE" );
    delay(2); // prevent re-entry this millisecond
  }
  if ( aTime >= 20000 && aTime <20001) {
    digitalWrite(LED, HIGH);       // set INPUT HIGH - WORKS
    showstatus( " loop() Set INPUT HIGH - THIS WORKS HALFWAY on LED_BUILTIN, dim but reads LOW ???" );
    delay(2); // prevent re-entry this millisecond
  }
  if ( aTime >= 30000 && aTime <30001) {
    digitalWrite(LED, LOW);        // set INPUT LOW - FAILS
    showstatus( " loop() Set INPUT LOW - Turns the LED_BUILTIN OFF ???" );
    delay(2); // prevent re-entry this millisecond
  }
}

void showstatus( String info ) {
  Serial.print(info + " time at: ");
  Serial.println(aTime);
  if ( digitalRead( LED ) )   Serial.print("       INPUT LED pin reads HIGH ");
  else   Serial.print("       INPUT LED pin reads LOW ");
  Serial.println();
}
 
Last edited:
I had thought the Teensy3 was different but in Arduino the register for output is also the one for setting the input pullups. So digitalWrite(3,HIGH); will set pullups to high if a pin is an input. I'm assuming this is a nice and simple electrical way to do things.

Unsure if the Teensy3 actually has hardware working that way but even if it doesn't it would be quite possible the compatibility code would be setting the pullups anway in case a library was using the feature for something.
 
Well having referred to the good book (t3 version https://www.pjrc.com/teensy/K20P64M72SF1RM.pdf) seems that the pullups are in different registers from the IO so it's not hardware behavior so guess next step is a look at the digitalWrite code.

edit:
If I'm reading it right the avr_emulation.h IO section lines (repeats for all pins)
Code:
			digitalWriteFast(1, HIGH);
			if (!(CORE_PIN1_DDRREG & CORE_PIN1_BIT)) CORE_PIN1_CONFIG = CONFIG_PULLUP;
are writing the value and also configuring pullups if the port direction register is set as input

So the pullups coming on if you set a input pin high is a feature. And is one of the things that digitalWriteFast doesn't do.
 
Last edited:
GremlinWrangler: Thanks for (fast) research - I suspected(WAG) it was triggering pullups - especially when I saw the DIM LED_BUILTIN. Suppose it is the LED support that makes the pin13 act differently.

At this time I am using #define and digitalWriteFast() may have acted differently as you suggest - but when I work to make this right it will come from a runtime variable and digitalWriteFast() wouldn't be used so I skipped testing that.

It was my error and I should not have done it - but the resulting behavior obscured debugging the source of the problem. Seeing the OUTPUT show HIGH was expected - so I assumed a hardware problem not letting it go low. Had the CONFIG_PULLUP dropped on writing LOW I would not have seen my error until even later - when I tried to use the 'second' pins function.

Indeed a one line pin write wouldn't be the same if it had to double check the pinMode() against the user actual usage. I tried to make the title unassuming but suggestive for future searches - though following the forum rule should result in catching this before other random posts. In fact it was during my plan to minimize the sketch after I repro'd on a new T_3.2 what I saw on an older T_3.1 reading the sketch code I assumed was 'safe' from question when I caught the problem obscured by conflicting #define's.
 
Back
Top