D0 input impedance when using Serial 1

Updated T+24hr: Although it shouldn't, placement of a pinMode(0,INPUT) following the Serial1.begin(x) places the D0 pin into a high impedance state WHILE allowing the Serial1 serial port to operate normally for both RX and TX functions. This is counter to advice that the Serial functions 'disconnect io pin muxing'. So - although I have found a workaround, I am even more confused.

Original post, T=0: Hey Folks - Nano EVERY, serial_port_one, D0 input impedance question. This is likely a internal-to-the-4089 code question.

In a nutshell: When configured for either a hardware serial port (Serial1) OR a digital input, the D0 (RXD input to the 4089) should be a (relatively) high impedance INPUT, correct? I find this not to be the case as follows:

1.) If I configure the D0 pin as a digital IO pin (input OR output) the pin acts as expected.
2.) If I configure the D0/D1 pin as a hardware serial port (Serial1), it works wonderfully as expected.
3.) But: If I look closer at the D0 pin after Serial1.begin, the pin does not resemble an input - a weak external pulldown no longer pulls this D0 input low: This is what I fail to understand or wish to report as a problem.

More detail: (and shown in the code section included.)
Start with a completely uncommitted (completely unconnected, brand new Nano EVERY). Connect to a USB port. Add a single weak pulldown to D0 (I used 300K to GND.) No other connections are needed to demonstrate this situation.

Configure D0 as input -> results in a digital low as expected due to added weak pulldown.
Configure D0 as output, set high -> results in digital high as expected (high overcomes the added weak pulldown.)
Configure D0 as output, set low -> results in digital low as epected.

Now what doesn't work:
With D0 configured as input, perform a Serial1.begin: D0 immediately transitions high, but should have stayed low due to my added weak pulldown. Even a much stronger pulldown (e.g. 47K) does not overcome the high value at the D0 input - which SHOULD remain an input. It seems the part is driving this input pin internally with a strong pullup or other driver.

The icing on the problem: performing a Serial1.end leaves D0 in a high state with strong high drive, but then setting pinMode(0,INPUT) immediately returns the pin to the expected low state. Something is definitely not right in the pin muxing of the serial1 pin connections.

My goal with using D0 as an input (by connecting it to a DIFFERENT IO pin configured as an input) is to detect a 'connection event' when a custom designed device is connected to the serial port by monitoring the status of the D0 input to the serial port. This device has a pullup which will overcome the 300K pulldown when connected - but this will only work if D0 line ACTS LIKE AN INPUT which it is failing to do when the serial_1 port is enabled. (unfortunately I can't enable and disable the serial1 port to have this work - the best solution lies in understanding (or fixing) why D0 remains 'driven' as the RXD input.

I'm a sparky (EE) whose talents lie far from code - so I understand all non-code things well. Help me understand why the pin input impedance changes to be quite low once serial1.begin has been invoked?

Thanks for any light you can shed on this.

// Starting point:
// Other than the microUSB connector plugged in for downloading/debug a
// completely unconnected NANO EVERY with one exception:  The a single weak (300K) pull down on D0.
// On the NANO EVERY, the microUSB port is the default Serial_ZERO port.
// On the NANO EVERY. the D0 and D1 lines are the Serial_ONE port.
// There is nothing connected to the D0 or D1 pins other than the pulldown on D0.
// When D0 is configured as an INPUT or when SERIAL1 is enabled, D0 SHOULD remain an input, HOWEVER this is not true.


void setup() {
  Serial.begin(9600);   // this is the USB serial port, not the D0/D1 serial port on the NANO EVERY

  Serial.println("Start with D0 set as input.  D0 should remain low due to added pulldown.");
  pinMode(0, INPUT);    // pin 0 as input with 300K pulldown.  Scope confirms low level - YAY!
  delay (5000);

  Serial.println("Now configure D0 as output with D0 set high");
  pinMode(0, OUTPUT);   // now set D0 to output.  Pin D0 should follow the level as requested
  digitalWrite(0, 1);   // set D0 HIGH.  Scope confirms high level - also, YAY!
  delay (5000);

  Serial.println("Now configure D0 as output with D0 set low");
  digitalWrite(0, 0);   // set D0 LOW.  Scope confirms low level - also, YAY!
  delay (5000);
  
  Serial.println("Now configure D0 as input again.  Pin should be in low state via pulldown.");
  pinMode(0, INPUT);    // Now play nice:  Before enabling SerialOne, Set D0 to input.  Scope confirms Low state.  YAY! again.
  delay (5000);

  Serial.println("Now things stop working:  Enable SerialONE"); // D0 SHOULD REMAIN LOW but does not:  BOOO!
  Serial1.begin(38400);   // SERIAL ONE D0 (input!) IS NOW 'DRIVEN' HIGH (with something fairly low impedance), OVERCOMING THE 300K PULLDOWN.
  delay (5000);

  Serial.println("Now disabling SerialONE");    // However, D0 REMAINS HIGH UNTIL PINMODE SETS TO INPUT AGAIN.
  Serial1.end();
  delay (5000);

  Serial.println("ending with starting with D0 = input");
  pinMode(0, INPUT);    // Normality returns with D0 set to input again. Scope confirms D0 is low - YAY!
}

void loop() {
  Serial.print("Done");

  delay(10000);

}

Perhaps it should be documented. It isn't necessarily a problem when considering the Arduino boards as aimed at novices.

If you look at the library source code, megaavr/1.8.6/cores/arduino/UART.cpp, and at the UartClass::begin you will find the lines:

//Set up the rx pin

pinMode(_hwserial_rx_pin, INPUT_PULLUP);

which explains why you are seeing the internal pullup rather than a straight high impedance input. But the reason to do this is to get defined operation (namely no received data) if the pin is not connected. Of course, as an EE you know better than to leave input pins unconnected!

As to the "disconnects from pin multiplexing" you need to understand the hardware architecture. You can always read a digital pin, even if it configured as an output pin(!). An output pin (such as TX) cannot be written to if the USART is enabled since it is being driven by the USART, hence it is disconnected from pin multiplexing.

For a full understanding, check out the data sheet, ATmega4809 Data Sheet. Always a good read.