PDA

View Full Version : Use of IRRemote Lib and AltSerial with Teensy 2.0



stumbler
01-13-2013, 03:03 PM
Hello Teensy community,

I'm a happy user of Teensy 2.0, and used it in numerous hobby project and protoyping fo job. I've also backed T3 on kickstarter.
Finally, a forum just for Teensy.

What I want is using the IRRemote Lib to send IR signals and I also want to transmit serial data with AltSerial Library.

By the way:
I didn't managed to successfully receive data with the NewSoftSerial or the SoftwareSerial library.
The test code was something like:
1) if USB (CDC) data received, transmit with Hardware Serial (9600 baud) (wich is connected by wire to the SoftSerial input).
2) Check if softserial received and transmit back to USB.
With AltSerial it works great.

I'm using Arduino 1.01.

The problem is that both library use the same pin 10 (one transmit IR signal the other as Serial Rx).
After closer inspection it appear that one uses the timer 4 and the other timer3.
It's probably because this pin is also ICP3 (Input capture 3) and OC4A (output compare 4).

My main question is : How can I resolve this conflict ?
For example : what should I modify to use OC4B pin instead of OC4A pin ? Or use another Capture Input for serial RX ?


I've worked with several MCU in the past years. Teensy as introduced me to AVR architecture and Arduino IDE.

Here are the registry configuration for both library :

IrRemoteInt.h

// Teensy 2.0
#elif defined(__AVR_ATmega32U4__)
//#define IR_USE_TIMER1 // tx = pin 14
//#define IR_USE_TIMER3 // tx = pin 9
#define IR_USE_TIMER4_HS // tx = pin 10
....

// defines for timer4 (10 bits, high speed option)
#elif defined(IR_USE_TIMER4_HS)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1))
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1)))
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4))
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
#define TIMER_INTR_NAME TIMER4_OVF_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR4A = (1<<PWM4A); \
TCCR4B = _BV(CS40); \
TCCR4C = 0; \
TCCR4D = (1<<WGM40); \
TCCR4E = 0; \
TC4H = pwmval >> 8; \
OCR4C = pwmval; \
TC4H = (pwmval / 3) >> 8; \
OCR4A = (pwmval / 3) & 255; \
})



known_boards.h (AltSerial)

// Teensy 2.0
//
#if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)

//#define ALTSS_USE_TIMER1
//#define INPUT_CAPTURE_PIN 22 // receive
//#define OUTPUT_COMPARE_A_PIN 14 // transmit
//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
//#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM

#define ALTSS_USE_TIMER3
#define INPUT_CAPTURE_PIN 10 // receive
#define OUTPUT_COMPARE_A_PIN 9 // transmit
known_timer.h

#elif defined(ALTSS_USE_TIMER3)
#define CONFIG_TIMER_NOPRESCALE() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS30))
#define CONFIG_TIMER_PRESCALE_8() (TIMSK3 = 0, TCCR3A = 0, TCCR3B = (1<<ICNC3) | (1<<CS31))
#define CONFIG_MATCH_NORMAL() (TCCR3A = TCCR3A & ~((1<<COM3A1) | (1<<COM3A0)))
#define CONFIG_MATCH_TOGGLE() (TCCR3A = (TCCR3A & ~(1<<COM3A1)) | (1<<COM3A0))
#define CONFIG_MATCH_CLEAR() (TCCR3A = (TCCR3A | (1<<COM3A1)) & ~(1<<COM3A0))
#define CONFIG_MATCH_SET() (TCCR3A = TCCR3A | ((1<<COM3A1) | (1<<COM3A0)))
#define CONFIG_CAPTURE_FALLING_EDGE() (TCCR3B &= ~(1<<ICES3))
#define CONFIG_CAPTURE_RISING_EDGE() (TCCR3B |= (1<<ICES3))
#define ENABLE_INT_INPUT_CAPTURE() (TIFR3 = (1<<ICF3), TIMSK3 = (1<<ICIE3))
#define ENABLE_INT_COMPARE_A() (TIFR3 = (1<<OCF3A), TIMSK3 |= (1<<OCIE3A))
#define ENABLE_INT_COMPARE_B() (TIFR3 = (1<<OCF3B), TIMSK3 |= (1<<OCIE3B))
#define DISABLE_INT_INPUT_CAPTURE() (TIMSK3 &= ~(1<<ICIE3))
#define DISABLE_INT_COMPARE_A() (TIMSK3 &= ~(1<<OCIE3A))
#define DISABLE_INT_COMPARE_B() (TIMSK3 &= ~(1<<OCIE3B))
#define GET_TIMER_COUNT() (TCNT3)
#define GET_INPUT_CAPTURE() (ICR3)
#define GET_COMPARE_A() (OCR3A)
#define GET_COMPARE_B() (OCR3B)
#define SET_COMPARE_A(val) (OCR3A = (val))
#define SET_COMPARE_B(val) (OCR3B = (val))
#define CAPTURE_INTERRUPT TIMER3_CAPT_vect
#define COMPARE_A_INTERRUPT TIMER3_COMPA_vect
#define COMPARE_B_INTERRUPT TIMER3_COMPB_vect

