diff --git a/library.properties b/library.properties index 73ed2fc..5021e17 100644 --- a/library.properties +++ b/library.properties @@ -1,11 +1,11 @@ -name=uTimerLib -version=1.6.0 -author=Naguissa -maintainer=Naguissa -sentence=Tiny and cross-device compatible timer library -paragraph=Supports Arduino AVR, SAM, STM32, ESP8266, ESP32 and SAMD21 microcontrollers -category=Timing -url=https://github.com/Naguissa/uTimerLib -architectures=* -includes=uTimerLib.h - +name=uTimerLib +version=1.6.1 +author=Naguissa +maintainer=Naguissa +sentence=Tiny and cross-device compatible timer library +paragraph=Supports Arduino AVR, SAM, STM32, ESP8266, ESP32 and SAMD21 microcontrollers +category=Timing +url=https://github.com/Naguissa/uTimerLib +architectures=* +includes=uTimerLib.h + diff --git a/src/hardware/uTimerLib.ATTINY.cpp b/src/hardware/uTimerLib.ATTINY.cpp index 3a94ecd..52018d3 100644 --- a/src/hardware/uTimerLib.ATTINY.cpp +++ b/src/hardware/uTimerLib.ATTINY.cpp @@ -1,279 +1,279 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.ATTINY.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ - -#if defined(ARDUINO_ARCH_AVR) && (defined(ARDUINO_attiny) || defined(ARDUINO_AVR_ATTINYX4) || defined(ARDUINO_AVR_ATTINYX5) || defined(ARDUINO_AVR_ATTINYX7) || defined(ARDUINO_AVR_ATTINYX8) || defined(ARDUINO_AVR_ATTINYX61) || defined(ARDUINO_AVR_ATTINY43) || defined(ARDUINO_AVR_ATTINY828) || defined(ARDUINO_AVR_ATTINY1634) || defined(ARDUINO_AVR_ATTINYX313)) -#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - - #ifndef TCCR1A - #define TCCR1A GTCCR - #endif - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - - unsigned char CSMask = 0; - // For this notes, we asume 16MHz CPU. We recalculate 'us' if not: - if (F_CPU != 16000000) { - us = F_CPU / 16000000 * us; - } - TIMSK &= ~((1 << TOIE1) | (1 << OCIE1A)); // Disable overflow interruption when 0 + Disable interrupt on compare match - cli(); - // ATTiny, using Timer1. Counts at 16MHz (it other speed is used we recalculate us before) - /* - Prescaler: TCCR1; 4 last bits, CS10, CS11, CS12 and CS13 - - CS13 CS12 CS11 CS10 Freq Divisor Base Delay Overflow delay - 0 0 0 0 stopped - - - - 0 0 0 1 16MHz 1 0.0625us 16us - 0 0 1 0 16MHz 2 0.125us 32us - 0 0 1 1 16MHz 4 0.25us 64us - 0 1 0 0 16MHz 8 0.5us 128us - 0 1 0 1 16MHz 16 1us 256us - 0 1 1 0 16MHz 32 2us 512us - 0 1 1 1 16MHz 64 4us 1024us - 1 0 0 0 16MHz 128 8us 2048us - 1 0 0 1 16MHz 256 16us 4096us - 1 0 1 0 16MHz 512 32us 8192us - 1 0 1 1 16MHz 1024 64us 16384us - 1 1 0 0 16MHz 2048 128us 32768us - 1 1 0 1 16MHz 4096 256us 65536us - 1 1 1 0 16MHz 8192 512us 131072us - 1 1 1 1 16MHz 16384 1024us 262144us - */ - if (us >= 262144) { - CSMask = (1<= 131072) { - CSMask = (1<= 65536) { - CSMask = (1<= 32768) { - CSMask = (1<= 16384) { - CSMask = (1<= 8192) { - CSMask = (1<= 4096) { - CSMask = (1<= 2048) { - CSMask = (1<= 1024) { - CSMask = (1<= 512) { - CSMask = (1<= 256) { - CSMask = (1<= 128) { - CSMask = (1<= 64) { - CSMask = (1<= 32) { - CSMask = (1<= 16) { - CSMask = (1< 0) { - _overflows--; - } - if (_overflows == 0 && _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; - } - } - _cb(); - } - } - - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - - - - - - /** - * \brief Attach Interrupts using internal functionality - * - * Note: This is device-dependant - */ - ISR(TIMER1_OVF_vect) { - TimerLib._interrupt(); - } - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.ATTINY.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ + +#if (defined(ARDUINO_ARCH_AVR) && (defined(ARDUINO_attiny) || defined(ARDUINO_AVR_ATTINYX4) || defined(ARDUINO_AVR_ATTINYX5) || defined(ARDUINO_AVR_ATTINYX7) || defined(ARDUINO_AVR_ATTINYX8) || defined(ARDUINO_AVR_ATTINYX61) || defined(ARDUINO_AVR_ATTINY43) || defined(ARDUINO_AVR_ATTINY828) || defined(ARDUINO_AVR_ATTINY1634) || defined(ARDUINO_AVR_ATTINYX313))) && defined(UTIMERLIB_HW_COMPILE) +#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + + #ifndef TCCR1A + #define TCCR1A GTCCR + #endif + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + + unsigned char CSMask = 0; + // For this notes, we asume 16MHz CPU. We recalculate 'us' if not: + if (F_CPU != 16000000) { + us = F_CPU / 16000000 * us; + } + TIMSK &= ~((1 << TOIE1) | (1 << OCIE1A)); // Disable overflow interruption when 0 + Disable interrupt on compare match + cli(); + // ATTiny, using Timer1. Counts at 16MHz (it other speed is used we recalculate us before) + /* + Prescaler: TCCR1; 4 last bits, CS10, CS11, CS12 and CS13 + + CS13 CS12 CS11 CS10 Freq Divisor Base Delay Overflow delay + 0 0 0 0 stopped - - - + 0 0 0 1 16MHz 1 0.0625us 16us + 0 0 1 0 16MHz 2 0.125us 32us + 0 0 1 1 16MHz 4 0.25us 64us + 0 1 0 0 16MHz 8 0.5us 128us + 0 1 0 1 16MHz 16 1us 256us + 0 1 1 0 16MHz 32 2us 512us + 0 1 1 1 16MHz 64 4us 1024us + 1 0 0 0 16MHz 128 8us 2048us + 1 0 0 1 16MHz 256 16us 4096us + 1 0 1 0 16MHz 512 32us 8192us + 1 0 1 1 16MHz 1024 64us 16384us + 1 1 0 0 16MHz 2048 128us 32768us + 1 1 0 1 16MHz 4096 256us 65536us + 1 1 1 0 16MHz 8192 512us 131072us + 1 1 1 1 16MHz 16384 1024us 262144us + */ + if (us >= 262144) { + CSMask = (1<= 131072) { + CSMask = (1<= 65536) { + CSMask = (1<= 32768) { + CSMask = (1<= 16384) { + CSMask = (1<= 8192) { + CSMask = (1<= 4096) { + CSMask = (1<= 2048) { + CSMask = (1<= 1024) { + CSMask = (1<= 512) { + CSMask = (1<= 256) { + CSMask = (1<= 128) { + CSMask = (1<= 64) { + CSMask = (1<= 32) { + CSMask = (1<= 16) { + CSMask = (1< 0) { + _overflows--; + } + if (_overflows == 0 && _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; + } + } + _cb(); + } + } + + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + + + + + + /** + * \brief Attach Interrupts using internal functionality + * + * Note: This is device-dependant + */ + ISR(TIMER1_OVF_vect) { + TimerLib._interrupt(); + } + +#endif +#endif diff --git a/src/hardware/uTimerLib.AVR.cpp b/src/hardware/uTimerLib.AVR.cpp index 38c023d..768616f 100644 --- a/src/hardware/uTimerLib.AVR.cpp +++ b/src/hardware/uTimerLib.AVR.cpp @@ -1,361 +1,361 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.AVR.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ - -#if (defined(__AVR_ATmega32U4__) || defined(ARDUINO_ARCH_AVR)) && !defined(ARDUINO_attiny) -#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - - unsigned char CSMask = 0; - // For this notes, we asume 16MHz CPU. We recalculate 'us' if not: - if (F_CPU != 16000000) { - us = F_CPU / 16000000 * us; - } - - // Leonardo and other 32U4 boards - #ifdef __AVR_ATmega32U4__ - TIMSK3 &= ~((1 << TOIE3) | (1 << OCIE3A)); // Disable overflow interruption when 0 + Disable interrupt on compare match - cli(); - // 32U4, using Timer3. Counts at 16MHz - /* - Prescaler: TCCR3B; 3 last bits, CS30, CS31 and CS32 - - CS32 CS31 CS30 Freq Divisor Base Delay Overflow delay - 0 0 0 stopped - - - - 0 0 1 16MHz 1 0.0625us 16us - 0 1 0 2MHz 8 0.5us 128us - 0 1 1 250KHz 64 4us 1024us - 1 0 0 62.5KHz 256 16us 4096us - 1 0 1 15.625KHz 1024 64us 16384us - */ - if (us >= 16384) { - CSMask = (1<= 4096) { - CSMask = (1<= 2048) { - CSMask = (1<= 512) { - CSMask = (1<= 16) { - CSMask = (1<= 16384) { - CSMask = (1<= 4096) { - CSMask = (1<= 2048) { - CSMask = (1<= 1024) { - CSMask = (1<= 512) { - CSMask = (1<= 128) { - CSMask = (1<= 16) { - CSMask = (1< 500000) { - _overflows = s / 16384 * 1000000; - } else { - _overflows = s * 1000000 / 16384; - } - // Original: _remaining = 256 - round(((us * 1000000) % 16384) / 64); - // Anti-Overflow trick: - if (s > 16384) { - unsigned long int temp = floor(s / 16384) * 16384; - _remaining = 256 - ((((s - temp) * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers - } else { - _remaining = 256 - (((s * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers - } - - __overflows = _overflows; - __remaining = _remaining; - _overflows += 1; - - //ASSR &= ~(1< 500000) { - _overflows = s / 16384 * 1000000; - } else { - _overflows = s * 1000000 / 16384; - } - // Original: _remaining = 256 - round(((us * 1000000) % 16384) / 64); - // Anti-Overflow trick: - if (s > 16384) { - unsigned long int temp = floor(s / 16384) * 16384; - _remaining = 256 - ((((s - temp) * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers - } else { - _remaining = 256 - (((s * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers - } - - __overflows = _overflows; - __remaining = _remaining; - _overflows += 1; - - ASSR &= ~(1< 0) { - _overflows--; - } - if (_overflows == 0 && _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; - } - } - _cb(); - } - } - - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - - - - - - /** - * \brief Attach Interrupts using internal functionality - * - * Note: This is device-dependant - */ - #ifdef __AVR_ATmega32U4__ - // Arduino AVR - ISR(TIMER3_OVF_vect) { - TimerLib._interrupt(); - } - #else - // Arduino AVR - ISR(TIMER2_OVF_vect) { - TimerLib._interrupt(); - } - #endif - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.AVR.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ + +#if (defined(__AVR_ATmega32U4__) || defined(ARDUINO_ARCH_AVR)) && !defined(ARDUINO_attiny) && defined(UTIMERLIB_HW_COMPILE) +#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + + unsigned char CSMask = 0; + // For this notes, we asume 16MHz CPU. We recalculate 'us' if not: + if (F_CPU != 16000000) { + us = F_CPU / 16000000 * us; + } + + // Leonardo and other 32U4 boards + #ifdef __AVR_ATmega32U4__ + TIMSK3 &= ~((1 << TOIE3) | (1 << OCIE3A)); // Disable overflow interruption when 0 + Disable interrupt on compare match + cli(); + // 32U4, using Timer3. Counts at 16MHz + /* + Prescaler: TCCR3B; 3 last bits, CS30, CS31 and CS32 + + CS32 CS31 CS30 Freq Divisor Base Delay Overflow delay + 0 0 0 stopped - - - + 0 0 1 16MHz 1 0.0625us 16us + 0 1 0 2MHz 8 0.5us 128us + 0 1 1 250KHz 64 4us 1024us + 1 0 0 62.5KHz 256 16us 4096us + 1 0 1 15.625KHz 1024 64us 16384us + */ + if (us >= 16384) { + CSMask = (1<= 4096) { + CSMask = (1<= 2048) { + CSMask = (1<= 512) { + CSMask = (1<= 16) { + CSMask = (1<= 16384) { + CSMask = (1<= 4096) { + CSMask = (1<= 2048) { + CSMask = (1<= 1024) { + CSMask = (1<= 512) { + CSMask = (1<= 128) { + CSMask = (1<= 16) { + CSMask = (1< 500000) { + _overflows = s / 16384 * 1000000; + } else { + _overflows = s * 1000000 / 16384; + } + // Original: _remaining = 256 - round(((us * 1000000) % 16384) / 64); + // Anti-Overflow trick: + if (s > 16384) { + unsigned long int temp = floor(s / 16384) * 16384; + _remaining = 256 - ((((s - temp) * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers + } else { + _remaining = 256 - (((s * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers + } + + __overflows = _overflows; + __remaining = _remaining; + _overflows += 1; + + //ASSR &= ~(1< 500000) { + _overflows = s / 16384 * 1000000; + } else { + _overflows = s * 1000000 / 16384; + } + // Original: _remaining = 256 - round(((us * 1000000) % 16384) / 64); + // Anti-Overflow trick: + if (s > 16384) { + unsigned long int temp = floor(s / 16384) * 16384; + _remaining = 256 - ((((s - temp) * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers + } else { + _remaining = 256 - (((s * 1000000) % 16384) / 64 + 0.5); // + 0.5 is round for positive numbers + } + + __overflows = _overflows; + __remaining = _remaining; + _overflows += 1; + + ASSR &= ~(1< 0) { + _overflows--; + } + if (_overflows == 0 && _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; + } + } + _cb(); + } + } + + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + + + + + + /** + * \brief Attach Interrupts using internal functionality + * + * Note: This is device-dependant + */ + #ifdef __AVR_ATmega32U4__ + // Arduino AVR + ISR(TIMER3_OVF_vect) { + TimerLib._interrupt(); + } + #else + // Arduino AVR + ISR(TIMER2_OVF_vect) { + TimerLib._interrupt(); + } + #endif + +#endif +#endif diff --git a/src/hardware/uTimerLib.ESP.cpp b/src/hardware/uTimerLib.ESP.cpp index 8a38b65..29a6507 100644 --- a/src/hardware/uTimerLib.ESP.cpp +++ b/src/hardware/uTimerLib.ESP.cpp @@ -1,126 +1,126 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.ESP.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) -#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - unsigned long int ms = (us / 1000) + 0.5; - if (ms == 0) { - ms = 1; - } - __overflows = _overflows = __remaining = _remaining = 0; - _ticker.attach_ms(ms, uTimerLib::interrupt); - } - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired s seconds - * - * Note: This is device-dependant - * - * @param s Desired timing in seconds - */ - void uTimerLib::_attachInterrupt_s(unsigned long int s) { - if (s == 0) { // Not valid - return; - } - - __overflows = _overflows = __remaining = _remaining = 0; - _ticker.attach(s, uTimerLib::interrupt); - } - - - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void uTimerLib::_loadRemaining() { } - - /** - * \brief Clear timer interrupts - * - * Note: This is device-dependant - */ - void uTimerLib::clearTimer() { - _ticker.detach(); - } - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - void uTimerLib::_interrupt() { - if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen - return; - } - if (_type == UTIMERLIB_TYPE_TIMEOUT) { - clearTimer(); - } - _cb(); - } - - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - - - /** - * \brief Attach Interrupts using internal functionality - * - * Note: This is device-dependant - */ - void uTimerLib::interrupt() { - TimerLib._interrupt(); - } - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.ESP.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +#if (defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)) && defined(UTIMERLIB_HW_COMPILE) +#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + unsigned long int ms = (us / 1000) + 0.5; + if (ms == 0) { + ms = 1; + } + __overflows = _overflows = __remaining = _remaining = 0; + _ticker.attach_ms(ms, uTimerLib::interrupt); + } + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired s seconds + * + * Note: This is device-dependant + * + * @param s Desired timing in seconds + */ + void uTimerLib::_attachInterrupt_s(unsigned long int s) { + if (s == 0) { // Not valid + return; + } + + __overflows = _overflows = __remaining = _remaining = 0; + _ticker.attach(s, uTimerLib::interrupt); + } + + + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void uTimerLib::_loadRemaining() { } + + /** + * \brief Clear timer interrupts + * + * Note: This is device-dependant + */ + void uTimerLib::clearTimer() { + _ticker.detach(); + } + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + void uTimerLib::_interrupt() { + if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen + return; + } + if (_type == UTIMERLIB_TYPE_TIMEOUT) { + clearTimer(); + } + _cb(); + } + + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + + + /** + * \brief Attach Interrupts using internal functionality + * + * Note: This is device-dependant + */ + void uTimerLib::interrupt() { + TimerLib._interrupt(); + } + +#endif +#endif diff --git a/src/hardware/uTimerLib.SAM.cpp b/src/hardware/uTimerLib.SAM.cpp index 916c3fa..0a15374 100644 --- a/src/hardware/uTimerLib.SAM.cpp +++ b/src/hardware/uTimerLib.SAM.cpp @@ -1,235 +1,235 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.SAM.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -#ifdef ARDUINO_ARCH_SAM -#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - - - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - - /* - 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(ID_TC3); // 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); - } - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired s seconds - * - * Note: This is device-dependant - * - * @param s Desired timing in seconds - */ - void uTimerLib::_attachInterrupt_s(unsigned long int s) { - if (s == 0) { // Not valid - return; - } - - /* - 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); - } - - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void uTimerLib::_loadRemaining() { - TC_SetRC(TC1, 0, _remaining); - } - - /** - * \brief Clear timer interrupts - * - * Note: This is device-dependant - */ - void uTimerLib::clearTimer() { - _type = UTIMERLIB_TYPE_OFF; - - NVIC_DisableIRQ(TC3_IRQn); - } - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - 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; - } 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; - - TC_SetRC(TC1, 0, 4294967295); - } - } - _cb(); - } else if (_overflows > 0) { // Reload for SAM - TC_SetRC(TC1, 0, 4294967295); - } - } - - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - - - - /** - * \brief Attach Interrupts using internal functionality - * - * Note: This is device-dependant - */ - void TC3_Handler() { - TC_GetStatus(TC1, 0); // reset interrupt - TimerLib._interrupt(); - } - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.SAM.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +#if defined(ARDUINO_ARCH_SAM) && defined(UTIMERLIB_HW_COMPILE) +#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + + + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + + /* + 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(ID_TC3); // 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); + } + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired s seconds + * + * Note: This is device-dependant + * + * @param s Desired timing in seconds + */ + void uTimerLib::_attachInterrupt_s(unsigned long int s) { + if (s == 0) { // Not valid + return; + } + + /* + 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); + } + + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void uTimerLib::_loadRemaining() { + TC_SetRC(TC1, 0, _remaining); + } + + /** + * \brief Clear timer interrupts + * + * Note: This is device-dependant + */ + void uTimerLib::clearTimer() { + _type = UTIMERLIB_TYPE_OFF; + + NVIC_DisableIRQ(TC3_IRQn); + } + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + 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; + } 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; + + TC_SetRC(TC1, 0, 4294967295); + } + } + _cb(); + } else if (_overflows > 0) { // Reload for SAM + TC_SetRC(TC1, 0, 4294967295); + } + } + + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + + + + /** + * \brief Attach Interrupts using internal functionality + * + * Note: This is device-dependant + */ + void TC3_Handler() { + TC_GetStatus(TC1, 0); // reset interrupt + TimerLib._interrupt(); + } + +#endif +#endif diff --git a/src/hardware/uTimerLib.SAMD21.cpp b/src/hardware/uTimerLib.SAMD21.cpp index 41b57f2..be78dcd 100644 --- a/src/hardware/uTimerLib.SAMD21.cpp +++ b/src/hardware/uTimerLib.SAMD21.cpp @@ -1,272 +1,272 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.SAMD21.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -#ifdef _SAMD21_ -#ifndef _uTimerLib_IMP_ - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - - /* - 16 bit timer - - Prescaler: - Prescalers: GCLK_TC, GCLK_TC/2, GCLK_TC/4, GCLK_TC/8, GCLK_TC/16, GCLK_TC/64, GCLK_TC/256, GCLK_TC/1024 - Base frequency: 84MHz - - We will use TCC2, as there're some models with only 3 timers (regular models have 5 TCs) - - REMEMBER! 16 bit counter!!! - - - Name Prescaler Freq Base Delay Overflow delay - GCLK_TC 1 48MHz 0,020833333us 1365,333333333us; 1,365333333333ms - GCLK_TC/2 2 24MHz 0,041666667us 2730,666666667us; 2,730666666667ms - GCLK_TC/4 4 12MHz 0,083333333us 5461,333333333us; 5,461333333333ms - GCLK_TC/8 8 6MHz 0,166666667us 10922,666666667us; 10,922666666667ms - GCLK_TC/16 16 3MHz 0,333333333us 21845,333333333us; 21,845333333333ms - GCLK_TC/64 64 750KHz 1,333333333us 87381,333311488us; 87,381333311488ms - GCLK_TC/256 256 187,5KHz 5,333333333us 349525,333311488us; 349,525333311488ms - GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s - - Will be using: - GCLK_TC/16 for us - GCLK_TC/1024 for s - */ - - // Enable clock for TC - REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3)) ; - while (GCLK->STATUS.bit.SYNCBUSY == 1); // sync - - // Disable TC - _TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; - while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - - // Set Timer counter Mode to 16 bits + Set TC as normal Normal Frq + Prescaler: GCLK_TC/16 - _TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV16); - while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - - if (us > 21845) { - __overflows = _overflows = us / 21845.333333333; - __remaining = _remaining = ((us - (21845.333333333 * _overflows)) / 0.333333333) + 0.5; // +0.5 is same as round - } else { - __overflows = _overflows = 0; - __remaining = _remaining = (us / 0.333333333) + 0.5; // +0.5 is same as round - } - - if (__overflows == 0) { - _loadRemaining(); - _remaining = 0; - } else { - _TC->CC[0].reg = 65535; - _TC->INTENSET.reg = 0; // disable all interrupts - _TC->INTENSET.bit.OVF = 1; // enable overfollow - // Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - } - - _TC->COUNT.reg = 0; // Reset to 0 - - NVIC_EnableIRQ(TC3_IRQn); - - // Enable TC - _TC->CTRLA.reg |= TC_CTRLA_ENABLE; - } - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired s seconds - * - * Note: This is device-dependant - * - * @param s Desired timing in seconds - */ - void uTimerLib::_attachInterrupt_s(unsigned long int s) { - if (s == 0) { // Not valid - return; - } - - /* - GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s - */ - - // Enable clock for TC - REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3)) ; - while (GCLK->STATUS.bit.SYNCBUSY == 1); // sync - - // Disable TC - _TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; - while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - - // Set Timer counter Mode to 16 bits + Set TC as normal Normal Frq + Prescaler: GCLK_TC/1024 - _TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV1024); - while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - - if (s > 1) { - __overflows = _overflows = s / 1.398101333333333; - __remaining = _remaining = ((s - (1.398101333333333 * _overflows)) / 0.000021333333333) + 0.5; // +0.5 is same as round - } else { - __overflows = _overflows = 0; - __remaining = _remaining = (s / 0.000021333333333) + 0.5; // +0.5 is same as round - } - - if (__overflows == 0) { - _loadRemaining(); - _remaining = 0; - } else { - _TC->CC[0].reg = 65535; - _TC->INTENSET.reg = 0; // disable all interrupts - _TC->INTENSET.bit.OVF = 1; // enable overfollow - // Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - } - - _TC->COUNT.reg = 0; // Reset to 0 - - NVIC_EnableIRQ(TC3_IRQn); - - // Enable TC - _TC->CTRLA.reg |= TC_CTRLA_ENABLE; - } - - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void uTimerLib::_loadRemaining() { - _TC->COUNT.reg = 0; // Reset to 0 - _TC->CC[0].reg = _remaining; - _TC->INTENSET.reg = 0; // disable all interrupts - _TC->INTENSET.bit.MC0 = 1; // enable compare match to CC0 - while (_TC->STATUS.bit.SYNCBUSY == 1); // sync - } - - /** - * \brief Clear timer interrupts - * - * Note: This is device-dependant - */ - void uTimerLib::clearTimer() { - _type = UTIMERLIB_TYPE_OFF; - - // Disable TC - _TC->INTENSET.reg = 0; // disable all interrupts - _TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; -} - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - 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; - } 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; - - _TC->COUNT.reg = 0; // Reset to 0 - _TC->INTENSET.reg = 0; // disable all interrupts - _TC->INTENSET.bit.OVF = 0; // enable overfollow - _TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0 - _TC->CC[0].reg = 65535; - } - } - _cb(); - } else if (_overflows > 0) { // Reload for SAMD21 - _TC->COUNT.reg = 0; // Reset to 0 - _TC->INTENSET.reg = 0; // disable all interrupts - _TC->INTENSET.bit.OVF = 0; // enable overfollow - _TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0 - _TC->CC[0].reg = 65535; - } - } - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - - - - /** - * \brief Attach Interrupts using internal functionality - * - * Note: This is device-dependant - */ - void TC3_Handler() { - // Overflow - Nothing, we will use compare to max value instead to unify behaviour - if (TimerLib._TC->INTFLAG.bit.OVF == 1) { - TimerLib._TC->INTFLAG.bit.OVF = 1; // Clear flag - TimerLib._interrupt(); - } - // Compare - if (TimerLib._TC->INTFLAG.bit.MC0 == 1) { - TimerLib._TC->INTFLAG.bit.MC0 = 1; // Clear flag - TimerLib._interrupt(); - } - } - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.SAMD21.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +#if defined(_SAMD21_) && defined(UTIMERLIB_HW_COMPILE) +#ifndef _uTimerLib_IMP_ + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + + /* + 16 bit timer + + Prescaler: + Prescalers: GCLK_TC, GCLK_TC/2, GCLK_TC/4, GCLK_TC/8, GCLK_TC/16, GCLK_TC/64, GCLK_TC/256, GCLK_TC/1024 + Base frequency: 84MHz + + We will use TCC2, as there're some models with only 3 timers (regular models have 5 TCs) + + REMEMBER! 16 bit counter!!! + + + Name Prescaler Freq Base Delay Overflow delay + GCLK_TC 1 48MHz 0,020833333us 1365,333333333us; 1,365333333333ms + GCLK_TC/2 2 24MHz 0,041666667us 2730,666666667us; 2,730666666667ms + GCLK_TC/4 4 12MHz 0,083333333us 5461,333333333us; 5,461333333333ms + GCLK_TC/8 8 6MHz 0,166666667us 10922,666666667us; 10,922666666667ms + GCLK_TC/16 16 3MHz 0,333333333us 21845,333333333us; 21,845333333333ms + GCLK_TC/64 64 750KHz 1,333333333us 87381,333311488us; 87,381333311488ms + GCLK_TC/256 256 187,5KHz 5,333333333us 349525,333311488us; 349,525333311488ms + GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s + + Will be using: + GCLK_TC/16 for us + GCLK_TC/1024 for s + */ + + // Enable clock for TC + REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3)) ; + while (GCLK->STATUS.bit.SYNCBUSY == 1); // sync + + // Disable TC + _TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; + while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + + // Set Timer counter Mode to 16 bits + Set TC as normal Normal Frq + Prescaler: GCLK_TC/16 + _TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV16); + while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + + if (us > 21845) { + __overflows = _overflows = us / 21845.333333333; + __remaining = _remaining = ((us - (21845.333333333 * _overflows)) / 0.333333333) + 0.5; // +0.5 is same as round + } else { + __overflows = _overflows = 0; + __remaining = _remaining = (us / 0.333333333) + 0.5; // +0.5 is same as round + } + + if (__overflows == 0) { + _loadRemaining(); + _remaining = 0; + } else { + _TC->CC[0].reg = 65535; + _TC->INTENSET.reg = 0; // disable all interrupts + _TC->INTENSET.bit.OVF = 1; // enable overfollow + // Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + } + + _TC->COUNT.reg = 0; // Reset to 0 + + NVIC_EnableIRQ(TC3_IRQn); + + // Enable TC + _TC->CTRLA.reg |= TC_CTRLA_ENABLE; + } + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired s seconds + * + * Note: This is device-dependant + * + * @param s Desired timing in seconds + */ + void uTimerLib::_attachInterrupt_s(unsigned long int s) { + if (s == 0) { // Not valid + return; + } + + /* + GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s + */ + + // Enable clock for TC + REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3)) ; + while (GCLK->STATUS.bit.SYNCBUSY == 1); // sync + + // Disable TC + _TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; + while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + + // Set Timer counter Mode to 16 bits + Set TC as normal Normal Frq + Prescaler: GCLK_TC/1024 + _TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV1024); + while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + + if (s > 1) { + __overflows = _overflows = s / 1.398101333333333; + __remaining = _remaining = ((s - (1.398101333333333 * _overflows)) / 0.000021333333333) + 0.5; // +0.5 is same as round + } else { + __overflows = _overflows = 0; + __remaining = _remaining = (s / 0.000021333333333) + 0.5; // +0.5 is same as round + } + + if (__overflows == 0) { + _loadRemaining(); + _remaining = 0; + } else { + _TC->CC[0].reg = 65535; + _TC->INTENSET.reg = 0; // disable all interrupts + _TC->INTENSET.bit.OVF = 1; // enable overfollow + // Skip: while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + } + + _TC->COUNT.reg = 0; // Reset to 0 + + NVIC_EnableIRQ(TC3_IRQn); + + // Enable TC + _TC->CTRLA.reg |= TC_CTRLA_ENABLE; + } + + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void uTimerLib::_loadRemaining() { + _TC->COUNT.reg = 0; // Reset to 0 + _TC->CC[0].reg = _remaining; + _TC->INTENSET.reg = 0; // disable all interrupts + _TC->INTENSET.bit.MC0 = 1; // enable compare match to CC0 + while (_TC->STATUS.bit.SYNCBUSY == 1); // sync + } + + /** + * \brief Clear timer interrupts + * + * Note: This is device-dependant + */ + void uTimerLib::clearTimer() { + _type = UTIMERLIB_TYPE_OFF; + + // Disable TC + _TC->INTENSET.reg = 0; // disable all interrupts + _TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; +} + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + 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; + } 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; + + _TC->COUNT.reg = 0; // Reset to 0 + _TC->INTENSET.reg = 0; // disable all interrupts + _TC->INTENSET.bit.OVF = 0; // enable overfollow + _TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0 + _TC->CC[0].reg = 65535; + } + } + _cb(); + } else if (_overflows > 0) { // Reload for SAMD21 + _TC->COUNT.reg = 0; // Reset to 0 + _TC->INTENSET.reg = 0; // disable all interrupts + _TC->INTENSET.bit.OVF = 0; // enable overfollow + _TC->INTENSET.bit.MC0 = 1; // disable compare match to CC0 + _TC->CC[0].reg = 65535; + } + } + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + + + + /** + * \brief Attach Interrupts using internal functionality + * + * Note: This is device-dependant + */ + void TC3_Handler() { + // Overflow - Nothing, we will use compare to max value instead to unify behaviour + if (TimerLib._TC->INTFLAG.bit.OVF == 1) { + TimerLib._TC->INTFLAG.bit.OVF = 1; // Clear flag + TimerLib._interrupt(); + } + // Compare + if (TimerLib._TC->INTFLAG.bit.MC0 == 1) { + TimerLib._TC->INTFLAG.bit.MC0 = 1; // Clear flag + TimerLib._interrupt(); + } + } + +#endif +#endif diff --git a/src/hardware/uTimerLib.SAMD51.cpp b/src/hardware/uTimerLib.SAMD51.cpp index a00573a..dfd3eaa 100644 --- a/src/hardware/uTimerLib.SAMD51.cpp +++ b/src/hardware/uTimerLib.SAMD51.cpp @@ -1,282 +1,282 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.SAMD51.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -#ifdef __SAMD51__ -#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - #define UTIMERLIB_WAIT_SYNC() while (TC1->COUNT16.SYNCBUSY.reg) - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - /* - 16 bit timer - - Prescaler: - Prescalers: GCLK_TC, GCLK_TC/2, GCLK_TC/4, GCLK_TC/8, GCLK_TC/16, GCLK_TC/64, GCLK_TC/256, GCLK_TC/1024 - Base frequency: 84MHz - - We will use TC1 - - REMEMBER! 16 bit counter!!! - - Name Prescaler Freq Base Delay Overflow delay - GCLK_TC 1 120MHz 0,008333333us 546,133333333us; 0,546133333333ms - GCLK_TC/2 2 60MHz 0,016666667us 1092,266666667us; 1,092266666667ms - GCLK_TC/4 4 30MHz 0,033333333us 2184,533333333us; 2,184533333333ms - GCLK_TC/8 8 20MHz 0,066666667us 4369,066666667us; 4,369066666667ms - GCLK_TC/16 16 10MHz 0,133333333us 8738,133333333us; 8,738133333333ms - GCLK_TC/64 64 1,875MHz 0,533333333us 34952,533333333us; 34,952533333333ms - GCLK_TC/256 256 468,75KHz 2,133333333us 139810,133333333us; 139,810133333333ms - GCLK_TC/1024 1024 117,1875Hz 8,533333333us 559240,533333333us; 559,240533333333ms - - Will be using: - GCLK_TC/16 for us - GCLK_TC/1024 for s - */ - - -/* - // Enable the TC bus clock - MCLK->APBAMASK.bit.TC1_ = 1; - GCLK->PCHCTRL[TC1_GCLK_ID].bit.GEN = 0; - GCLK->PCHCTRL[TC1_GCLK_ID].bit.CHEN = 1; -*/ - // Enable the TC bus clock - GCLK->PCHCTRL[TC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN; - while(GCLK->SYNCBUSY.reg); // sync - - TC1->COUNT16.CTRLA.bit.ENABLE = 0; - UTIMERLIB_WAIT_SYNC(); - - TC1->COUNT16.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val; - UTIMERLIB_WAIT_SYNC(); - - - - TC1->COUNT16.CTRLA.reg &= ((~(TC_CTRLA_ENABLE)) & (~(TC_CTRLA_PRESCALER_DIV1024)) & (~(TC_CTRLA_PRESCALER_DIV256)) & (~(TC_CTRLA_PRESCALER_DIV64)) & (~(TC_CTRLA_PRESCALER_DIV16)) & (~(TC_CTRLA_PRESCALER_DIV4)) & (~(TC_CTRLA_PRESCALER_DIV2)) & (~(TC_CTRLA_PRESCALER_DIV1))); - UTIMERLIB_WAIT_SYNC(); - - TC1->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16; - UTIMERLIB_WAIT_SYNC(); - - - if (us > 8738) { - __overflows = _overflows = us / 8738.133333333; - __remaining = _remaining = (us - (8738.133333333 * _overflows)) / 0.133333333 + 0.5; // +0.5 is same as round - } else { - __overflows = _overflows = 0; - __remaining = _remaining = (us / 0.133333333 + 0.5); // +0.5 is same as round - } - - if (__remaining != 0) { - __remaining = _remaining = (((uint16_t) 0xffff) - __remaining); // Remaining is max value minus remaining - } - - if (__overflows == 0) { - _loadRemaining(); - _remaining = 0; - } else { - TC1->COUNT16.COUNT.reg = 0; - } - - - TC1->COUNT16.INTENSET.reg = 0; - TC1->COUNT16.INTENSET.bit.OVF = 1; - // Enable InterruptVector - NVIC_EnableIRQ(TC1_IRQn); - - // Count on event - //TC1->COUNT16.EVCTRL.bit.EVACT = TC_EVCTRL_EVACT_COUNT_Val; - - TC1->COUNT16.CTRLA.bit.ENABLE = 1; - } - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired s seconds - * - * Note: This is device-dependant - * - * @param s Desired timing in seconds - */ - void uTimerLib::_attachInterrupt_s(unsigned long int s) { - if (s == 0) { // Not valid - return; - } - - /* - GCLK_TC/1024 1024 117,1875Hz 8,533333333us 559240,533333333us; 559,240533333333ms - */ - - - - - // Enable the TC bus clock - GCLK->PCHCTRL[TC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN; - while(GCLK->SYNCBUSY.reg); // sync - - TC1->COUNT16.CTRLA.bit.ENABLE = 0; - UTIMERLIB_WAIT_SYNC(); - - TC1->COUNT16.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val; - UTIMERLIB_WAIT_SYNC(); - - - - TC1->COUNT16.CTRLA.reg &= ((~(TC_CTRLA_ENABLE)) & (~(TC_CTRLA_PRESCALER_DIV1024)) & (~(TC_CTRLA_PRESCALER_DIV256)) & (~(TC_CTRLA_PRESCALER_DIV64)) & (~(TC_CTRLA_PRESCALER_DIV16)) & (~(TC_CTRLA_PRESCALER_DIV4)) & (~(TC_CTRLA_PRESCALER_DIV2)) & (~(TC_CTRLA_PRESCALER_DIV1))); - UTIMERLIB_WAIT_SYNC(); - - TC1->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024; - UTIMERLIB_WAIT_SYNC(); - - - __overflows = _overflows = s / 0.559240533333333; - __remaining = _remaining = (s - (0.559240533333333 * _overflows)) / 0.000008533333333 + 0.5; // +0.5 is same as round - - if (__remaining != 0) { - __remaining = _remaining = (((uint16_t) 0xffff) - __remaining); // Remaining is max value minus remaining - } - - if (__overflows == 0) { - _loadRemaining(); - _remaining = 0; - } else { - TC1->COUNT16.COUNT.reg = 0; - } - - - TC1->COUNT16.INTENSET.reg = 0; - TC1->COUNT16.INTENSET.bit.OVF = 1; - // Enable InterruptVector - NVIC_EnableIRQ(TC1_IRQn); - - // Count on event - //TC1->COUNT16.EVCTRL.bit.EVACT = TC_EVCTRL_EVACT_COUNT_Val; - - TC1->COUNT16.CTRLA.bit.ENABLE = 1; - } - - - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void uTimerLib::_loadRemaining() { - TC1->COUNT16.COUNT.reg = _remaining; - } - - /** - * \brief Clear timer interrupts - * - * Note: This is device-dependant - */ - void uTimerLib::clearTimer() { - _type = UTIMERLIB_TYPE_OFF; - - TC1->COUNT16.INTENSET.reg = 0; - // Disable InterruptVector - NVIC_DisableIRQ(TC1_IRQn); - } - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - 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; - } 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; - } - } - _cb(); - } - } - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - - - - - - /** - * \brief Attach Interrupts using internal functionality - * - * Note: This is device-dependant - */ - void TC1_Handler() { - if (TC1->COUNT16.INTFLAG.bit.OVF == 1) { - TC1->COUNT16.INTENSET.bit.OVF = 1; // Clear flag - TimerLib._interrupt(); - } - if (TC1->COUNT16.INTFLAG.bit.MC0 == 1) { - TC1->COUNT16.INTENSET.bit.MC0 = 1; // Clear flag - } - } - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.SAMD51.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +#if defined(__SAMD51__) && defined(UTIMERLIB_HW_COMPILE) +#if !defined(_uTimerLib_IMP_) && defined(_uTimerLib_cpp_) + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + #define UTIMERLIB_WAIT_SYNC() while (TC1->COUNT16.SYNCBUSY.reg) + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + /* + 16 bit timer + + Prescaler: + Prescalers: GCLK_TC, GCLK_TC/2, GCLK_TC/4, GCLK_TC/8, GCLK_TC/16, GCLK_TC/64, GCLK_TC/256, GCLK_TC/1024 + Base frequency: 84MHz + + We will use TC1 + + REMEMBER! 16 bit counter!!! + + Name Prescaler Freq Base Delay Overflow delay + GCLK_TC 1 120MHz 0,008333333us 546,133333333us; 0,546133333333ms + GCLK_TC/2 2 60MHz 0,016666667us 1092,266666667us; 1,092266666667ms + GCLK_TC/4 4 30MHz 0,033333333us 2184,533333333us; 2,184533333333ms + GCLK_TC/8 8 20MHz 0,066666667us 4369,066666667us; 4,369066666667ms + GCLK_TC/16 16 10MHz 0,133333333us 8738,133333333us; 8,738133333333ms + GCLK_TC/64 64 1,875MHz 0,533333333us 34952,533333333us; 34,952533333333ms + GCLK_TC/256 256 468,75KHz 2,133333333us 139810,133333333us; 139,810133333333ms + GCLK_TC/1024 1024 117,1875Hz 8,533333333us 559240,533333333us; 559,240533333333ms + + Will be using: + GCLK_TC/16 for us + GCLK_TC/1024 for s + */ + + +/* + // Enable the TC bus clock + MCLK->APBAMASK.bit.TC1_ = 1; + GCLK->PCHCTRL[TC1_GCLK_ID].bit.GEN = 0; + GCLK->PCHCTRL[TC1_GCLK_ID].bit.CHEN = 1; +*/ + // Enable the TC bus clock + GCLK->PCHCTRL[TC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN; + while(GCLK->SYNCBUSY.reg); // sync + + TC1->COUNT16.CTRLA.bit.ENABLE = 0; + UTIMERLIB_WAIT_SYNC(); + + TC1->COUNT16.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val; + UTIMERLIB_WAIT_SYNC(); + + + + TC1->COUNT16.CTRLA.reg &= ((~(TC_CTRLA_ENABLE)) & (~(TC_CTRLA_PRESCALER_DIV1024)) & (~(TC_CTRLA_PRESCALER_DIV256)) & (~(TC_CTRLA_PRESCALER_DIV64)) & (~(TC_CTRLA_PRESCALER_DIV16)) & (~(TC_CTRLA_PRESCALER_DIV4)) & (~(TC_CTRLA_PRESCALER_DIV2)) & (~(TC_CTRLA_PRESCALER_DIV1))); + UTIMERLIB_WAIT_SYNC(); + + TC1->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16; + UTIMERLIB_WAIT_SYNC(); + + + if (us > 8738) { + __overflows = _overflows = us / 8738.133333333; + __remaining = _remaining = (us - (8738.133333333 * _overflows)) / 0.133333333 + 0.5; // +0.5 is same as round + } else { + __overflows = _overflows = 0; + __remaining = _remaining = (us / 0.133333333 + 0.5); // +0.5 is same as round + } + + if (__remaining != 0) { + __remaining = _remaining = (((uint16_t) 0xffff) - __remaining); // Remaining is max value minus remaining + } + + if (__overflows == 0) { + _loadRemaining(); + _remaining = 0; + } else { + TC1->COUNT16.COUNT.reg = 0; + } + + + TC1->COUNT16.INTENSET.reg = 0; + TC1->COUNT16.INTENSET.bit.OVF = 1; + // Enable InterruptVector + NVIC_EnableIRQ(TC1_IRQn); + + // Count on event + //TC1->COUNT16.EVCTRL.bit.EVACT = TC_EVCTRL_EVACT_COUNT_Val; + + TC1->COUNT16.CTRLA.bit.ENABLE = 1; + } + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired s seconds + * + * Note: This is device-dependant + * + * @param s Desired timing in seconds + */ + void uTimerLib::_attachInterrupt_s(unsigned long int s) { + if (s == 0) { // Not valid + return; + } + + /* + GCLK_TC/1024 1024 117,1875Hz 8,533333333us 559240,533333333us; 559,240533333333ms + */ + + + + + // Enable the TC bus clock + GCLK->PCHCTRL[TC1_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN; + while(GCLK->SYNCBUSY.reg); // sync + + TC1->COUNT16.CTRLA.bit.ENABLE = 0; + UTIMERLIB_WAIT_SYNC(); + + TC1->COUNT16.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val; + UTIMERLIB_WAIT_SYNC(); + + + + TC1->COUNT16.CTRLA.reg &= ((~(TC_CTRLA_ENABLE)) & (~(TC_CTRLA_PRESCALER_DIV1024)) & (~(TC_CTRLA_PRESCALER_DIV256)) & (~(TC_CTRLA_PRESCALER_DIV64)) & (~(TC_CTRLA_PRESCALER_DIV16)) & (~(TC_CTRLA_PRESCALER_DIV4)) & (~(TC_CTRLA_PRESCALER_DIV2)) & (~(TC_CTRLA_PRESCALER_DIV1))); + UTIMERLIB_WAIT_SYNC(); + + TC1->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024; + UTIMERLIB_WAIT_SYNC(); + + + __overflows = _overflows = s / 0.559240533333333; + __remaining = _remaining = (s - (0.559240533333333 * _overflows)) / 0.000008533333333 + 0.5; // +0.5 is same as round + + if (__remaining != 0) { + __remaining = _remaining = (((uint16_t) 0xffff) - __remaining); // Remaining is max value minus remaining + } + + if (__overflows == 0) { + _loadRemaining(); + _remaining = 0; + } else { + TC1->COUNT16.COUNT.reg = 0; + } + + + TC1->COUNT16.INTENSET.reg = 0; + TC1->COUNT16.INTENSET.bit.OVF = 1; + // Enable InterruptVector + NVIC_EnableIRQ(TC1_IRQn); + + // Count on event + //TC1->COUNT16.EVCTRL.bit.EVACT = TC_EVCTRL_EVACT_COUNT_Val; + + TC1->COUNT16.CTRLA.bit.ENABLE = 1; + } + + + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void uTimerLib::_loadRemaining() { + TC1->COUNT16.COUNT.reg = _remaining; + } + + /** + * \brief Clear timer interrupts + * + * Note: This is device-dependant + */ + void uTimerLib::clearTimer() { + _type = UTIMERLIB_TYPE_OFF; + + TC1->COUNT16.INTENSET.reg = 0; + // Disable InterruptVector + NVIC_DisableIRQ(TC1_IRQn); + } + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + 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; + } 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; + } + } + _cb(); + } + } + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + + + + + + /** + * \brief Attach Interrupts using internal functionality + * + * Note: This is device-dependant + */ + void TC1_Handler() { + if (TC1->COUNT16.INTFLAG.bit.OVF == 1) { + TC1->COUNT16.INTENSET.bit.OVF = 1; // Clear flag + TimerLib._interrupt(); + } + if (TC1->COUNT16.INTFLAG.bit.MC0 == 1) { + TC1->COUNT16.INTENSET.bit.MC0 = 1; // Clear flag + } + } + +#endif +#endif diff --git a/src/hardware/uTimerLib.STM32.cpp b/src/hardware/uTimerLib.STM32.cpp index c01aaa7..6ebe029 100644 --- a/src/hardware/uTimerLib.STM32.cpp +++ b/src/hardware/uTimerLib.STM32.cpp @@ -1,194 +1,194 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.STM32.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -#ifdef _VARIANT_ARDUINO_STM32_ -#ifndef _uTimerLib_IMP_ - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { - if (us == 0) { // Not valid - return; - } - - // STM32, all variants - Max us is: uint32 max / CYCLES_PER_MICROSECOND - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - Timer3->setMode(1, TIMER_OUTPUT_COMPARE); - __overflows = _overflows = __remaining = _remaining = 0; - Timer3->setOverflow(us, MICROSEC_FORMAT); - Timer3->setCaptureCompare(1, us, MICROSEC_COMPARE_FORMAT); - if (_toInit) { - _toInit = false; - Timer3->attachInterrupt(1, uTimerLib::interrupt); - } - Timer3->resume(); - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #else - Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); - __overflows = _overflows = __remaining = _remaining = 0; - uint16_t timerOverflow = Timer3.setPeriod(us); - Timer3.setCompare(TIMER_CH1, timerOverflow); - if (_toInit) { - _toInit = false; - Timer3.attachInterrupt(TIMER_CH1, uTimerLib::interrupt); - } - Timer3.refresh(); - Timer3.resume(); - #endif - } - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired s seconds - * - * Note: This is device-dependant - * - * @param s Desired timing in seconds - */ - void uTimerLib::_attachInterrupt_s(unsigned long int s) { - if (s == 0) { // Not valid - return; - } - - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - Timer3->setMode(1, TIMER_OUTPUT_COMPARE); - __overflows = _overflows = s; - __remaining = _remaining = 0; - Timer3->setOverflow((unsigned long int) 1000000, MICROSEC_FORMAT); - Timer3->setCaptureCompare(1, (unsigned long int) 1000000, MICROSEC_COMPARE_FORMAT); - if (_toInit) { - _toInit = false; - Timer3->attachInterrupt(1, uTimerLib::interrupt); - } - Timer3->resume(); - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #else - Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); - Timer3.setPeriod((uint32) 1000000); - Timer3.setCompare(TIMER_CH1, 0); - Timer3.setCount(1); - __overflows = _overflows = s; - __remaining = _remaining = 0; - if (_toInit) { - _toInit = false; - Timer3.attachInterrupt(TIMER_CH1, uTimerLib::interrupt); - } - Timer3.refresh(); - Timer3.resume(); - #endif - } - - - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void uTimerLib::_loadRemaining() { } - - /** - * \brief Clear timer interrupts - * - * Note: This is device-dependant - */ - void uTimerLib::clearTimer() { - _type = UTIMERLIB_TYPE_OFF; - - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - Timer3->pause(); - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #else - Timer3.pause(); - #endif - } - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - void uTimerLib::_interrupt() { - if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen - return; - } - // We are making X overflows, as much as seconds (none on us). So wee compare upper than 1 - if (_overflows > 1) { - _overflows--; - } else { - _overflows = __overflows; - if (_type == UTIMERLIB_TYPE_TIMEOUT) { - clearTimer(); - } - _cb(); - } - } - - /** - * \brief Static envelope for Internal intermediate function to control timer interrupts - */ - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - void uTimerLib::interrupt(HardwareTimer *ignored) { - _instance->_interrupt(); - } - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #else - void uTimerLib::interrupt() { - _instance->_interrupt(); - } - #endif - - - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.STM32.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +#if (defined(_VARIANT_ARDUINO_STM32_) || defined(ARDUINO_ARCH_STM32)) && defined(UTIMERLIB_HW_COMPILE) +#ifndef _uTimerLib_IMP_ + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { + if (us == 0) { // Not valid + return; + } + + // STM32, all variants - Max us is: uint32 max / CYCLES_PER_MICROSECOND + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + Timer3->setMode(1, TIMER_OUTPUT_COMPARE); + __overflows = _overflows = __remaining = _remaining = 0; + Timer3->setOverflow(us, MICROSEC_FORMAT); + Timer3->setCaptureCompare(1, us, MICROSEC_COMPARE_FORMAT); + if (_toInit) { + _toInit = false; + Timer3->attachInterrupt((uint32_t) 1, uTimerLib::interrupt); + } + Timer3->resume(); + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #else + Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); + __overflows = _overflows = __remaining = _remaining = 0; + uint16_t timerOverflow = Timer3.setPeriod(us); + Timer3.setCompare(TIMER_CH1, timerOverflow); + if (_toInit) { + _toInit = false; + Timer3.attachInterrupt(TIMER_CH1, uTimerLib::interrupt); + } + Timer3.refresh(); + Timer3.resume(); + #endif + } + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired s seconds + * + * Note: This is device-dependant + * + * @param s Desired timing in seconds + */ + void uTimerLib::_attachInterrupt_s(unsigned long int s) { + if (s == 0) { // Not valid + return; + } + + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + Timer3->setMode(1, TIMER_OUTPUT_COMPARE); + __overflows = _overflows = s; + __remaining = _remaining = 0; + Timer3->setOverflow((unsigned long int) 1000000, MICROSEC_FORMAT); + Timer3->setCaptureCompare(1, (unsigned long int) 1000000, MICROSEC_COMPARE_FORMAT); + if (_toInit) { + _toInit = false; + Timer3->attachInterrupt((uint32_t) 1, uTimerLib::interrupt); + } + Timer3->resume(); + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #else + Timer3.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); + Timer3.setPeriod((uint32) 1000000); + Timer3.setCompare(TIMER_CH1, 0); + Timer3.setCount(1); + __overflows = _overflows = s; + __remaining = _remaining = 0; + if (_toInit) { + _toInit = false; + Timer3.attachInterrupt(TIMER_CH1, uTimerLib::interrupt); + } + Timer3.refresh(); + Timer3.resume(); + #endif + } + + + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void uTimerLib::_loadRemaining() { } + + /** + * \brief Clear timer interrupts + * + * Note: This is device-dependant + */ + void uTimerLib::clearTimer() { + _type = UTIMERLIB_TYPE_OFF; + + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + Timer3->pause(); + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #else + Timer3.pause(); + #endif + } + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + void uTimerLib::_interrupt() { + if (_type == UTIMERLIB_TYPE_OFF) { // Should not happen + return; + } + // We are making X overflows, as much as seconds (none on us). So wee compare upper than 1 + if (_overflows > 1) { + _overflows--; + } else { + _overflows = __overflows; + if (_type == UTIMERLIB_TYPE_TIMEOUT) { + clearTimer(); + } + _cb(); + } + } + + /** + * \brief Static envelope for Internal intermediate function to control timer interrupts + */ + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + callback_function_t uTimerLib::interrupt() { + _instance->_interrupt(); + } + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #else + void uTimerLib::interrupt() { + _instance->_interrupt(); + } + #endif + + + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + +#endif +#endif diff --git a/src/hardware/uTimerLib.UNSUPPORTED.cpp b/src/hardware/uTimerLib.UNSUPPORTED.cpp index d16611b..c44dcf0 100644 --- a/src/hardware/uTimerLib.UNSUPPORTED.cpp +++ b/src/hardware/uTimerLib.UNSUPPORTED.cpp @@ -1,90 +1,90 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file hardware/uTimerLib.STM32.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -#if !defined(__AVR_ATmega32U4__) && !defined(ARDUINO_ARCH_AVR) && !defined(_VARIANT_ARDUINO_STM32_) && !defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_SAM) && !defined(_SAMD21_) && !defined(__SAMD51__) && !defined(ARDUINO_attiny) -#ifndef _uTimerLib_IMP_ - #define _uTimerLib_IMP_ - #include "uTimerLib.cpp" - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds - * - * Note: This is device-dependant - * - * @param us Desired timing in microseconds - */ - void uTimerLib::_attachInterrupt_us(unsigned long int us) { } - - - /** - * \brief Sets up the timer, calculation variables and interrupts for desired s seconds - * - * Note: This is device-dependant - * - * @param s Desired timing in seconds - */ - void uTimerLib::_attachInterrupt_s(unsigned long int s) { } - - - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void uTimerLib::_loadRemaining() { } - - /** - * \brief Clear timer interrupts - * - * Note: This is device-dependant - */ - void uTimerLib::clearTimer() { } - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - void uTimerLib::_interrupt() { - #pragma message "This board is unsupported. Please, report it on https://github.com/Naguissa/uTimerLib/issues" - } - - - /** - * \brief Preinstantiate Object - * - * Now you can use al functionality calling Timerlib.function - */ - uTimerLib TimerLib = uTimerLib(); - -#endif -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file hardware/uTimerLib.STM32.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +#if (!defined(__AVR_ATmega32U4__) && !defined(ARDUINO_ARCH_AVR) && !defined(_VARIANT_ARDUINO_STM32_) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_SAM) && !defined(_SAMD21_) && !defined(__SAMD51__) && !defined(ARDUINO_attiny) && !defined(ARDUINO_AVR_ATTINYX5) && defined(UTIMERLIB_HW_COMPILE)) +#ifndef _uTimerLib_IMP_ + #define _uTimerLib_IMP_ + #include "uTimerLib.cpp" + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired ms microseconds + * + * Note: This is device-dependant + * + * @param us Desired timing in microseconds + */ + void uTimerLib::_attachInterrupt_us(unsigned long int us) { } + + + /** + * \brief Sets up the timer, calculation variables and interrupts for desired s seconds + * + * Note: This is device-dependant + * + * @param s Desired timing in seconds + */ + void uTimerLib::_attachInterrupt_s(unsigned long int s) { } + + + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void uTimerLib::_loadRemaining() { } + + /** + * \brief Clear timer interrupts + * + * Note: This is device-dependant + */ + void uTimerLib::clearTimer() { } + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + void uTimerLib::_interrupt() { + #pragma message "This board is unsupported. Please, report it on https://github.com/Naguissa/uTimerLib/issues" + } + + + /** + * \brief Preinstantiate Object + * + * Now you can use al functionality calling Timerlib.function + */ + uTimerLib TimerLib = uTimerLib(); + +#endif +#endif diff --git a/src/uTimerLib.cpp b/src/uTimerLib.cpp index 3db9084..ba59956 100644 --- a/src/uTimerLib.cpp +++ b/src/uTimerLib.cpp @@ -1,138 +1,142 @@ -/** - * \class uTimerLib - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @file uTimerLib.cpp - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ - -// # if !defined(_uTimerLib_cpp_) && defined(_uTimerLib_IMP_) -#ifndef _uTimerLib_cpp_ - #define _uTimerLib_cpp_ - #include "uTimerLib.h" - - // extern uTimerLib TimerLib; - - #ifdef _VARIANT_ARDUINO_STM32_ - uTimerLib *uTimerLib::_instance = NULL; - #endif - - /** - * \brief Constructor - */ - uTimerLib::uTimerLib() { - #ifdef _VARIANT_ARDUINO_STM32_ - _instance = this; - clearTimer(); - #endif - } - - /** - * \brief Attaches a callback function to be executed each us microseconds - * - * @param cb Callback function to be called - * @param us Interval in microseconds - */ - void uTimerLib::setInterval_us(void (* cb)(), unsigned long int us) { - clearTimer(); - _cb = cb; - _type = UTIMERLIB_TYPE_INTERVAL; - _attachInterrupt_us(us); - } - - - /** - * \brief Attaches a callback function to be executed once when us microseconds have passed - * - * @param cb Callback function to be called - * @param us Timeout in microseconds - */ - void uTimerLib::setTimeout_us(void (* cb)(), unsigned long int us) { - clearTimer(); - _cb = cb; - _type = UTIMERLIB_TYPE_TIMEOUT; - _attachInterrupt_us(us); - } - - - /** - * \brief Attaches a callback function to be executed each s seconds - * - * @param cb Callback function to be called - * @param s Interval in seconds - */ - void uTimerLib::setInterval_s(void (* cb)(), unsigned long int s) { - clearTimer(); - _cb = cb; - _type = UTIMERLIB_TYPE_INTERVAL; - _attachInterrupt_s(s); - } - - - /** - * \brief Attaches a callback function to be executed once when s seconds have passed - * - * @param cb Callback function to be called - * @param s Timeout in seconds - */ - void uTimerLib::setTimeout_s(void (* cb)(), unsigned long int s) { - clearTimer(); - _cb = cb; - _type = UTIMERLIB_TYPE_TIMEOUT; - _attachInterrupt_s(s); - } - - -#endif - -#if (defined(__AVR_ATmega32U4__) || defined(ARDUINO_ARCH_AVR)) && !defined(ARDUINO_attiny) && !defined(ARDUINO_AVR_ATTINYX4) && !defined(ARDUINO_AVR_ATTINYX5) && !defined(ARDUINO_AVR_ATTINYX7) && !defined(ARDUINO_AVR_ATTINYX8) && !defined(ARDUINO_AVR_ATTINYX61) && !defined(ARDUINO_AVR_ATTINY43) && !defined(ARDUINO_AVR_ATTINY828) && !defined(ARDUINO_AVR_ATTINY1634) && !defined(ARDUINO_AVR_ATTINYX313) - #include "hardware/uTimerLib.AVR.cpp" -#endif - -#if defined(ARDUINO_ARCH_AVR) && (defined(ARDUINO_attiny) ||defined(ARDUINO_AVR_ATTINYX5)) - #include "hardware/uTimerLib.ATTINY.cpp" -#endif - -#ifdef _VARIANT_ARDUINO_STM32_ - #include "hardware/uTimerLib.STM32.cpp" -#endif -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - #include "hardware/uTimerLib.ESP.cpp" -#endif -#ifdef ARDUINO_ARCH_SAM - #include "hardware/uTimerLib.SAM.cpp" -#endif -#ifdef _SAMD21_ - #include "hardware/uTimerLib.SAMD21.cpp" -#endif -#ifdef __SAMD51__ - #include "hardware/uTimerLib.SAMD51.cpp" -#endif - - -#if !defined(__AVR_ATmega32U4__) && !defined(ARDUINO_ARCH_AVR) && !defined(_VARIANT_ARDUINO_STM32_) && !defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_SAM) && !defined(_SAMD21_) && !defined(__SAMD51__) && !defined(ARDUINO_attiny) && !defined(ARDUINO_AVR_ATTINYX5) - #include "hardware/uTimerLib.UNSUPPORTED.cpp" -#endif +/** + * \class uTimerLib + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @file uTimerLib.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ + +// # if !defined(_uTimerLib_cpp_) && defined(_uTimerLib_IMP_) +#ifndef _uTimerLib_cpp_ + #define _uTimerLib_cpp_ + #include "uTimerLib.h" + + // extern uTimerLib TimerLib; + + #if defined(_VARIANT_ARDUINO_STM32_) || defined(ARDUINO_ARCH_STM32) + uTimerLib *uTimerLib::_instance = NULL; + #endif + + /** + * \brief Constructor + */ + uTimerLib::uTimerLib() { + #ifdef _VARIANT_ARDUINO_STM32_ + _instance = this; + clearTimer(); + #endif + } + + /** + * \brief Attaches a callback function to be executed each us microseconds + * + * @param cb Callback function to be called + * @param us Interval in microseconds + */ + void uTimerLib::setInterval_us(void (* cb)(), unsigned long int us) { + clearTimer(); + _cb = cb; + _type = UTIMERLIB_TYPE_INTERVAL; + _attachInterrupt_us(us); + } + + + /** + * \brief Attaches a callback function to be executed once when us microseconds have passed + * + * @param cb Callback function to be called + * @param us Timeout in microseconds + */ + void uTimerLib::setTimeout_us(void (* cb)(), unsigned long int us) { + clearTimer(); + _cb = cb; + _type = UTIMERLIB_TYPE_TIMEOUT; + _attachInterrupt_us(us); + } + + + /** + * \brief Attaches a callback function to be executed each s seconds + * + * @param cb Callback function to be called + * @param s Interval in seconds + */ + void uTimerLib::setInterval_s(void (* cb)(), unsigned long int s) { + clearTimer(); + _cb = cb; + _type = UTIMERLIB_TYPE_INTERVAL; + _attachInterrupt_s(s); + } + + + /** + * \brief Attaches a callback function to be executed once when s seconds have passed + * + * @param cb Callback function to be called + * @param s Timeout in seconds + */ + void uTimerLib::setTimeout_s(void (* cb)(), unsigned long int s) { + clearTimer(); + _cb = cb; + _type = UTIMERLIB_TYPE_TIMEOUT; + _attachInterrupt_s(s); + } + + #define UTIMERLIB_HW_COMPILE + + // Now load each hardware variation support: + + #if (defined(__AVR_ATmega32U4__) || defined(ARDUINO_ARCH_AVR)) && !defined(ARDUINO_attiny) && !defined(ARDUINO_AVR_ATTINYX4) && !defined(ARDUINO_AVR_ATTINYX5) && !defined(ARDUINO_AVR_ATTINYX7) && !defined(ARDUINO_AVR_ATTINYX8) && !defined(ARDUINO_AVR_ATTINYX61) && !defined(ARDUINO_AVR_ATTINY43) && !defined(ARDUINO_AVR_ATTINY828) && !defined(ARDUINO_AVR_ATTINY1634) && !defined(ARDUINO_AVR_ATTINYX313) + #include "hardware/uTimerLib.AVR.cpp" + #endif + + #if defined(ARDUINO_ARCH_AVR) && (defined(ARDUINO_attiny) ||defined(ARDUINO_AVR_ATTINYX5)) + #include "hardware/uTimerLib.ATTINY.cpp" + #endif + + #if defined(_VARIANT_ARDUINO_STM32_) || defined(ARDUINO_ARCH_STM32) + #include "hardware/uTimerLib.STM32.cpp" + #endif + + #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + #include "hardware/uTimerLib.ESP.cpp" + #endif + #ifdef ARDUINO_ARCH_SAM + #include "hardware/uTimerLib.SAM.cpp" + #endif + #ifdef _SAMD21_ + #include "hardware/uTimerLib.SAMD21.cpp" + #endif + #ifdef __SAMD51__ + #include "hardware/uTimerLib.SAMD51.cpp" + #endif + + + #if !defined(__AVR_ATmega32U4__) && !defined(ARDUINO_ARCH_AVR) && !defined(_VARIANT_ARDUINO_STM32_) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_ESP8266) && !defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_SAM) && !defined(_SAMD21_) && !defined(__SAMD51__) && !defined(ARDUINO_attiny) && !defined(ARDUINO_AVR_ATTINYX5) + #include "hardware/uTimerLib.UNSUPPORTED.cpp" + #endif + +#endif diff --git a/src/uTimerLib.h b/src/uTimerLib.h index 964bcad..ea89795 100644 --- a/src/uTimerLib.h +++ b/src/uTimerLib.h @@ -1,158 +1,158 @@ -/** - * \mainpage - * \brief Arduino tiny and cross-device compatible timer library. - * - * Timers used by each microcontroller: - * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) - * * Atmel AVR 32U4: Timer3 (4rd timer) - * * Atmel AVR other: Timer2 (3rd timer) - * * STM32: Timer3 (3rd timer) - * * SAM (Due): TC3 (Timer1, channel 0) - * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) - * * ESP32: OS Timer, one slot of software timer. - * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf - * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf - * - * You have public TimerLib variable with following methods: - * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. - * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. - * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. - * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. - * * TimerLib.clearTimer();* : will clear any timed function if exists. - * - * @copyright Naguissa - * @author Naguissa - * @see https://github.com/Naguissa/uTimerLib - * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html - * @see naguissa@foroelectro.net - * @version 1.6.0 - */ -/** \file uTimerLib.h - * \brief uTimerLib header file - */ -#ifndef _uTimerLib_ - /** - * \brief Prevent multiple inclussion - */ - #define _uTimerLib_ - - #include "Arduino.h" - - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - #include //Ticker Library - #endif - // Operation modes - /** - * \brief Internal status - */ - #define UTIMERLIB_TYPE_OFF 0 - /** - * \brief Internal status - */ - #define UTIMERLIB_TYPE_TIMEOUT 1 - /** - * \brief Internal status - */ - #define UTIMERLIB_TYPE_INTERVAL 2 - - #ifdef _VARIANT_ARDUINO_STM32_ - #include "HardwareTimer.h" - - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - // Private member - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #else - extern HardwareTimer Timer3; - #endif - #endif - - class uTimerLib { - public: - uTimerLib(); - void setInterval_us(void (*) (), unsigned long int); - void setInterval_s(void (*) (), unsigned long int); - void setTimeout_us(void (*) (), unsigned long int); - void setTimeout_s(void (*) (), unsigned long int); - - /** - * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) - * - * Note: This is device-dependant - */ - void clearTimer(); - - /** - * \brief Internal intermediate function to control timer interrupts - * - * As timers doesn't give us enougth flexibility for large timings, - * this function implements oferflow control to offer user desired timings. - */ - void _interrupt(); - - #ifdef _VARIANT_ARDUINO_STM32_ - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - static void interrupt(HardwareTimer*); - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #else - static void interrupt(); - #endif - #endif - - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - #pragma message "ESP8266 / ESP32 can only reach a ms resolution so any us interrupt will be rounded to that" - static void interrupt(); - #endif - - #ifdef _SAMD21_ - TcCount16* _TC = (TcCount16*) TC3; - #endif - - #ifdef __SAMD51__ - #pragma message "SAMD51 support is still experimental" - #endif - - private: - static uTimerLib *_instance; - - unsigned long int _overflows = 0; - unsigned long int __overflows = 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; - - void _loadRemaining(); - - void _attachInterrupt_us(unsigned long int); - void _attachInterrupt_s(unsigned long int); - - #ifdef _VARIANT_ARDUINO_STM32_ - bool _toInit = true; - - // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 - #ifdef BOARD_NAME - HardwareTimer *Timer3 = new HardwareTimer(TIM3); - - // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 - #endif - - #endif - - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - Ticker _ticker; - #endif - }; - - extern uTimerLib TimerLib; - -#endif - +/** + * \mainpage + * \brief Arduino tiny and cross-device compatible timer library. + * + * Timers used by each microcontroller: + * * Atmel ATtiny X5: Timer1 (2nd timer) - https://github.com/damellis/attiny and https://github.com/SpenceKonde/ATTinyCore (25, 45 and 85) + * * Atmel AVR 32U4: Timer3 (4rd timer) + * * Atmel AVR other: Timer2 (3rd timer) + * * STM32: Timer3 (3rd timer) + * * SAM (Due): TC3 (Timer1, channel 0) + * * ESP8266: OS Timer, one slot of seven available (Software timer provided by Arduino because ESP8266 has only two hardware timers and one is needed by it normal operation) + * * ESP32: OS Timer, one slot of software timer. + * * SAMD21: Timer 4, CC0 (TC3). See http://ww1.microchip.com/downloads/en/DeviceDoc/40001882A.pdf + * * SAMD51: Timer 2 (TC1), 16 bits mode (See http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf + * + * You have public TimerLib variable with following methods: + * * TimerLib.setInterval_us(callback_function, microseconds);* : callback_function will be called each microseconds. + * * TimerLib.setInterval_s(callback_function, seconds);* : callback_function will be called each seconds. + * * TimerLib.setTimeout_us(callback_function, microseconds);* : callback_function will be called once when microseconds have passed. + * * TimerLib.setTimeout_s(callback_function, seconds);* : callback_function will be called once when seconds have passed. + * * TimerLib.clearTimer();* : will clear any timed function if exists. + * + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uTimerLib + * @see https://www.foroelectro.net/librerias-arduino-ide-f29/utimerlib-libreria-arduino-para-eventos-temporizad-t191.html + * @see naguissa@foroelectro.net + * @version 1.6.1 + */ +/** \file uTimerLib.h + * \brief uTimerLib header file + */ +#ifndef _uTimerLib_ + /** + * \brief Prevent multiple inclussion + */ + #define _uTimerLib_ + + #include "Arduino.h" + + #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + #include //Ticker Library + #endif + // Operation modes + /** + * \brief Internal status + */ + #define UTIMERLIB_TYPE_OFF 0 + /** + * \brief Internal status + */ + #define UTIMERLIB_TYPE_TIMEOUT 1 + /** + * \brief Internal status + */ + #define UTIMERLIB_TYPE_INTERVAL 2 + + #ifdef _VARIANT_ARDUINO_STM32_ + #include "HardwareTimer.h" + + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + // Private member + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #else + extern HardwareTimer Timer3; + #endif + #endif + + class uTimerLib { + public: + uTimerLib(); + void setInterval_us(void (*) (), unsigned long int); + void setInterval_s(void (*) (), unsigned long int); + void setTimeout_us(void (*) (), unsigned long int); + void setTimeout_s(void (*) (), unsigned long int); + + /** + * \brief Loads last bit of time needed to precisely count until desired time (non complete loop) + * + * Note: This is device-dependant + */ + void clearTimer(); + + /** + * \brief Internal intermediate function to control timer interrupts + * + * As timers doesn't give us enougth flexibility for large timings, + * this function implements oferflow control to offer user desired timings. + */ + void _interrupt(); + + #ifdef _VARIANT_ARDUINO_STM32_ + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + static callback_function_t interrupt(); + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #else + static void interrupt(); + #endif + #endif + + #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + #pragma message "ESP8266 / ESP32 can only reach a ms resolution so any us interrupt will be rounded to that" + static void interrupt(); + #endif + + #ifdef _SAMD21_ + TcCount16* _TC = (TcCount16*) TC3; + #endif + + #ifdef __SAMD51__ + #pragma message "SAMD51 support is still experimental" + #endif + + private: + static uTimerLib *_instance; + + unsigned long int _overflows = 0; + unsigned long int __overflows = 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; + + void _loadRemaining(); + + void _attachInterrupt_us(unsigned long int); + void _attachInterrupt_s(unsigned long int); + + #ifdef _VARIANT_ARDUINO_STM32_ + bool _toInit = true; + + // ST's Arduino Core STM32, https://github.com/stm32duino/Arduino_Core_STM32 + #ifdef BOARD_NAME + HardwareTimer *Timer3 = new HardwareTimer(TIM3); + + // Roger Clark Arduino STM32, https://github.com/rogerclarkmelbourne/Arduino_STM32 + #endif + + #endif + + #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + Ticker _ticker; + #endif + }; + + extern uTimerLib TimerLib; + +#endif +