Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

digitalRead gets stuck on 0 once analogRead is called on the pin #10927

Closed
1 task done
thegoodhen opened this issue Feb 1, 2025 · 7 comments
Closed
1 task done

digitalRead gets stuck on 0 once analogRead is called on the pin #10927

thegoodhen opened this issue Feb 1, 2025 · 7 comments
Labels
Status: Awaiting triage Issue is waiting for triage

Comments

@thegoodhen
Copy link

thegoodhen commented Feb 1, 2025

Board

ESP32-S3 custom board

Device Description

I bumped into this issue with my custom ESP32S3 board. The board was not detecting a button press after I mistakingly left analogRead in the loop.

Hardware Configuration

A button to pin 3, but can be replicated by having a pullup from 3 to vcc.

Version

latest master (checkout manually)

IDE Name

Arduino IDE

Operating System

Windows 10

Flash frequency

N/A

PSRAM enabled

yes

Upload speed

921600

Description

Once analogRead is called on a pin, subsequent calls to digitalWrite return zero, even if the pin is pulled high.

Sketch

void setup() {
  // put your setup code here, to run once:
  pinMode(3, INPUT);
  Serial.begin(115200);
  // gpio pulled high
  Serial.println(analogRead(3));
  delay(100);
}

void loop() {

  Serial.println(digitalRead(3));
  delay(100);
}

Debug Message

Printing zeros, despite being pulled high.

15:13:35.602 -> 0
15:13:35.699 -> 0
15:13:35.796 -> 0
15:13:35.893 -> 0
15:13:35.989 -> 0
15:13:36.086 -> 0
15:13:36.182 -> 0
15:13:36.279 -> 0
15:13:36.376 -> 0

When I interleave analogRead and digitalRead printouts (sanity check):

:15:22.993 -> 4095
15:15:23.090 -> 0
15:15:23.185 -> 4095
15:15:23.314 -> 0
15:15:23.410 -> 4095
15:15:23.507 -> 0
15:15:23.605 -> 4095

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@thegoodhen thegoodhen added the Status: Awaiting triage Issue is waiting for triage label Feb 1, 2025
@me-no-dev
Copy link
Member

АAnalog and digital modes are a very different thing. Different hardware inside the chip even. If you want to digital read that pin, you need to call pinMode(3, INPUT); first

@thegoodhen
Copy link
Author

thegoodhen commented Feb 1, 2025

АAnalog and digital modes are a very different thing. Different hardware inside the chip even. If you want to digital read that pin, you need to call pinMode(3, INPUT); first

Yes, that's what I did. It does not work. I am certain this is a bug.

I had a typo in my code that was supposed to demonstrate the issue. I updated it. Now it's correct, the behavior described persists. Reopen the issue, please.

Another example

`
void setup() {
// put your setup code here, to run once:
pinMode(3, INPUT);
Serial.begin(115200);
}

void loop() {
// put your main code here, to run repeatedly:
Serial.println(analogRead(3));
delay(100);

Serial.println(digitalRead(3));
delay(100);
}

`

Prints:

17:29:02.002 -> 4095
17:29:02.098 -> 0
17:29:02.195 -> 4095
17:29:02.291 -> 0
17:29:02.388 -> 4095
17:29:02.485 -> 0
17:29:02.582 -> 4095
17:29:02.678 -> 0
17:29:02.774 -> 4095
17:29:02.902 -> 0

@me-no-dev
Copy link
Member

I'm not sure you understood me

void loop(){
  Serial.println(analogRead(3));
  delay(100);

  pinMode(3, INPUT); // You need to do this after analogRead and before digitalRead to switch the pin to digital
  Serial.println(digitalRead(3));
  delay(100);
}

@thegoodhen
Copy link
Author

thegoodhen commented Feb 2, 2025

I'm not sure you understood me

void loop(){
Serial.println(analogRead(3));
delay(100);

pinMode(3, INPUT); // You need to do this after analogRead and before digitalRead to switch the pin to digital
Serial.println(digitalRead(3));
delay(100);
}

I now understand why this happens, but this isn't a solution, it's a workaround—one that users wouldn't expect to be necessary.

You mentioned that analog and digital functions are handled by different hardware. That’s true, but this is also the case for other microcontrollers, such as the Arduino Uno.

However, the following code works correctly on an Uno without any extra pinMode calls:

void setup() {
  pinMode(A0, INPUT);
  Serial.begin(115200);
}

void loop() {
  Serial.println(analogRead(A0));
  delay(100);
  Serial.println(digitalRead(A0));
  delay(100);
}

Output on Arduino Uno (as expected):

1023
1
1023
1
1023
1

I understand that the ESP32 is very different hardware, but once a user calls pinMode(pin, INPUT), they are fully justified in expecting that both digitalRead and analogRead will "just work" from that point onward.

The fact that analogRead permanently prevents subsequent digitalReads from working correctly is:

  • Unexpected (breaks standard user expectations).
  • Undocumented (not mentioned in any official documentation).
  • Inconsistent with Arduino's reference implementation (which makes an effort to abstract away hardware differences).

This difference will break cross-platform code portability, which is one of the main goals of a HAL.

Arduino HALs often take steps to ensure correct pin behavior. For example, the Uno’s digitalRead implementation explicitly ensures that PWM is not active before reading a pin:

int digitalRead(uint8_t pin)
{
	uint8_t timer = digitalPinToTimer(pin);
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);

	if (port == NOT_A_PIN) return LOW;

	// If the pin supports PWM output, turn it off before reading.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	return (*portInputRegister(port) & bit) ? HIGH : LOW;
}

The only logical conclusion is that this behavior is a bug.

I can probably fix it and submit a pull request, but I need to know that you’re willing to accept it.

@me-no-dev
Copy link
Member

I beg to differ. The fact that AVR's hardware and Arduino's original code allows such use, does not make it correct. Those are two very different IO modes. There are more things that the original Arduino allows and are not allowed on ESP32. Also things that are not correct. So to argue that one platform does not allow invalid use and that is a bug is invalid IMHO. Even if we make it possible (which we can) the result will be unpredictable, because the pin in ADC mode is connected to different hardware inside the chip and the digital value of it will be just wrong and unpredictable.

@thegoodhen
Copy link
Author

I beg to differ. The fact that AVR's hardware and Arduino's original code allows such use, does not make it correct. Those are two very different IO modes. There are more things that the original Arduino allows and are not allowed on ESP32. Also things that are not correct. So to argue that one platform does not allow invalid use and that is a bug is invalid IMHO. Even if we make it possible (which we can) the result will be unpredictable, because the pin in ADC mode is connected to different hardware inside the chip and the digital value of it will be just wrong and unpredictable.

Yes, but arguably, the end user does not care about the hardware differences. This is what the HAL should abstract away.
It's fully reasonable for users to assume they can rely on digitalRead working correctly once they call pinMode(pin, INPUT), no matter whether or not they also called analogRead or not.

I propose the following behavior:

When you call digitalRead, it should check if the pin was previously connected to the ADC. If so, it disconnects it from the ADC and uses it as as a digital pin, reading the correct value. This makes the behavior consistent with user expectations.

I should get less busy by the end of the week. If I fix it, will you accept a pull request?

@me-no-dev
Copy link
Member

If I fix it, will you accept a pull request?

yes we will

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Awaiting triage Issue is waiting for triage
Projects
None yet
Development

No branches or pull requests

2 participants