Can I use CurieTimerOne lib inside of another library?

Hello! I am writing a library that needs to have a StartTimer() and StopTimer() function. I figured I could just write a wrapper for CurieTimerOne similar to this:

bool MyClass::StartTimer(unsigned long tickDurationMicroSeconds)
{
     	CurieTimerOne.start(tickDurationMicroSeconds, &timerISR);
        …
}

bool MyClass::StopTimer()
{
     	CurieTimerOne.kill();
	…
}

But this doesn't seem to actually work. I looked at the Servo library because it too uses the ARC Timer 1, and it looks like they are writing the timer limits directly to the registers.

From Servo.cpp

static void timer1_init_servo(uint32_t ticktime)
{
    /* ensure that the timer will not generate interrupts */
    aux_reg_write(ARC_V2_TMR1_CONTROL, 0);
    aux_reg_write(ARC_V2_TMR1_COUNT, 0);    /* clear the count value */

    /* connect specified routine/parameter to the timer 0 interrupt vector */
    interrupt_connect(ARCV2_IRQ_TIMER1, timer1_isr_servo);

    /*
     * Set the reload value to achieve the configured tick rate, enable the
     * counter and interrupt generation.
     *
     * The global variable 'tickunit' represents the #cycles/tick.
     */

    aux_reg_write(ARC_V2_TMR1_LIMIT, ticktime); /* write the limit value */
    /* count only when not halted for debug and enable interrupts */
    aux_reg_write(ARC_V2_TMR1_CONTROL, ARC_V2_TMR_CTRL_NH | ARC_V2_TMR_CTRL_IE);
    aux_reg_write(ARC_V2_TMR1_COUNT, 0); /* write the start value */

    /* Everything has been configured. It is now safe to enable the interrupt */
    interrupt_enable(ARCV2_IRQ_TIMER1);
}

I also looked at the init() implementation in CurieTimerOne.cpp:

int CurieTimer::init(const unsigned int periodHz,
  void (*userCallBack)())
{
  if((periodHz == 0) || (periodHz > MAX_PERIOD_HZ))
    return -(INVALID_PERIOD);

  interrupt_disable(timerIrqNum);  // Disable Timer at controller
  aux_reg_write(timerControlAddr, 0);  // Disable Timer itself

  if(userCallBack != NULL)
    userCB = userCallBack;
  aux_reg_write(timerLimitAddr, periodHz);  // Load Timer period

  aux_reg_write(timerCountAddr, 0);  // Reset variables
  tickCnt = 0;

  if(isrFuncPtr != NULL) {  // Enable timer running with interrupt
    interrupt_connect(timerIrqNum, isrFuncPtr);
    aux_reg_write(timerControlAddr, ARC_TIMER_EN_INTR_BIT_FLAG |
		  ARC_TIMER_NON_HALT_ONLY_BIT_FLAG);
    interrupt_enable(timerIrqNum);
  }
  else {  // Timer runs without interrupt
    aux_reg_write(timerControlAddr, ARC_TIMER_NON_HALT_ONLY_BIT_FLAG);
  }

  currState = RUNNING;
  return SUCCESS;
}

So while I am building my library, should my code look more like what is in the Servo and CurieTimerOne libraries, or is there a way of simply being able to use CurieTimerOne?

Thanks!

Servo uses Timer 1. If you are using servo then it doesn’t matter what library you have, you simply cannot use Timer 1 for other stuff and expect the Servo library to still work. Find a library that uses Timer 2. Or post what you want to do with it. 9 times out of 10 that someone thinks they need a timer they really just need to learn how to write better code with millis.

I’m not using the Servo library for the very reason. I have written my own ISR that periodically calls a callback function which either drives a pin high or low depending on the current state.

The skeleton of that looks like this:

timerISR()
{
   for(int i = 0; i < numServos; i++)
   {
       if(servoList[i].timeout > 0)
          servoList[i].timeout--;
       else
          servoList[i].callback(i);
   }
}

void servoCB(int index)
{
    if(servoList[index].pin == LOW)
        drive HIGH
        recalculate timeout;
    else
        drive LOW
        recalculate timeout
}

So what I would like to happen, is for the ability to call, from my sample sketch, something like

ExampleSketch.ino

myClass.startTimer(unsigned long int microsec);

Which would start the ARC timer 1 exactly as it does in CurieTimerOne.

So you don't want to use the Servo library to drive your servos because it uses Timer 1 to do it? But you want to use Timer 1 to drive your servos? This isn't making any damned sense. Can you explain what's going on without being so vague. Just come out with it already. What are you trying to do here?

I need to control the timer directly in order to support different types of peripherals (leds, servos, loading data, etc.). Timer1 supports PWM but only for 1 pin. And the servo lib supports up to 12 servos, but doesn't allow for anything else to use timer 1.

It appears that a wrapper function for CurieTimerOne.start() should work.. I just have to pin down why it isn't working right now.

I took the CurieTimer1Interrupt example and modified it to fit what I am trying to accomplish. From my example sketch, I am creating an instance of my class, and calling the Initialize() function which in turn calls CurieTimerOne.start(freq, ISR). Everytime the ISR is called, the led should be toggled. It looks like as soon as the sketch is loaded, the led gets turned on, but never toggles. I thought initially that it might be because an instance of CurieTimerOne is automatically created when a sketch is started, but if the library is only included once in my header file, I’m not really sure that that’s the issue.

.h

#ifndef testLib_Timer1_h
#define testLib_Timer1_h

#include <CurieTimerOne.h>

class testLib_Timer1
{
public:
   void Initialize();
   void toggleLed(); 
protected:
};
#endif /* testLib_Timer1_h */

.cpp

#include "testLib_Timer1.h"

bool toggle = 1;

void timedBlinkISR()
{
   digitalWrite(13,toggle);
   toggle = !toggle;
}

void testLib_Timer1::Initialize()
{
   pinMode(13, OUTPUT);
   CurieTimerOne.start(1000, timedBlinkISR);
}

void testLib_Timer1::toggleLed()
{
   if(toggle == 0)
   {
       digitalWrite(13,HIGH);
       toggle = 1;
   }
   else
   {
       digitalWrite(13, LOW);
       toggle = 0;
   }
}

.ino

#include <testLib_Timer1.h>

testLib_Timer1 myTest;

void setup() {
 myTest.Initialize();
}

void loop() {
}

toggle needs to be volatile if it will be altered in the ISR.

Why in the world would you need an ISR to do something as slow as blink an LED?

Delta_G:
toggle needs to be volatile if it will be altered in the ISR.

Thanks for the suggestion. I re-educated myself on the keyword and it makes perfect sense. Unfortunately, I am still not seeing the LED get toggled as expected. It just remains on.

claudiaa:
Thanks for the suggestion. I re-educated myself on the keyword and it makes perfect sense. Unfortunately, I am still not seeing the LED get toggled as expected. It just remains on.

You got new code? But I can't see it.