Go Down

Topic: analogWrite incompatable with digitalWrite (Read 3199 times) previous topic - next topic

PeterH


You shouldn't necessarily expect that doing a digital write (which is a one-off pin state change) would cancel that.


I would expect all the operations that can be applied to a pin to have defined and self-consistent behaviour.
If there is conflict between different operations (such as changing pin modes, digital and analog writes, analog reads) then the documentation should define what actually happens.
And, what actually happens should preferably be sensible and self-consistent. Requiring the sketch to explicitly start and stop analog writes separately from digital writes is IMO not sensible or self-consistent.
I only provide help via the forum - please do not contact me for private consultancy.

liudr

digitalWrite() does turn off PWM on ATMEGA chips. There is a turnOffPWM function that digitalWrite calls.

freeze

The Due board incorporates a sophisticated CPU, and people will write sophisticated and complex code for it. If setting a pin HIGH or LOW succeeds or fails depending on a something done a thousand lines of code earlier, perhaps in a function written by someone else, bugs will be essentially impossible to diagnose.
Possible suggestions:
1: Basic functions should cause as few side effects as possible. Those that are unavoidable should be documented.
2: Functions that set states could return a value to indicate success or failure.
3: Pins could be queried to determine their state. For example, isDigitalOut(9) would return true if pin 9 were able to accept a call to digitalWrite(9, LOW). (Or a library could define C++ Pin objects with an interface to allow for this.)

It is important that I make clear that I started this thread to ask for help with a problem I had trouble with. People who answered have been helpful and courteous. Furthermore, I have great respect for those who have created the Arduino project, and for their immense amount of work coding and testing it all. Any suggestions I may have are made in that spirit.
Thank you.

Nick Gammon

The thing is that the processor has a hardware timer (more than one in fact) that runs asynchronously. That is, once started they "take over" the output port and output PWM pulses.

As a courtesy to beginners the Uno library was written with extra code (which itself takes time and is thus not necessarily a good thing) to cancel any existing PWM output.

The fact remains that if you initiate something on the board (eg. turn on a serial port) you are expected to be aware of that fact.

Let me give you an example. This code on the Uno is supposed to turn off D0, however if you plug in an LED it will glow:

Code: [Select]

void setup ()
  {
  Serial.begin (115200);
  pinMode (0, OUTPUT);
  digitalWrite (0, LOW);
  }  // end of setup

void loop () { }


Why? Because the serial hardware has taken over the port. You are supposed to realize that. Otherwise every digital write would have to turn off PWM, serial hardware, I2C hardware, SPI hardware and so on. All this "turning off other functions" would take a lot longer than just writing to the pin and people would complain that the digitalWrite is ridiculously slow.

They have crammed a lot of functionality into the chip. Some of it conflicts with other things, and it is all documented in the datasheet. The libraries hide some of that from you, but not all.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

retrolefty

And sometimes basic library functions change behaviour when new features are added to them.

One example someone showed posted about, that after IDE 1.0.2 or so, if you have a digital input pin setup with it's internal pull-up enabled but then any time later do a subsequent pinMode(pin#, INPUT) the internal pull-up will be disabled.

That wasn't the case prior to them adding the new pinMode(pin#, INPUT_PULLUP) option feature. Now that may not be a real problem for most all existing code, but I bet somewhere in the Arduino universe there is a sketch that will break because of the change of behavior.

I always though the behavior of performing a analogWrite() on a non PWM pin was rather cute, but pretty useless and probably should have had a NOP type behavior instead, or return an error or at least something Spock would have been pleased with.  ;)

Lefty

freeze

The serial port conflict with pin 0 is well documented:
" Serial. It communicates on digital pins 0 (RX) and 1 (TX) as well as with the computer via USB. Thus, if you use these functions, you cannot also use pins 0 and 1 for digital input or output."
I hope that something like "Once PWM, always PWM" will also be well documented.
Perhaps a cancelPWM(int pin) function would be useful.

liudr

Arduino doesn't provide end() opposite begin(), Serial.end() was recently added I believe (not in 0022). Audio has no end. If they have pwm.begin() and end(), I would use them by the book. They don't. At best they would provide begin(), and years later add end(). You can't blame developers with not properly ending a procedure if you are not including it with the release. Honestly I think that calling analogWrite will do PWM, and there is no need to turn it off before doing digitalWrite. Rhe documentation paragraph one seems to assure me of this freedom:

http://arduino.cc/en/Reference/AnalogWrite

Nick Gammon

Better see this then:

https://github.com/arduino/Arduino/issues/476

Quote

What change would like to see?

A noAnalogWrite() function that turns off PWM on a pin (so you can use it for normal digital input and output).

Why?

The new digitalWrite(), digitalRead(), and pinMode() in 1.0 don't disable PWM, so there needs to be a way to do it explicitly. So you'd do something like: ...


Issue closed with a "won't fix" reason given.  :(
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

mitocho

I also ran into this problem. 

The best simple fix I found:

Code: [Select]

analogWrite( pin, 255 );
pinMode( pin, OUTPUT);
digitalWrite( pin, HIGH );


If you're trying to implement that in current code, the easiest way may be to replace all digitalWrite() with another function, like digitalWrite2().  A simple find and replace would be the easiest way to do that.

Then, make the function digitalWrite2() as follows:
Code: [Select]

digitalWrite2( int pin , int value ) {
pinMode( pin, OUTPUT);
digitalWrite( pin, value );
}


Just a note, I didn't check if HIGH or LOW is a int.  So the above code may not work, but it should be a simple fix

GoForSmoke

We can read & write the port registers directly if we want speed.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

liudr


We can read & write the port registers directly if we want speed.



I don't think speed was the goal here. Rather encapsulation was. If you run a command, it should not affect a subsequent command.

GoForSmoke



We can read & write the port registers directly if we want speed.



I don't think speed was the goal here. Rather encapsulation was. If you run a command, it should not affect a subsequent command.


I thought that was the point of coding.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

liudr

Apparently that point was not well made with DUE.

jchalo99

ok apparently i like digging up dead threads. but my search again lead me here. As this thread pointed out analogwrite and digitalwrite do not play nice together on the DUE. the solution appears to be resetting the pin(s) to output(s). is that correct?

my issue is analogwrite to a pin works well, i can send it multiple different values and it works. than i digialwrite it low, and than it wont let me pwm the pin.

Go Up