arduino / ArduinoCore-renesas

MIT License
109 stars 74 forks source link

Calls to digitalWrite() don't work after a previous analogWrite() #58

Open technoblogy opened 1 year ago

technoblogy commented 1 year ago

Once you've generated PWM on a pin with analogWrite(), a subsequent digitalWrite() doesn't work.

Here is a sequence of calls and the resulting voltage on the pin (on core 0.8.7), compared to the same sequence on an original Arduino Uno R3:

Command Arduino R4 Arduino R3
pinMode(3, OUTPUT) 0V 0V
digitalWrite(3, HIGH) 4.7V 5V
analogWrite(3, 200) 3.68V 3.9V
digitalWrite(3, LOW) 3.68V 0V
digitalWrite(3, HIGH) 3.68V 5V

The R3 behaviour is what I'd expect.

Here's a visual demonstration of the problem. This program first blinks the builtin LED, and then pulsates it smoothly on and off:

void blink () {
  for (int i=0; i<5; i++) {
    digitalWrite(13, HIGH); delay(1000);
    digitalWrite(13, LOW); delay(1000);
  }
}

void pulse () {
  for (int i=0; i<5; i++) {
    for (int x=0; x<=255; x++) { analogWrite(13, x); delay(5); }
    for (int x=255; x>=0; x--) { analogWrite(13, x); delay(5); }
  }
}

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  blink();
  delay(1000);
  pulse();
  delay(1000);
}

The call to blink() only works the first time around loop().

The same problem occurs on the Uno R4 WiFi.

Note: Originally posted on the Early Access Program forum, but still an issue.

mjs513 commented 1 year ago

@technoblogy try this for your pulse function:

void pulse () {
  for (int i=0; i<5; i++) {
    for (int x=0; x<=255; x++) { analogWrite(13, x); delay(5); }
    for (int x=255; x>=0; x--) { analogWrite(13, x); delay(5); }
  }
    pinMode(13, OUTPUT);
}

looks like analogWrite does something to mess with pinMode. Tested on a Minima.

technoblogy commented 1 year ago

Thanks, but my point is that calling pinMode() again shouldn't be necessary.

mjs513 commented 1 year ago

Thanks, but my point is that calling pinMode() again shouldn't be necessary.

I agree thats why I added it to make it painfully clear.

aentinger commented 1 year ago

Once you've generated PWM on a pin with analogWrite(), a subsequent digitalWrite() doesn't work.

Others may see this differently but this is acceptable behaviour to me.

This use case of using the same pin both as digital output and as PWM output within the same sketch is one that's unlikely to occur outside of your experimental setup (in the real world ™️). If you insist on doing it than one call to pinMode is a minor price to pay.

technoblogy commented 1 year ago

Others may see this differently but this is acceptable behaviour to me.

The reason I see it as unacceptable is that I have code (a more complicated version of the example at https://github.com/arduino/ArduinoCore-renesas/issues/58#issue-1809936399) that works on all other Arduino compatible boards, but fails in a non-obvious way on the Uno R4 Minima and Uno R4 WiFi.

WestfW commented 1 year ago

I really hate the "cluttering" of digitalWrite() with checks for whether an analogWrite() is in effect, whether the pin is in INPUT mode (and therefore should have a pullup enabled) (which the R4 code also doesn't do) and so on. Some of this is painful preservation of AVR behavior, and some is just things that ought to be the programmer's responsibility.

OTOH, other boards have implemented this behavior, so it is a backward incompatibility.

aentinger commented 1 year ago

I really hate the "cluttering" of digitalWrite() with checks for whether an analogWrite() is in effect ...

That's my position too. It needlessly adds extra state and I can already see people bike-shedding about performance. To top it off, switching back and forth between PWM and digital output is simply not a sensible use case scenario in the real world :tm: . A PWM of 0 is digitalWrite(pin, LOW) and a PWM of 1024 (?) is digitalWrite(pin, HIGH) and vice versa. :shrug:

KurtE commented 1 year ago

I don't have a strong opinion, on if pinMode call should be needed here or not. But this issue was linked to in a thread I started, so decided to take a look.

It reminded me of a recent thread up on the PJRC forum: https://forum.pjrc.com/threads/73248-Teensy-4-1-PWM-pulsing-output-with-values-0-and-256

Where the PWM code does not give you the same effects for 0 and 256 (8 bit mode) as setting the pin High or Low. Instead it might still give a very small pulse or gap. Which is why some then explicitly set the pin High or Low. But this could cause problems for some devices that rely on a consistent timing of the pulses, of when the next pulse should start.

But I have seen more than once where sketches do intermix using PWM and digital mode.