Skip to content

Commit

Permalink
Version 0.3.0:
Browse files Browse the repository at this point in the history
 - Added SAM (Arduino DUE) compatibility
 - Some timing fixes
 - Examples more correct (added volatile to variable used in ISR)
  • Loading branch information
Naguissa committed Feb 22, 2018
1 parent 98c4b27 commit b241e27
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@



bool status = 0;
volatile bool status = 0;

void timed_function() {
status = !status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@



bool status = 0;
volatile bool status = 0;

void timed_function() {
status = !status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@



bool status = 0;
volatile bool status = 0;

void timed_function() {
status = !status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@



bool status = 0;
volatile bool status = 0;

void timed_function() {
status = !status;
Expand Down
Binary file not shown.
6 changes: 6 additions & 0 deletions extras/data sources.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
AVR Timer2:
- https://hetpro-store.com/TUTORIALES/arduino-timer/
- https://playground.arduino.cc/Main/TimerPWMCheatsheet

Arduino DUE (SAM):
- https://forum.arduino.cc/index.php?topic=130423.0
- http://2manyprojects.net/timer-interrupts


2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=uTimerLib
version=0.2.1
version=0.3.0
author=Naguissa <naguissa@foroelectro.net>
maintainer=Naguissa <naguissa@foroelectro.net>
sentence=Tiny and cross-device compatible timer library
Expand Down
160 changes: 148 additions & 12 deletions src/uTimerLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Timers used by microcontroller
* Atmel AVR: Timer2 (3rd timer)
* STM32: Timer3 (3rd timer)
* SAM (Due): TC3 (Timer1, channel 0)
*
* @copyright Naguissa
* @author Naguissa
Expand Down Expand Up @@ -100,6 +101,9 @@ int uTimerLib::setTimeout_s(void (* cb)(), unsigned long int s) {
* @param unsigned long int us Desired timing in microseconds
*/
void uTimerLib::_attachInterrupt_us(unsigned long int us) {
if (us == 0) { // Not valid
return;
}
#ifdef ARDUINO_ARCH_AVR
unsigned char CSMask = 0;
// For this notes, we asume 16MHz CPU. We recalculate 'us' if not:
Expand All @@ -126,23 +130,23 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
if (us >= 16384) {
CSMask = (1<<CS22) | (1<<CS21) | (1<<CS20);
_overflows = us / 16384;
_remaining = 256 - round((us % 16384) / 64);
_remaining = 256 - ((us % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers
} else {
if (us >= 4096) {
CSMask = (1<<CS22) | (1<<CS21) | (1<<CS20);
_remaining = 256 - round(us / 64);
_remaining = 256 - (us / 64 + 0.5); // + 0.5 is round for positive numbers
} else if (us >= 2048) {
CSMask = (1<<CS22) | (1<<CS21);
_remaining = 256 - round(us / 16);
_remaining = 256 - (us / 16 + 0.5); // + 0.5 is round for positive numbers
} else if (us >= 1024) {
CSMask = (1<<CS22) | (1<<CS20);
_remaining = 256 - round(us / 8);
_remaining = 256 - (us / 8 + 0.5); // + 0.5 is round for positive numbers
} else if (us >= 512) {
CSMask = (1<<CS22);
_remaining = 256 - round(us / 4);
_remaining = 256 - (us / 4 + 0.5); // + 0.5 is round for positive numbers
} else if (us >= 128) {
CSMask = (1<<CS21) | (1<<CS20);
_remaining = 256 - round(us / 2);
_remaining = 256 - (us / 2 + 0.5); // + 0.5 is round for positive numbers
} else if (us >= 16) {
CSMask = (1<<CS21);
_remaining = 256 - us * 2;
Expand All @@ -163,6 +167,7 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
// Clean counter in normal operation, load remaining when overflows == 0
if (__overflows == 0) {
_loadRemaining();
_remaining = 0;
} else {
TCNT2 = 0; // Clean timer count
}
Expand All @@ -188,6 +193,66 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
#endif



// SAM, Arduino Due
#ifdef ARDUINO_ARCH_SAM
/*
Prescalers: MCK/2, MCK/8, MCK/32, MCK/128
Base frequency: 84MHz
Available Timers:
ISR/IRQ TC Channel Due pins
TC0 TC0 0 2, 13
TC1 TC0 1 60, 61
TC2 TC0 2 58
TC3 TC1 0 none
TC4 TC1 1 none
TC5 TC1 2 none
TC6 TC2 0 4, 5
TC7 TC2 1 3, 10
TC8 TC2 2 11, 12
We will use TC1, as it has no associated pins. We will choose Channel 0, so ISR is TC3
REMEMBER! 32 bit counter!!!
Name Prescaler Freq Base Delay Overflow delay
TC_CMR_TCCLKS_TIMER_CLOCK1 2 42MHz 0,023809524us 102261126,913327104us, 102,261126913327104s
TC_CMR_TCCLKS_TIMER_CLOCK2 8 10.5MHz 0,095238095us 409044503,35834112us, 409,04450335834112s
TC_CMR_TCCLKS_TIMER_CLOCK3 32 2.625MHz 0,380952381us 1636178017,523809524us, 1636,178017523809524s
TC_CMR_TCCLKS_TIMER_CLOCK4 128 656.25KHz 1,523809524us 6544712070,913327104us, 6544,712070913327104s
For simplify things, we'll use always TC_CMR_TCCLKS_TIMER_CLOCK32,as has enougth resolution for us.
*/
if (us > 1636178017) {
__overflows = _overflows = us / 1636178017.523809524;
__remaining = _remaining = (us - (1636178017.523809524 * _overflows)) / 0.380952381 + 0.5; // +0.5 is same as round
} else {
__overflows = _overflows = 0;
__remaining = _remaining = (us / 0.380952381 + 0.5); // +0.5 is same as round
}
pmc_set_writeprotect(false); // Enable write
pmc_enable_periph_clk((uint32_t) TC3_IRQn); // Enable TC1 - channel 0 peripheral
TC_Configure(TC1, 0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK3); // Configure clock; prescaler = 32

if (__overflows == 0) {
_loadRemaining();
_remaining = 0;
} else {
TC_SetRC(TC1, 0, 4294967295); // Int on last number
}

TC_Start(TC1, 0);
TC1->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;
TC1->TC_CHANNEL[0].TC_IDR = ~TC_IER_CPCS;
NVIC_EnableIRQ(TC3_IRQn);
#endif



}


Expand All @@ -199,6 +264,9 @@ void uTimerLib::_attachInterrupt_us(unsigned long int us) {
* @param unsigned long int s Desired timing in seconds
*/
void uTimerLib::_attachInterrupt_s(unsigned long int s) {
if (s == 0) { // Not valid
return;
}
// Arduino AVR
#ifdef ARDUINO_ARCH_AVR
unsigned char CSMask = 0;
Expand All @@ -224,9 +292,9 @@ void uTimerLib::_attachInterrupt_s(unsigned long int s) {
// Anti-Overflow trick:
if (s > 16384) {
unsigned long int temp = floor(s / 16384) * 16384;
_remaining = 256 - round((((s - temp) * 1000000) % 16384) / 64);
_remaining = 256 - ((((s - temp) * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers
} else {
_remaining = 256 - round(((s * 1000000) % 16384) / 64);
_remaining = 256 - (((s * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers
}

__overflows = _overflows;
Expand Down Expand Up @@ -264,6 +332,43 @@ void uTimerLib::_attachInterrupt_s(unsigned long int s) {
Timer3.resume();
#endif


// SAM, Arduino Due
#ifdef ARDUINO_ARCH_SAM
/*
See _ms functions for detailed info; here only selected points
Name Prescaler Freq Base Delay Overflow delay
TC_CMR_TCCLKS_TIMER_CLOCK4 128 656.25KHz 1,523809524us 6544712070,913327104us, 6544,712070913327104s
For simplify things, we'll use always TC_CMR_TCCLKS_TIMER_CLOCK32,as has enougth resolution for us.
*/
if (s > 6544) {
__overflows = _overflows = s / 6544.712070913327104;
__remaining = _remaining = (s - (6544.712070913327104 * _overflows) / 0.000001523809524 + 0.5); // +0.5 is same as round
} else {
__overflows = _overflows = 0;
__remaining = _remaining = (s / 0.000001523809524 + 0.5); // +0.5 is same as round
}

pmc_set_writeprotect(false); // Enable write
//pmc_enable_periph_clk((uint32_t) TC3_IRQn); // Enable TC1 - channel 0 peripheral
pmc_enable_periph_clk(ID_TC3); // Enable TC1 - channel 0 peripheral
TC_Configure(TC1, 0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4); // Configure clock; prescaler = 128

if (__overflows == 0) {
_loadRemaining();
_remaining = 0;
} else {
TC_SetRC(TC1, 0, 4294967295); // Int on last number
}

TC1->TC_CHANNEL[0].TC_IER=TC_IER_CPCS;
TC1->TC_CHANNEL[0].TC_IDR=~TC_IER_CPCS;
NVIC_EnableIRQ(TC3_IRQn);
TC_Start(TC1, 0);
#endif
}


Expand All @@ -279,6 +384,10 @@ void uTimerLib::_loadRemaining() {
#endif

// STM32: Not needed

#ifdef ARDUINO_ARCH_SAM
TC_SetRC(TC1, 0, _remaining);
#endif
}

/**
Expand All @@ -297,6 +406,12 @@ void uTimerLib::clearTimer() {
#ifdef _VARIANT_ARDUINO_STM32_
Timer3.pause();
#endif

// SAM, Arduino Due
#ifdef ARDUINO_ARCH_SAM
NVIC_DisableIRQ(TC3_IRQn);
#endif

}

/**
Expand All @@ -309,27 +424,40 @@ void uTimerLib::_interrupt() {
if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen
return;
}

if (_overflows > 0) {
_overflows--;
}
if (_overflows == 0 && _remaining > 0) {
// Load remaining count to counter
_loadRemaining();
// And clear remaining count
_remaining = 0;
// Load remaining count to counter
_loadRemaining();
// And clear remaining count
_remaining = 0;
} else if (_overflows == 0 && _remaining == 0) {
if (_type == UTIMERLIB_TYPE_TIMEOUT) {
clearTimer();
} else if (_type == UTIMERLIB_TYPE_INTERVAL) {
if (__overflows == 0) {
_remaining = __remaining;
_loadRemaining();
_remaining = 0;
} else {
_overflows = __overflows;
_remaining = __remaining;
#ifdef ARDUINO_ARCH_SAM
TC_SetRC(TC1, 0, 4294967295);
#endif
}
}
_cb();
}
#ifdef ARDUINO_ARCH_SAM
// Reload for SAM
else if (_overflows > 0) {
TC_SetRC(TC1, 0, 4294967295);
}
#endif

}

/**
Expand Down Expand Up @@ -361,3 +489,11 @@ uTimerLib TimerLib = uTimerLib();
}
#endif


#ifdef ARDUINO_ARCH_SAM
void TC3_Handler() {
TC_GetStatus(TC1, 0); // reset interrupt
TimerLib._interrupt();
}
#endif

9 changes: 7 additions & 2 deletions src/uTimerLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@
static uTimerLib *_instance;

unsigned long int _overflows = 0;
unsigned char _remaining = 0;
unsigned long int __overflows = 0;
unsigned char __remaining = 0;
#ifdef ARDUINO_ARCH_AVR
unsigned char _remaining = 0;
unsigned char __remaining = 0;
#else
unsigned long int _remaining = 0;
unsigned long int __remaining = 0;
#endif
void (*_cb)() = NULL;
unsigned char _type = UTIMERLIB_TYPE_OFF;

Expand Down

0 comments on commit b241e27

Please sign in to comment.