Arduino Uno PWM pins conflict

binar picture binar · Sep 9, 2013 · Viewed 25.9k times · Source

I built this motor shield based on the L298N chip to control two motors of a tank. It uses pins 5 and 6 for one motor, and pins 10 and 11 for the other.

While trying to add a TSOP 4838 in order to control the tank with an IR remote I noticed that moving the motor on pins 10/11 in reverse only works at full speed - that is, a HIGH (255) value on pin 11. Anything below that value doesn't output anything on pin 11 (measured voltage on those pins is 0 V).

For the remote I use this library. The IR receiver is connected on pin 2 (but the pin doesn't matter). The problem is the library code itself. The line that enables IR listening irrecv.enableIRIn(); is what is causing the problem. I learned that there is a conflict of internal Arduino timers and the pins used for PWM by the shield.

This is the code to power the motor in reverse:

#include <IRremote.h>

// IR receiver configuration
const int irPin = 2;
IRrecv irrecv(irPin);

// Motors configuration
const int mLeftPin1  = 10;
const int mLeftPin2  = 11;
const int mRightPin1 = 5;
const int mRightPin2 = 6;

void setup()
{
  // Start IR
  irrecv.enableIRIn();

  // Setup motors
  pinMode(mLeftPin1, OUTPUT);
  pinMode(mLeftPin2, OUTPUT);
  pinMode(mRightPin1, OUTPUT);
  pinMode(mRightPin2, OUTPUT);

  // Move left motor in reverse, slower speed
  analogWrite(mLeftPin2, 100); // This works only with 255 instead of 100
  digitalWrite(mLeftPin1, LOW);
}

Now, I found here that the pins used by the timers on Arduino Uno are:

  • Pins 5 and 6: controlled by Timer0
  • Pins 9 and 10: controlled by Timer1
  • Pins 11 and 3: controlled by Timer2

So my questions are:

  1. Why does the shield in the instructable use pins 10 and 11 for PWM ? They correspond to 2 different timers. Why not 9 and 10?

  2. In order to use the IR along with the motor shield, what timer should I configure the IR library to use?

  3. If the answer is 2, a line should be uncommented in IRremoteInt.h. I am guessing the Uno would take the else branch at line 68, although only timer1 and timer2 are there. I wonder why timer0 couldn't be used for the Uno.

Although I'd like to leave cutting traces and resoldering as a last option, another possibility would be to change the pins used by the shield, but which? And I am guessing this would also be paired with configuring the timers to PWM on other pins than default, but I don't know anything about timers/interrupts and my knowledge of Arduino and C is limited.

I made this a long question, because I want to learn not just solve the problem, so feel free to explain more than what is asked.

While looking up for a solution I also found other conflicts to keep in mind when using PWM or timers:

  • Timer0 is an 8-bit timer, it can hold a maximum value of 255. It is used by delay() and millis(), so there are consequences when messing with it
  • Timer1 is a 16-bit timer, it can hold a maximum of 65535 (an unsigned 16-bit integer). The Arduino Servo library uses this timer
  • Timer2 is an 8-bit timer used by the Arduino tone() function

And, of course, the IRremote library uses TIMER_RESET, so depending on which timer it uses it can conflict with the associated pins.

Answer

user2461391 picture user2461391 · Sep 9, 2013
  1. Not all hardware is designed in the best way. Using 10 and 11 is indeed wasteful because it requires two timers.

2/3. Ideally you will use a timer that is not Timer0. Here's some more details on timers/interrupts:

The Arduino chip (328P) has three timers. Each timer can be used for multiple uses, however it is important to note that you can only have one timer interrupt enabled for each timer.

Take Timer0 for example. It interrupts in order to generate the proper delays for the delay() and delay_us() methods. It also is used for the PWM outputs on pins 5 and 6. This can happen because the PWM outputs don't use a timer interrupt, they use separate output compare modules.

Now looking specifically at your problem, it should work fine, even though you have a PWM output using timer2, the PWM does not take an interrupt on timer2 so the IR library should be free to use that interrupt. However, looking into the IR library code, we see this piece of code:

ISR(TIMER_INTR_NAME)
{
   TIMER_RESET; 

It appears that every time it interrupts, it resets the timer count. This could be why your PWM output is not working properly. The output compare module is waiting for a certain tick count, and it never reaches that.

As to why it somehow works at 255, we can take a look at the analogWrite code:

void analogWrite(uint8_t pin, int val)
{
    // We need to make sure the PWM output is enabled for those pins
    // that support it, as we turn it off when digitally reading or
    // writing with them.  Also, make sure the pin is in output mode
    // for consistenty with Wiring, which doesn't require a pinMode
    // call for the analog output pins.
    pinMode(pin, OUTPUT);
    if (val == 0)
    {
        digitalWrite(pin, LOW);
    }
    else if (val == 255)
    {
        digitalWrite(pin, HIGH);
    }

So by writing 255, the analogWrite code ignores the whole PWM and output compare thing, and just writes the pin high.

Finally, as to solving your problem, I would personally go the route of not using pins 11 and 3 (timer2). Yes it will require a small rewiring, but that way you can free up timer2 for the IR library to use.

Alternatively, you could poke around the IR library and try to make it work without resetting the count.