LightwaveRF icon indicating copy to clipboard operation
LightwaveRF copied to clipboard

Timer2 reliance - Fails to compile on 32u4 (No Timer2)

Open AssidiousBlue opened this issue 9 years ago • 3 comments

Currently the library is reliant on Timer2 use (8bit timer).

Unfortunately this makes it incompatible with ATMega 32u4 chips such as on the leonardo or Teensey. This chip has only the one 8-bit timer.

I'm quite confident that

Similar (subsequently solved) issue on IR library; https://code.google.com/p/rogue-code/issues/detail?id=13

Adding in something similar to this:

// Teensy 2.0 versus Leonardo
// These boards use the same chip but the pinouts are different.
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
  // it's Teensy 2.0
  //#define IR_USE_TIMER1   // tx = pin 14
  //#define IR_USE_TIMER3   // tx = pin 9
  #define IR_USE_TIMER4_HS  // tx = pin 10
#else
  // it's probably Leonardo
  #define IR_USE_TIMER1   // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4_HS  // tx = pin 13
#endif

as suggested here http://forum.arduino.cc/index.php?topic=115033.0 could handle some of the issues; although I don't think the pin needs changing but the interrupt enabling

Looking at you code for LwTx.h, this might fit in somewhere around line line 24, for example something like this;

// Teensy 2.0 versus Leonardo
// These boards use the same chip but the pinouts are different.
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
  // it's Teensy 2.0
  //#define TX_PIN_DEFAULT  14 // tx = pin 14 for Timer1
  //#define TX_PIN_DEFAULT   9 // tx = pin 9 for Timer3
  #define TX_PIN_DEFAULT  4 // tx = pin 10 for Timer4 high speed
#else
  // it's probably Leonardo
  #define IR_USE_TIMER1   9 // tx = pin 9
  //#define IR_USE_TIMER3   5 // tx = pin 5
  //#define IR_USE_TIMER4_HS  13 // tx = pin 13
#endif

and then in LwTx.cpp around line 248 add

// Teensy 2.0 versus Leonardo
// These boards use the same chip but the pinouts are different.
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
  // it's Teensy 2.0
    //code for timer4HS
#else
extern void lw_timer_Setup(void (*isrCallback)(), int period) {
    isrRoutine = isrCallback; // unused here as callback is direct
    byte clock = (period / 4) - 1;;
    cli();//stop interrupts
    //set timer1 interrupt at  clock uSec (default 140)
    TCCR1A = 0;// set entire TCCR21 register to 0
    TCCR1B = 0;// same for TCCR21
    TCNT1L  = 0;//initialize counter low byte value to 0
        TCNT1H = 0;//initialize counter high byte value to 0
    // set compare match register for clock uSec
    OCR1A = clock;// = 16MHz Prescale to 4 uSec * (counter+1)
    // turn on CTC mode
    TCCR1A |= (1 << WGM21);
    // Set CS11 bit for 64 prescaler
    TCCR1B |= (1 << CS22);   
    // disable timer compare interrupt
    TIMSK1 &= ~(1 << OCIE1A);
    sei();//enable interrupts
}

extern void lw_timer_Start() {
   //enable timer 2 interrupts
    TIMSK1 |= (1 << OCIE1A);
}

extern void lw_timer_Stop() {
    //disable timer 1 interrupt
    TIMSK1 &= ~(1 << OCIE1A);
}

//Hand over to real isr
ISR(TIMER1_COMPA_vect){
    isrTXtimer();
}

#endif

However I have had enough difficulty getting it to compile I have eclipsed my very minimal coding knowledge. I am not sure if you would need to change the TOP value of the timer, or if the compare limit set by the code above would be enough. I am also not sure if the rest of your code will handle a 16-bit return or needs changing to address timer1

Just sharing my thoughts having run into difficulty, sorry if it annoys

AssidiousBlue avatar Mar 07 '15 21:03 AssidiousBlue

Thanks for sharing that. I haven't uses TEENSY or 32u4 so far, but I will check that out further.

The reason why this code has been fairly easily ported to several environments is that the only real dependency for the tx side is that one can get a regular call-back from a timer at about 140uSec intervals. The state machine does the rest. Whether it is a 8 or 16 or even 32bit timer doesn't matter. The rest of the code does not access timers at all.

The rx side uses a pin change interrupt and the requirement there is to be able to read a clock at the interrupt which is good to within a few uSec.

What environment are you compiling in?

roberttidey avatar Mar 07 '15 22:03 roberttidey

Below code works on my Sparkfun pro micro (equivalent to an Arduino Leonardo, uses the 32u4)

//Default case is Arduino Mega328 which uses the TIMER2 ***TL changed to 32u4 timer3
extern void lw_timer_Setup(void (*isrCallback)(), int period) {
    isrRoutine = isrCallback; // unused here as callback is direct
    byte clock = (period / 4) - 1;;
    cli();//stop interrupts
    //set timer2 interrupt at  clock uSec (default 140)
    TCCR3A = 0;// set entire TCCR2A register to 0
    TCCR3B = 0;// same for TCCR2B
    TCNT3  = 0;//initialize counter value to 0
    // set compare match register for clock uSec
    OCR3A = clock;// = 16MHz Prescale to 4 uSec * (counter+1)
    // turn on CTC mode
    TCCR3B |= (1 << WGM32);
    // Set bits for 64 prescaler
    TCCR3B |= (1 << CS31);   
    TCCR3B |= (1 << CS30);   
    // disable timer compare interrupt
    TIMSK3 &= ~(1 << OCIE3A);
    sei();//enable interrupts
}

extern void lw_timer_Start() {
   //enable timer 2 interrupts
    TIMSK3 |= (1 << OCIE3A);
}

extern void lw_timer_Stop() {
    //disable timer 2 interrupt
    TIMSK3 &= ~(1 << OCIE3A);
}

//Hand over to real isr
ISR(TIMER3_COMPA_vect){
    isrTXtimer();
}

#endif

thigger avatar Dec 14 '15 11:12 thigger

Thanks. I have added this in as a variant selected by the PRO32U4 #define in the header file

roberttidey avatar Dec 18 '15 15:12 roberttidey