Pages: [1] 2   Go Down
Author Topic: analogWrite incompatable with digitalWrite  (Read 2793 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I posted this to the Due forum. Perhaps it is more appropriate here.

With the Arduino 1.5 software, the following code blinks an LED using the Uno board, but not with the Due:

int led = 9; //PWM
void setup() {               
  pinMode(led, OUTPUT);     
}

void loop() {
  analogWrite(led, 220);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}

However, the following works with both boards:

int led = 9; //PWM
void setup() {               
  pinMode(led, OUTPUT);     
}

void loop() {
  analogWrite(led, 220);
  delay(1000);
  analogWrite(led, 0);
  delay(1000);   
}

Does the Due not allow a call to digitalWrite if analogWrite has already been called?

The reason I ask this question is that such behavior is not only non-intuitive, but also breaks many lines of useful existing code. See the attachment for an example of motor driving code (for the Solarbotics Brutusbot robot) that works for the Uno board, but not for the Due board.

I have modified the robot code successfully. But this behavior of the analogWrite() and digitalWrite() seems to be a serious problem that should be addressed. 

Am I missing something?

* brutusbot_cmd_sharp.ino (8.31 KB - downloaded 11 times.)
Logged

Queens, New York
Offline Offline
Faraday Member
**
Karma: 108
Posts: 3785
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That is strange. I do the same thing, and I have never had a problem. What IDE version are you using?

Added: I just tried your code, and it works perfectly with 1.0.3
Code:
int led = 9; //PWM
void setup() {               
  pinMode(led, OUTPUT);     
}

void loop() {
  analogWrite(led, 220);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}
« Last Edit: March 25, 2013, 01:04:03 pm by HazardsMind » Logged

Created Libraries:
TFT_Extension, OneWireKeypad, SerialServo, (UPD)WiiClassicController, VWID

Switzerland
Offline Offline
Faraday Member
**
Karma: 112
Posts: 5281
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This combination of analogWrite() and digitalWrite() is not defined, even not for the UNO, although it works there. The Due has a completely different hardware architecture, so you cannot expect it to do the same in non-defined situations.

The Due has different types of I/O pins, some are really analog, some are PWM pins and some are driven by timer interrupts.

Quote
but also breaks many lines of useful existing code.

There is also a lot of useful existing code that runs on the UNO but not on the Leonardo (just to give another example). Some of it is coded like this because it uses special hardware features or because performance issues don't allow it otherwise, but often the reason for the incompatibility is simply a lack of knowledge of the original programmer.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 75
Posts: 7305
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I read the DUE reference just now and found no mention of special cautions on "not to digitalWrite after analogWrite" and why should there be cautions? I think this is pretty bad experience for Arduino users. There is no defined sequence of what arduino functions should be used so a call to analogWrite() should not affect a subsequent call to digitalWrite(), unless the Arduino team forget to disable the timer that could have driven the pin that is being treated as digital pin.

I don't have a DUE. Is the OP willing to test this on all DUE PWM pins?
Logged


Central MN, USA
Offline Offline
Tesla Member
***
Karma: 75
Posts: 7305
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

To test my theory, I have to read some code that deals with registers  smiley-sad

In digitalWrite()

if (timer != NOT_ON_TIMER) turnOffPWM(timer);

Here is the Arduino 1.5 version of turnOffPWM

Code:
static void turnOffPWM(uint8_t timer)
{
switch (timer)
{
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
#endif

#if defined(TCCR2) && defined(COM21)
case  TIMER2:   cbi(TCCR2, COM21);      break;
#endif

#if defined(TCCR0A) && defined(COM0A1)
case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
#endif

#if defined(TIMER0B) && defined(COM0B1)
case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
#endif

#if defined(TCCR3A) && defined(COM3A1)
case  TIMER3A:  cbi(TCCR3A, COM3A1);    break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case  TIMER3B:  cbi(TCCR3A, COM3B1);    break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case  TIMER3C:  cbi(TCCR3A, COM3C1);    break;
#endif

#if defined(TCCR4A) && defined(COM4A1)
case  TIMER4A:  cbi(TCCR4A, COM4A1);    break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case  TIMER4B:  cbi(TCCR4A, COM4B1);    break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case  TIMER4C:  cbi(TCCR4A, COM4C1);    break;
#endif
#if defined(TCCR4C) && defined(COM4D1)
case TIMER4D: cbi(TCCR4C, COM4D1); break;
#endif

#if defined(TCCR5A)
case  TIMER5A:  cbi(TCCR5A, COM5A1);    break;
case  TIMER5B:  cbi(TCCR5A, COM5B1);    break;
case  TIMER5C:  cbi(TCCR5A, COM5C1);    break;
#endif
}
}

digital_pin_to_timer_PGM[] has all the necessary information but I can't find its definition for DUE on my Arduino 1.5, which has DUE listed.

I don't know about these timers. Any volunteers?
Logged


Switzerland
Offline Offline
Faraday Member
**
Karma: 112
Posts: 5281
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@liudr: You're looking into the wrong code. digitalWrite() for the Due looks like this:

Code:
extern void digitalWrite( uint32_t ulPin, uint32_t ulVal )
{
  /* Handle */
if ( g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN )
  {
    return ;
  }

  if ( PIO_GetOutputDataStatus( g_APinDescription[ulPin].pPort, g_APinDescription[ulPin].ulPin ) == 0 )
  {
    PIO_PullUp( g_APinDescription[ulPin].pPort, g_APinDescription[ulPin].ulPin, ulVal ) ;
  }
  else
  {
    PIO_SetOutput( g_APinDescription[ulPin].pPort, g_APinDescription[ulPin].ulPin, ulVal, 0, PIO_PULLUP ) ;
  }
}


Your turnOffPWM() is AVR 8bit code.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

"a call to analogWrite() should not affect a subsequent call to digitalWrite()"
I agree. It is difficult to believe that this is the intended behaviour.
If it is unavoidable for technical reasons, this should be documented clearly.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 75
Posts: 7305
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

pylon,

My bet is that a timer is still driving the pin even after you do a digital write, which is wrong behavior. Does the DUE code "turn off PWM"? I can't understand much of the code you posted.
Logged


Switzerland
Offline Offline
Faraday Member
**
Karma: 112
Posts: 5281
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
My bet is that a timer is still driving the pin even after you do a digital write, which is wrong behavior.

The OP didn't told us yet which pins exactly do show this behavior. As the Due has different types of pins which analogWrite() manipulates, it possible that the different types react differently.

Quote
Does the DUE code "turn off PWM"?

No, it doesn't but I haven't understood yet if the hardware does that automatically, at least in some cases, maybe depending on the type of the pin.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 75
Posts: 7305
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OP used pin 9 in code so I assumed pin 9. I also asked OP to test all other DUE PWM pins for similar symptom.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The original problem that prompted this thread was unexpected behaviour of a robot using the Solarbotics CMDR motor drive shield. The CMDR shield uses pins 3, 5, 6, and 11 for outputs to the motor drive chip. Those pins do in fact exhibit this problem. I chose pin 9 to do further testing and to frame the question in a simpler form because it is a PMW chip on both the Uno and the Due, and it is not used by the motor shield.
I have not tested the other 7 PMW chips on the Due, but I will do so.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 75
Posts: 7305
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks freeze. If this indeed is a generic problem with all DUE PWM pins, the Arduino team will be happy/embarrassed to know.
Logged


Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks freeze. If this indeed is a generic problem with all DUE PWM pins, the Arduino team will be happy/embarrassed to know.
Why embarrassed?  Isn't that the point of marking the 1.5.x/Due branch of the IDE as Beta?  To find issues like this?
Logged

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.c

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 75
Posts: 7305
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'd be embarrassed. It took Arduino team so long to roll out the over-due DUE and there are still simple problems. If I were in the team I would read the ATMEGA digitalWrite before writing the DUE version, even if they use different architectures. Also their audio library is exhibiting some problem, at least missing end() method:

http://arduino.cc/forum/index.php/topic,155005.0.html

I wonder if an end user can ever fix a DUE bootloader problem if there are problems with bootloaders.
Logged


Global Moderator
Melbourne, Australia
Online Online
Brattain Member
*****
Karma: 511
Posts: 19339
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

With the Arduino 1.5 software, the following code blinks an LED using the Uno board, but not with the Due:

Code:
int led = 9; //PWM
void setup() {               
  pinMode(led, OUTPUT);     
}

void loop() {
  analogWrite(led, 220);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}


Yes, but that code doesn't make a heap of sense. The only reason it works on the Uno is that they added extra stuff to cancel PWM output when you did a digitalWrite.

analogWrite turns on PWM outputs on hardware timers. You shouldn't necessarily expect that doing a digital write (which is a one-off pin state change) would cancel that.

Maybe it's incompatible, but the original code is messy.
Logged

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

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Pages: [1] 2   Go Up
Jump to: