Changing Pin settings of an IR Library

Hi,

I am trying to use both the Adafruit Wave Shield and the IR Library from A Multi-Protocol Infrared Remote Library for the Arduino

The problem is, both use pin 3! Changing the pin on either one is sadly not as trivial as I wished, so I hope someone here can help me out.

I decided to change the pin used by die IR Library since it's the smaler one...

So there are 3 relevant methods that needs to be changed:

The first two are relatively self explanatory.

void IRsend::mark(int time) {

  // Sends an IR mark for the specified number of microseconds.
  // The mark output is modulated at the PWM frequency.
  TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output
  delayMicroseconds(time);
}
void IRsend::space(int time) {

  // Sends an IR space for the specified number of microseconds.
  // A space is no output, so the PWM output is disabled.
  TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output
  delayMicroseconds(time);
}

The third one gives me headaches...

void IRsend::enableIROut(int khz) {
  // Enables IR output.  The khz value controls the modulation frequency in kilohertz.
  // The IR output will be on pin 3 (OC2B).
  // This routine is designed for 36-40KHz; if you use it for other values, it's up to you
  // to make sure it gives reasonable results.  (Watch out for overflow / underflow / rounding.)
  // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
  // controlling the duty cycle.
  // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
  // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
  // A few hours staring at the ATmega documentation and this will all make sense.
  // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.

  
  // Disable the Timer2 Interrupt (which is used for receiving IR)
  TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt
  
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW); // When not sending PWM, we want it low
  
  // COM2A = 00: disconnect OC2A
  // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
  // WGM2 = 101: phase-correct PWM with OCRA as top
  // CS2 = 000: no prescaling
  TCCR2A = _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS20);

  // The top value for the timer.  The modulation frequency will be SYSCLOCK / 2 / OCR2A.
  OCR2A = SYSCLOCK / 2 / khz / 1000;
  OCR2B = OCR2A / 3; // 33% duty cycle
}

I can't wrap my head around these timer, and hardware pin names.
So I want the lib to use pin 6 instead of pin 2, if someone here can explain to me, what I need to do for this, or if it is possible anyway, I would be very thankful!

So I want the lib to use pin 6

Well you can't use Arduino Pin 6 for the IR transmit function. Not with the way that an ATmega timer is used with IRremote.

Now...

The IRremote library uses Timer 2 in a mode that only works with output on Arduino Pin 3.

I have modified the IRremote source to use Timer 1, which allows me to use Arduino Pin 9 or Arduino Pin 10, but, the WaveHC library uses Timer 1, and you can't use Timer 1 for IRremote at the same time that is being used for WaveHC. (I don't have a Wave Shield, so I haven't actually tried anything with the Wave HC library, but I have glanced at the code.)

If you were using one of the Mega boards, you could (probably) modify IRremote to use one of the other timers, but I haven't tried that either.

Theoretically you might be able to use Timer 0 (with Arduino Pin 5 as your IR output), but since Timer 0 is used for just about all Arduino stuff that depends on timing, I personally wouldn't even dream of futzing with Timer 0, let alone suggesting that other people do such a thing.

Bottom line: You can use just about any unused Arduino pin for receiving with the IRremote library (no modifications to the library source are needed). With an ATmega328 chip, I don't see any practical way to use the IRremote transmit functions with anything other than pin 3 unless you use Timer 1. If you were using one of the Arduino Mega boards, you could (probably) use one of the other timers, but I haven't tried that.

I would be interested in knowing what you are really doing in your project. What external device(s) are you controlling with the Arduino?

Regards,

Dave

hmm, thats not exactly the answer I was looking for...
Okay than, what I'm trying to do is an Lazer-Tag system with one device for receiving (aka "Shield") and another one for sending (aka, the "Tagger").
My "Tagger" will have an IR LED (surprise) a bunch of LEDs (about 6 at least), some kind of "recoil"-system, probably involving an electromagnet, some triggers (~3) and an switch for team selection.

I already have big problems keeping under the 1k SRAM limit, so I guess I should really start thinking on using an Mega on the Tagger side.

If I do so, can you explain to me, what I can try to do, to change the used timer & pin in the IR Lib?
(Because stopping the project or pass on sound is not an option :wink: )

Going to a Mega board will be a real adventure, I'm thinking. Since I haven't had the "opportunity" to test a Wave Shield with any of the wave player software libraries, I can't say how compatible they might be with a Mega board

