Arduino Uno PWM pins conflict
Asked Answered
A

3

14

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.

Alic answered 9/9, 2013 at 19:18 Comment(0)
F
14
  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.

Fondea answered 9/9, 2013 at 20:11 Comment(3)
Excellent answer, thank you! I'll be going the rewiring route and move pin 10 to 9 and pin 11 to 10 (just to keep a logical order). So this will be using only Timer1.Alic
I also saw the code for analogWrite() but at the time I didn't suspect timers could be the problem. Now looking at it, I also see that pinMode(pin, OUTPUT); in setup is redundant, as analogWrite already does that.Alic
@talereader Yeah you will notice a lot of redundant bloated code built into Arduino's functions. It is a good idea to keep those in mind, so later on if you need more speed, you can use the lower level C commands directly. (For example, instead of digitalWrite you can use the faster DDRB |= 0x01, it's less readable but much faster).Fondea
S
1

Pay attention to the board used, if you use Arduino Uno, then the code responsible would be: // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc else //define IR_USE_TIMER1 // tx = pin 9 define IR_USE_TIMER2 // tx = pin 3 endif

Silk answered 25/3, 2014 at 20:31 Comment(2)
You're right, the project I'm working on now is on a Mega 2560 and I looked at the wrong code. So the comment in the library warned me about pin 9 but didn't understand what's with the TX part back then.Alic
Just to clarify for whoever reads this in the future, your answer is to a question I asked in a comment below, not directly to the posted question.Alic
S
0

I had the same problem with a prebuilt L298 V2 motor shield.

The pins were marked like this on the shield:

Motor1: pin 3 and 5 Motor2: pin 6 and 9

I use PIN10 instead of 3 and using a small workaround: I put a wire from PIN10 to PIN3 on the SHIELD. My project was to control my robot with a SAMSUNG TV remote control.

Silk answered 15/3, 2014 at 14:31 Comment(3)
Welcome to SO fellow romanian! RoboFun is fun, but building your own is even more fun :) My purpose is learning so that's why I prefer DIY builds. But that also gave me some headaches. Anyway, since the tank project I have now moved to another project, using 2 steppers and also IR control. I modified the IRremote library a bit to suit my purposes. But I still have one question about this library: have you understood what the comments in IRremoteInt.h mean, the ones where timer usage is defined? For example, #define IR_USE_TIMER1 // tx = pin 11. What does pin 11 have to do with TIMER1?Alic
Also, I encountered this problem: I need to control the steppers in real time, keep the stepper moving while the IR button is pressed. However, the current remote I have (sparkfun.com/products/retired/10280) sends the same signal in 3 different formats and that takes time and creates delay problems (causing the steppers to stop). That's why I'm moving to this one: sparkfun.com/products/11759. Just ordered, hasn't arrived yet. But still, one IR command has 8 bytes and takes some time to be sent and fully read by the IR receiver. How does the Samsung TV remote behave?Alic
You'll hate it for sure. It has intermittent IR beam. Not suitable for fine motor control.Silk

© 2022 - 2024 — McMap. All rights reserved.