I won't send IR and serial TX simultaneously, one sending at a time, my last option will be to add additional hardware demultiplexer in the circuit.
Can this last option work ?

stumbler
01-13-2013, 08:33 PM
OK, after reading some parts of the AT32u4 datasheet, and reading http://www.arcfn.com/2009/07/secrets-of-arduino-pwm.html ,
I have done some trying and error.
Now I think it's working, I don't have the full test equipment, because it's sunday, just a little led that's glowing.

I didn't understand exactly in which PWM mode it's operating.
Why is there a left shift operation for some bit definition and not for others ?


What I did:
Replaced COM4A1 bit with COM4B1 (Compare module output connection)
PWM4A with PWM4B : Module enable
OCR4A with OCR4B : Compare value register.
CORE_OC4A_PIN with CORE_OC4B_PIN : pin number.

// defines for timer4 (10 bits, high speed option)
#elif defined(IR_USE_TIMER4_HS)
#define TIMER_RESET
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4B1))
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4B1)))
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4))
#define TIMER_DISABLE_INTR (TIMSK4 = 0)
#define TIMER_INTR_NAME TIMER4_OVF_vect
#define TIMER_CONFIG_KHZ(val) ({ \
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
TCCR4A = (1<<PWM4B); \
TCCR4B = _BV(CS40); \
TCCR4C = 0; \
TCCR4D = (1<<WGM40); \
TCCR4E = 0; \
TC4H = pwmval >> 8; \
OCR4C = pwmval; \
TC4H = (pwmval / 3) >> 8; \
OCR4B = (pwmval / 3) & 255; \
})
#define TIMER_CONFIG_NORMAL() ({ \
TCCR4A = 0; \
TCCR4B = _BV(CS40); \
TCCR4C = 0; \
TCCR4D = 0; \
TCCR4E = 0; \
TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \
OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \
TC4H = 0; \
TCNT4 = 0; \
})
#if defined(CORE_OC4B_PIN)
#define TIMER_PWM_PIN CORE_OC4B_PIN /* Teensy */
#else
#error "Please add OC4B pin number here\n"
#endif

PaulStoffregen
01-14-2013, 12:17 AM
That looks like it should work. You could also configure either IRremote or AltSoftSerial to use timer1.

As a sanity check, you're connecting 2 serial devices, right? Teensy 2.0 has a hardware uart, which is always superior to using software emulated serial. The only case where you should even consider SoftwareSerial or AltSoftSerial is when you need to connect 2 serial devices.

stumbler
01-14-2013, 11:21 AM
That looks like it should work. You could also configure either IRremote or AltSoftSerial to use timer1.

As a sanity check, you're connecting 2 serial devices, right? Teensy 2.0 has a hardware uart, which is always superior to using software emulated serial. The only case where you should even consider SoftwareSerial or AltSoftSerial is when you need to connect 2 serial devices.

I've found those TIMER1 define for teensy parts, seemed that it would wreck other things, I prefered to stay with timer4 and use another compare module.

Yes, I will use 2 serial devices (+ USB CDC), this is the reason why I need a reliable software serial communication.
AltSerial Seems to be a quite effective library as explained here:
http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
I've found the opportunity to look at the source and see to use compare module to tx and capture module to rx.

What's distracting me are those shift left of the register bit definition. Why do we need this ?
Do we use Atmega368 bit definition and AT32U4 definitions are just a shift away from the Atmega368 bit definition ?

One day, I want to port a hardware Servo control library that I wrote for PICs which use CCP module (capture/compare/pwm) in order to have a high accuracy (200ns time steps over 2000us) timining output and robust to interrupt disable (1000us latency is possible).