pin output level after analogWrite() on non PWM pins

(not sure if this has been discussed in the past)
Currently with analogWrite() if you pass a value of 0 you get a LOW and if you pass 255 you get a HIGH
and any value in between you get PWM.
The question is how to handle non pwm pins.

Currently the code will set the pin to LOW for any values less than 128 and HIGH for any values above 127.
based on this code in wiring_analog.c

			case NOT_ON_TIMER:
			default:
				if (val < 128) {
					digitalWrite(pin, LOW);
				} else {
					digitalWrite(pin, HIGH);
				}

While I am very mindful of backward compatibility and always want to try to preserve it, I'm curious
on peoples thoughts on this existing behavior.
While it seems logical and useful at first, I find it very unhelpful in some real world situations.

In some cases it would be preferred that the code not attempt to "dim" half way through but
rather simply keep the pin HIGH for all values other than 0 as "dimming" (pwm) is simply not supported
on that pin.

For example, if using a pin to control a backlight on a lcd.
If the user writes code that supports dimming of the backlight, then the current behavior causes issues
because the sketch doesn't really know (and shouldn't really have to know) whether the pin supports pwm.
So now if the sketch asks for half brightness (which might be a value of 127) then the backlight is off.
The sketch has no way of knowing.
In this situation it would preferred that the pin remain high.

This extends to libraries as well. For example, suppose a library is trying to implement the
lcd 1.0 Arduino Playground - LCDAPI
The setBacklight() api call is defined to dim the backlight if it can but if it can't then it is full
bright until it is "off" with a value of 0.

To implement this kind of thing is very messy given the way the analogWrite() API functions today.

It may just be me but I was surprised the first time I ran into this as I saw the LED on the
arduino go off half way through the pwm values. I had to look up that it wasn't a pwm pin and
then look at the analogWrite() code to see that non pwm pins turn off half way through.
I was expecting a non pwm to not "dim" and stay on vs turn off half way through as staying on seemed
more logical/natural to me when pwm can't be done.

My suggestion would be to alter the analog_write() code to leave the pin HIGH until a value of 0
is specified for non pwm pins by changing the code to this:

			default:
				if (val) {
					digitalWrite(pin,HIGH);
				} else {
					digitalWrite(pin, LOW);
				}

This would change the behavior to leave the pin HIGH until it turned off with a 0
on non PWM pins which ensures that the output is not turned off for half the pwm values.

But this has backward compatibility issues as it is changing behavior.
So my questions are:
What do other folks think of this?
Have you seen real world cases where the existing behavior (pin LOW for values 127 and below) was needed
or preferred over leaving the pin HIGH for all values other than 0?

--- bill

This kind of "opaque" behavior is distasteful to me. There should be no analogWrite() support on pins that don't have PWM...end of story.

--
The Flexible MIDI Shield: MIDI IN/OUT, stacking headers, your choice of I/O pins

RuggedCircuits:
This kind of "opaque" behavior is distasteful to me. There should be no analogWrite() support on pins that don't have PWM...end of story.

--
The Flexible MIDI Shield: MIDI IN/OUT, stacking headers, your choice of I/O pins

ok, that's one opinion.
And you could also take that logic 1 step further and say:
There should be no analogWrite() on pins that don't have analog voltage outputs ... end of story
as well. It should have been pwmWrite() instead.
(Or even better been extensions to digitalWrite() to include pwm values as well as simple HIGH/LOW values)
But that wasn't what I was asking.

The question becomes what is the behavior of least surprise given the existing analogWrite() API
when trying to set a PWM value to a non PWM pin?

Leave it HIGH for all values other than 0 or the existing behavior of turning it off for the lower
half of the PWM values?

--- bill

The behavior of least surprise, then, is to leave it the way it is for compatibility with existing code. Short of changing analogWrite()-->pwmWrite() and disallowing it on pins that don't support PWM, I don't think changing analogWrite() has enough importance to justify backwards incompatibility.

--
The Rugged Circuits Yellowjacket: 802.11 WiFi module with ATmega328P microcontroller, only 1.6" x 1.2", bootloader

I'd still like to hear from anyone that needs or wants the existing behavior vs
leaving the pin HIGH unless a 0 value is specified.

In other words, there may not be much if any backwards compatibility if nobody is depending
on the existing behavior.

--- bill

One could make the equally valid argument that any value short of 255 should leave the pin off.

What about PWM-Outputs with 10bit? If you have such a microcontroller with an analog output with more then 8bit, would you differ at the value 512?
And why it should be the exact average? Why not the straightened value for detecting TTL-level? :wink:
I think that's not a good suggestion.

Sorry for my bad english, hope you understand it...

retrolefty:
In this hardware guys mind there is only one 'correct' answer. If a call is made to a pin that doesn't support pwm then it should just return without performing any action on said pin, just leave it's mode and value unchanged.

And I agree it should have been called pwmWrite() and not analogWrite(), but it was explained to me by one of the arduino developers that 'artists' would be confused by calling it such and they were the original attended users of the platform. So be it, I'm big enough to cringe and squint and call it analogWrite. :wink:

Note that they did make a small concession on the site's language reference page by calling it:

"analogWrite() -PWM"

Lefty

Would it help to be able to query if a pin does or does not support PWM?

if ( analogWriteDoesTheRightThing( LCD_DIMMER_PIN ) )
{
analogWrite( LCD_DIMMER_PIN, brightness );
}
else
{
if ( brightness )
digitalWrite( LCD_DIMMER_PIN, HIGH );
else
digitalWrite( LCD_DIMMER_PIN, LOW );
}

Knowing if pwm is supported on a pin does help.

The issue that I'm currently running into is that in order to implement the
setBacklight() function in the LCD 1.0 API you have to know this because of the way
that analogWrite() works.

I agree with the way setBacklight(val) is defined I think it makes sense for lcd backlight behavior.
0 is off; other values are for dimming unless dimming is not supported
in which case you get "on".
The problem is the way that analogWrite() works, you can't simply call analogWrite().

It is easy to work around this by doing the same thing that analogWrite() does and use
digitalPinToTimer() on the pin to see if the pin supports PWM and then react accordingly by either calling analogWrite()
or setting the pin to HIGH as needed, (it's really not that big of deal)
but the more I thought about this, the more I began to wonder does the current analogWrite()
behavior on non pwm pins really make sense?
And that is why I started this thread.

My real world case is that the current behavior doesn't work for my situation.
I can only assume that there must be other cases where the current behavior is desired.

Does anybody have any real world experience or examples
where the existing behavior works for them and is desired?

If nothing else, it will help me understand the usefulness of the current analogWrite() behavior.

--- bill

the more I began to wonder does the current analogWrite() behavior on non pwm pins really make sense?

Doesn't make sense to me. The behaviour seems very arbitrary.

I can only assume that there must be other cases where the current behavior is desired.

My understanding of Arduino API is that, if possible, every function call should have some affect so the artist has feedback. In other words, turning the LED full on at some arbitrary threshold is better than doing nothing so the artist at least knows the program is running.

Does anybody have any real world experience or examples where the existing behavior works for them and is desired?

I don't and I cannot imagine any.

I agree with RuggedCircuits and retrolefty with a small exception. If possible, at compile time, an error should be generated.

Yep. That would be nice. But it really isn't a compile time thing that can be detected.
analogWrite() can be passed a variable parameter at runtime given the way the arduino APIs are defined
and there is no way to catch that at compile time.

Anyway, I've moved on by simply not worrying about it and writing code that detects if the pin
supports PWM and then making the output work the way I want/need it to work.

--- bill