Many Arduino pins have different physical port positions, so if the library uses direct port pin manipulation, the library functions might have to be changed. The SPI port pins are different, so getting the SD memory module to operate on a Wave Shield plugged into a Mega board (or a Mega proto shield that is plugged into a Mega board) may require some minor surgery (or, maybe, not). Etc., etc.

Just as a teaser: Forget the wave stuff for now. Let's just see what we can do with IRremote.

I have been thinking of porting the IRremote library to use with my Metga1280 board, but I haven't done anything until now. I haven't really needed such a thing, but, it has crossed my mind...

So, I'll get started like this:

First of all, as we already know, the IRremote library as supplied uses Timer 2 and the IR transmit output is the ATmega OC2B pin.

Now, here's where it starts to get a little bit "interesting."

For the ATmega328p, OC2B is Bit 3 on PORT D (Pin 5 on the 28-pin DIP package). For Arduino boards using '328 processors, Pin D3 is connected to Arduino Pin 3. So, with the original package, if you connect your transmit LED circuitry to Arduino Pin 3 you are in business.

However...

For the ATmega1280 and '2560 chips, OCR2B is connected to Bit 6 of Port H (pin 18 of the 100 TQFP package). On the Mega boards, Pin H6 is connected to Arduino Pin 9.

So, to get the IRremote send functions to work on a Mega board, open IRremote.cpp and go to the lines where it sets the pin mode of pin 3 to output (line 200, I think).

Change the code in line 200 and 201 to the following:

  //
  // For Mega boards, OCR2B is Arduino Pin 9.  For '328 boards it's Arduino Pin 3
  // davekw7x
  //
#if defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW); // When not sending PWM, we want it low
#else
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW); // When not sending PWM, we want it low
#endif

Now, this is just a beginning: You have a library for which the transmit stuff works with '328 Arduino boards and Mega boards. The difference is that for '328 boards you put the transmit circuitry on pin 3 and with Mega boards you put it on pin 9.

If Pin 9 is OK for your application (no conflicts with your wave player or other applications), you are finished with the IRremote library. You can skip over the stuff about changing IRremote to use another Timer

_Start of stuff about changing IRremote to use another Timer

So...

Make sure the IRremote stuff (transmitting and receiving) works before going any farther. Note that I have tested the transmit part, but not the receive part. I "think" the receive stuff might work, and some day I will test it.

Now, the biggie: Instead of Timer 2, I will try the '1280 Timer 4. Timer 4 is somewhat "enhanced" over Timer 2, but has modes that are compatible with what the IRremote uses to create the transmit timing.

So, make the changes that I showed before, except use pin 79in the setMode and digitalWrite statements.

Now, here's the "fun" stuff: Everywhere in IRremote.cpp that it uses Timer 2 registers, change the statements to use Timer 4. (If you are using the Arduino IDE text editor, now might be a good time to get a "real" programmer's editor, but you can probably do it with the built-in editor....)

For one example: In the IRsend::mark function, instead of

  TCCR2A |= _BV(COM2B1);

We want

  TCCR4A |= _BV(COM4B1); // Enable Mega pin 7 PWM output

Maybe put the #if defined... stuff around two statements like this:

#if defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  TCCR4A |= _BV(COM4B1); // Enable Mega Pin 7 PWM output
#else
  TCCR2A |= _BV(COM2B1); // Enable Duelimanove/UNO PWM Pin 3 output
#endif

And so it goes...

If you have changed everything concerning Timer 2 and its registers to Timer 4, you should be ready to start testing. (You will have to define a macro for RESET_TIMER4 in IRremoteInt.h to be able to use it in IRremote.cpp.)
_End of stuff about changing IRremote to use another Timer

Then...After you are absolutely positively sure that all of the IRremote stuff works with your Mega (again, I have tested the IR transmit stuff but not the receiver stuff with my changes), you are ready to start with the WaveHC library. It can still use Timer 1, but you will have to make changes for the different pin numbers in some of the functions. I'll leave that up to you.

Regards,

Dave

Wow thats some great info! Thanks very much. I still have my trouble understanding every part, but know I have something to begin with.

Theres one thing I question myself:
Should I use an Mega and edit the IR Lib, or should I buy an Arduino Mini/Nano and connect it to the Uno?
On the cost side, an Mega or an Uno+Mini is relatively equal.
So the real question should be: Can I use the IRremote lib on a Nano/Mini without problems?