Go Down

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

freeze

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?

HazardsMind

#1
Mar 25, 2013, 07:00 pm Last Edit: Mar 25, 2013, 07:04 pm by HazardsMind Reason: 1
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: [Select]
int led = 9; //PWM
void setup() {               
  pinMode(led, OUTPUT);     
}

void loop() {
  analogWrite(led, 220);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

pylon

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.

liudr

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?

liudr

To test my theory, I have to read some code that deals with registers  :(

In digitalWrite()

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

Here is the Arduino 1.5 version of turnOffPWM

Code: [Select]
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?

pylon

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

Code: [Select]
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.

freeze

"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.

liudr

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.

pylon

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.

liudr

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.

freeze

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.

liudr

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

James C4S


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?
Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

liudr

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.

Nick Gammon


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

Code: [Select]
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.
Please post technical questions on the forum, not by personal message. Thanks!

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

Go Up