diff --git a/libraries/CurieTimerOne/CurieTimerOne.cpp b/libraries/CurieTimerOne/CurieTimerOne.cpp index fe0d7653..5aa76385 100644 --- a/libraries/CurieTimerOne/CurieTimerOne.cpp +++ b/libraries/CurieTimerOne/CurieTimerOne.cpp @@ -50,25 +50,15 @@ static void timerOnePwmCbWrapper(void) } -CurieTimer::CurieTimer(const unsigned int timerNum) : +CurieTimer::CurieTimer() : tickCnt(0), currState(IDLE), userCB(NULL) { - if(timerNum == 0) { - timerCountAddr = ARC_V2_TMR0_COUNT; - timerControlAddr = ARC_V2_TMR0_CONTROL; - timerLimitAddr = ARC_V2_TMR0_LIMIT; - timerIrqNum = ARCV2_IRQ_TIMER0; - isrFuncPtr = NULL; - pwmCB = NULL; - } - else { - timerCountAddr = ARC_V2_TMR1_COUNT; - timerControlAddr = ARC_V2_TMR1_CONTROL; - timerLimitAddr = ARC_V2_TMR1_LIMIT; - timerIrqNum = ARCV2_IRQ_TIMER1; - isrFuncPtr = &timerOneIsrWrapper; - pwmCB = &timerOnePwmCbWrapper; - } + timerCountAddr = ARC_V2_TMR1_COUNT; + timerControlAddr = ARC_V2_TMR1_CONTROL; + timerLimitAddr = ARC_V2_TMR1_LIMIT; + timerIrqNum = ARCV2_IRQ_TIMER1; + isrFuncPtr = &timerOneIsrWrapper; + pwmCB = &timerOnePwmCbWrapper; } @@ -86,6 +76,7 @@ void CurieTimer::kill() tickCnt = 0; userCB = NULL; currState = IDLE; + pauseCntrl = pauseCount = pwmPin = dutyCycle = nonDutyCycle = periodInUsec = 0; } @@ -154,25 +145,26 @@ int CurieTimer::pwmStart(unsigned int outputPin, double dutyPercentage, unsigned unsigned int pwmPeriod; // Safe guard against periodUsec overflow when convert to hz. - if((periodUsec == 0) || (periodUsec >= MAX_PERIOD)) + if((periodUsec == 0) || (periodUsec >= MAX_PERIOD_USEC)) return -(INVALID_PERIOD); if((dutyPercentage < 0.0) || (dutyPercentage > 100.0)) return -(INVALID_DUTY_CYCLE); + periodInUsec = periodUsec; pwmPin = outputPin; pinMode(pwmPin, OUTPUT); if(dutyPercentage == 0.0) { - // If PWM is already running, reset the timer and set pin to LOW - kill(); + // If PWM is already running, pause to stop it from interfering, and set pin to LOW + pause(); digitalWrite(pwmPin, LOW); return SUCCESS; } if(dutyPercentage == 100.0) { - // If PWM is already running, reset the timer and set pin to HIGH - kill(); + // If PWM is already running, pause to stop it from interfering, and set pin to HIGH + pause(); digitalWrite(pwmPin, HIGH); return SUCCESS; } @@ -204,7 +196,7 @@ int CurieTimer::pwmStart(unsigned int outputPin, int dutyRange, unsigned int per if((dutyRange < 0) || (dutyRange > MAX_DUTY_RANGE)) return -(INVALID_DUTY_CYCLE); - return pwmStart(outputPin, ((double)dutyRange * 100.0)/(double)MAX_DUTY_RANGE, periodUsec); + return pwmStart(outputPin, ((double)dutyRange/(double)MAX_DUTY_RANGE) * 100.0, periodUsec); } @@ -224,6 +216,31 @@ inline void CurieTimer::pwmCallBack(void) } +// Method: setPeriod +// This method is for making this library backward compatible to the AVR +// TimerOne library. The routine changs the time period by pausing the timer +// and resume it with the new period. This is not timer re-initialization. + +void CurieTimer::setPeriod(unsigned long microseconds) +{ + unsigned int periodHz; + + if((microseconds == 0) || (microseconds > MAX_PERIOD_USEC)) + microseconds = 1000000; + + periodInUsec = microseconds; + periodHz = microseconds * HZ_USEC; + pause(); + + aux_reg_write(timerLimitAddr, periodHz); // Load Timer period + + if(pauseCount >= periodHz) + pauseCount = 0; + + resume(); +} + + // Method: init // Kick off the timer with a period, in Hz, provided. Initialize // timer to run in non-halt mode, enable timer interrupt. Always install @@ -232,7 +249,7 @@ inline void CurieTimer::pwmCallBack(void) int CurieTimer::init(const unsigned int periodHz, void (*userCallBack)()) { - if((periodHz == 0) || (periodHz > MAX_PERIOD)) + if((periodHz == 0) || (periodHz > MAX_PERIOD_HZ)) return -(INVALID_PERIOD); interrupt_disable(timerIrqNum); // Disable Timer at controller diff --git a/libraries/CurieTimerOne/CurieTimerOne.h b/libraries/CurieTimerOne/CurieTimerOne.h index b8708f0d..b84704bc 100644 --- a/libraries/CurieTimerOne/CurieTimerOne.h +++ b/libraries/CurieTimerOne/CurieTimerOne.h @@ -48,11 +48,8 @@ // Timer-1 is clocked at ARCV2_TIMER1_CLOCK_FREQ defined in conf.h const unsigned int HZ_USEC = (ARCV2_TIMER1_CLOCK_FREQ / 1000000); // Hz per micro second. -const unsigned int MAX_PERIOD = (0x0FFFFFFFF / HZ_USEC); - -// The two ARC timers. -const unsigned int ARC_TIMER_0 = 0; -const unsigned int ARC_TIMER_1 = 1; +const unsigned int MAX_PERIOD_HZ = 0x0FFFFFFFF; +const unsigned int MAX_PERIOD_USEC = (MAX_PERIOD_HZ / HZ_USEC); // Duty cycle range. const int MAX_DUTY_RANGE = 1023; @@ -80,21 +77,91 @@ typedef enum { // Class: CurieTimer // // Description: -// This class describes the functionalities of a Arc Timer. It has the knowledge -// of only 2 timers available in the h/w - a limitation. The timers are sourced by -// a 32 HHz clock, a constant, used in this class, defined in the conf.h file. +// This class describes the functionalities of a Arc Timer, in particular, timer-1. +// Timer-0 is not available for this module to utilize. The timers are clocked by +// a 32 HHz source and have 32-bit counters. // class CurieTimer { public: - // Constructor. Default is timer-1. - CurieTimer(const unsigned int timerNum = ARC_TIMER_1); + // Constructor. + CurieTimer(); + + // The following methods are similar to the ones found in the AVR TimerOne library. + + //**************************** + // Configuration + //**************************** + + inline void initialize(unsigned long microseconds = 1000000) { + if((microseconds == 0) || (microseconds > MAX_PERIOD_USEC)) + microseconds = 1000000; + periodInUsec = microseconds; + init( (microseconds * HZ_USEC), NULL ); + } + + void setPeriod(unsigned long microseconds); + + //**************************** + // Run Control + //**************************** + + inline void start(void) { + pause(); + pauseCount = 0; + resume(); + } + + inline void stop(void) { return pause(); } + + inline void restart(void) { start(); } + + // Resume the timer from where it was paused. + void resume(void); + + //**************************** + // PWM outputs + //**************************** + + inline void setPwmDuty(char pin, unsigned int duty) { + pwmStart( pin, (int) duty, periodInUsec ); + } + + inline void pwm(char pin, unsigned int duty) { + pwmStart( pin, (int) duty, periodInUsec ); + } + + inline void pwm(char pin, unsigned int duty, unsigned long microseconds) { + pwmStart( pin, (int) duty, microseconds ); + } + + inline void disablePwm(char pin) { + pwmStop(); + } + + //**************************** + // Interrupt Function + //**************************** + + void attachInterrupt(void (*isr)()); + + inline void attachInterrupt(void (*isr)(), unsigned long microseconds) { + attachInterrupt( isr ); + setPeriod( microseconds ); + } + + inline void detachInterrupt(void) { attachInterrupt(NULL); }; + + ///////// + // The following are additional methods provided by Intel for the Curie platform. + //////// // Set up the timer with the input period, in usec, and the call back routine. // Period stays with the timer until it is killed or re/start another round. - inline int start(const unsigned int timerPeriodUsec = 0, + inline int start(const unsigned int timerPeriodUsec, void (*userCallBack)() = NULL) { + periodInUsec = timerPeriodUsec; return( init((timerPeriodUsec * HZ_USEC), userCallBack) ); } // Restarting the timer, start counter from 0. @@ -104,8 +171,6 @@ class CurieTimer void kill(void); // Attach or detach the user call back routine. - void attachInterrupt(void (*userCallBack)()); - void detachInterrupt(void) { return attachInterrupt(NULL); }; // Timer interrupt count. inline unsigned int readTickCount(void) { return tickCnt; } @@ -114,9 +179,6 @@ class CurieTimer // Pausing the timer = no count up, no interrupt. void pause(void); - inline void stop(void) { return pause(); } - // Resume the timer from where it was paused. - void resume(void); // Start software PWM. Note that the timer is consumed once PWM is set. int pwmStart(unsigned int outputPin, double dutyPercentage, unsigned int periodUsec); @@ -148,6 +210,7 @@ class CurieTimer unsigned int pwmPin; unsigned int dutyCycle; unsigned int nonDutyCycle; + unsigned int periodInUsec; void (*isrFuncPtr)(); void (*userCB)(); diff --git a/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino b/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino new file mode 100644 index 00000000..04147cf0 --- /dev/null +++ b/libraries/CurieTimerOne/examples/CurieTimer1BlinkSpeed/blinkSpeed.ino @@ -0,0 +1,30 @@ +#include + +const int blinkPin = 13; + +void setup(void) +{ + CurieTimerOne.initialize(50000); + Serial.begin(9600); +} + +void loop(void) +{ + unsigned int range; + + Serial.println("PWM blink: low -> high duty cycle"); + + for (float dutyCycle = 5.0; dutyCycle <= 100.0; dutyCycle++) { + range = (dutyCycle / 100) * 1023; + CurieTimerOne.pwm(blinkPin, range); + delay(50); + } + + Serial.println("PWM blink: high -> low duty cycle"); + + for (float dutyCycle = 100.0; dutyCycle > 5.0; dutyCycle--) { + range = (dutyCycle / 100) * 1023; + CurieTimerOne.setPwmDuty(blinkPin, range); + delay(50); + } +} diff --git a/libraries/CurieTimerOne/keywords.txt b/libraries/CurieTimerOne/keywords.txt index bcf1d0a4..734a16df 100644 --- a/libraries/CurieTimerOne/keywords.txt +++ b/libraries/CurieTimerOne/keywords.txt @@ -11,18 +11,24 @@ CurieTimer KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### -start KEYWORD2 -restart KEYWORD2 -kill KEYWORD2 -attachInterrupt KEYWORD2 -detachInterrupt KEYWORD2 -readTickCount KEYWORD2 -rdRstTickCount KEYWORD2 -pause KEYWORD2 -resume KEYWORD2 -pwmStart KEYWORD2 -pwmStop KEYWORD2 +initialize KEYWORD2 +setPeriod KEYWORD2 +start KEYWORD2 +stop KEYWORD2 +restart KEYWORD2 +resume KEYWORD2 +setPwmDuty KEYWORD2 +pwm KEYWORD2 +disablePwm KEYWORD2 +attachInterrupt KEYWORD2 +detachInterrupt KEYWORD2 +kill KEYWORD2 +readTickCount KEYWORD2 +rdRstTickCount KEYWORD2 +pause KEYWORD2 +pwmStart KEYWORD2 +pwmStop KEYWORD2 ####################################### # Instances (KEYWORD2) ####################################### -CurieTimerOne KEYWORD2 +CurieTimerOne KEYWORD2