From 6a986d2b0c25c43ecd156f32bd8db929e2dee1c0 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Sun, 23 Aug 2020 14:14:04 +0100 Subject: [PATCH] Embed ArduinoTimers library Makes it so much easier for novice users as the ArduinoTimers libraray is not yet available from the IDE Library Manager. --- ATMEGA2560/Timer.h | 194 ++++++++++++++++++++++++++++++++++++++++++ ATMEGA328/Timer.h | 208 +++++++++++++++++++++++++++++++++++++++++++++ ATMEGA4809/Timer.h | 131 ++++++++++++++++++++++++++++ ATSAMC21G/Timer.h | 129 ++++++++++++++++++++++++++++ ATSAMD21G/Timer.h | 144 +++++++++++++++++++++++++++++++ ArduinoTimers.h | 24 ++++++ DCCWaveform.cpp | 2 +- Timer.cpp | 94 ++++++++++++++++++++ VirtualTimer.h | 21 +++++ 9 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 ATMEGA2560/Timer.h create mode 100644 ATMEGA328/Timer.h create mode 100644 ATMEGA4809/Timer.h create mode 100644 ATSAMC21G/Timer.h create mode 100644 ATSAMD21G/Timer.h create mode 100644 ArduinoTimers.h create mode 100644 Timer.cpp create mode 100644 VirtualTimer.h diff --git a/ATMEGA2560/Timer.h b/ATMEGA2560/Timer.h new file mode 100644 index 0000000..2568c9e --- /dev/null +++ b/ATMEGA2560/Timer.h @@ -0,0 +1,194 @@ +#ifndef ATMEGA2560Timer_h +#define ATMEGA2560Timer_h + +#include "../VirtualTimer.h" +#include + +class Timer : public VirtualTimer { +private: + int pwmPeriod; + unsigned long timer_resolution; + unsigned char clockSelectBits; + int timer_num; + unsigned long lastMicroseconds; +public: +void (*isrCallback)(); + Timer(int timer_num) { + switch (timer_num) + { + case 1: + case 3: + case 4: + case 5: + timer_resolution = 65536; + break; + } + this->timer_num = timer_num; + lastMicroseconds = 0; + } + + void initialize() { + switch (timer_num) + { + case 1: + TCCR1B = _BV(WGM13) | _BV(WGM12); + TCCR1A = _BV(WGM11); + break; + case 3: + TCCR3B = _BV(WGM33) | _BV(WGM32); + TCCR3A = _BV(WGM31); + break; + case 4: + TCCR4B = _BV(WGM43) | _BV(WGM42); + TCCR4A = _BV(WGM41); + break; + case 5: + TCCR5B = _BV(WGM53) | _BV(WGM52); + TCCR5A = _BV(WGM51); + break; + } + } + + void setPeriod(unsigned long microseconds) { + if(microseconds == lastMicroseconds) + return; + lastMicroseconds = microseconds; + const unsigned long cycles = (F_CPU / 1000000) * microseconds; + if (cycles < timer_resolution) { + clockSelectBits = 1 << 0; + pwmPeriod = cycles; + } else + if (cycles < timer_resolution * 8) { + clockSelectBits = 1 << 1; + pwmPeriod = cycles / 8; + } else + if (cycles < timer_resolution * 64) { + clockSelectBits = (1 << 0) | (1 << 1); + pwmPeriod = cycles / 64; + } else + if (cycles < timer_resolution * 256) { + clockSelectBits = 1 << 2; + pwmPeriod = cycles / 256; + } else + if (cycles < timer_resolution * 1024) { + clockSelectBits = (1 << 2) | (1 << 0); + pwmPeriod = cycles / 1024; + } else { + clockSelectBits = (1 << 2) | (1 << 0); + pwmPeriod = timer_resolution - 1; + } + + switch (timer_num) + { + case 1: + ICR1 = pwmPeriod; + TCCR1B = _BV(WGM13) | _BV(WGM12) | clockSelectBits; + break; + case 3: + ICR3 = pwmPeriod; + TCCR3B = _BV(WGM33) | _BV(WGM32) | clockSelectBits; + break; + case 4: + ICR4 = pwmPeriod; + TCCR4B = _BV(WGM43) | _BV(WGM42) | clockSelectBits; + break; + case 5: + ICR5 = pwmPeriod; + TCCR5B = _BV(WGM53) | _BV(WGM52) | clockSelectBits; + break; + } + + } + void start() { + switch (timer_num) + { + case 1: + TCCR1B = 0; + TCNT1 = 0; // TODO: does this cause an undesired interrupt? + TCCR1B = _BV(WGM13) | _BV(WGM12) | clockSelectBits; + break; + case 3: + TCCR3B = 0; + TCNT3 = 0; // TODO: does this cause an undesired interrupt? + TCCR3B = _BV(WGM33) | _BV(WGM32) | clockSelectBits; + break; + case 4: + TCCR4B = 0; + TCNT4 = 0; // TODO: does this cause an undesired interrupt? + TCCR4B = _BV(WGM43) | _BV(WGM42) | clockSelectBits; + break; + case 5: + TCCR5B = 0; + TCNT5 = 0; // TODO: does this cause an undesired interrupt? + TCCR5B = _BV(WGM53) | _BV(WGM52) | clockSelectBits; + break; + } + + + } + void stop() { + switch (timer_num) + { + case 1: + TCCR1B = _BV(WGM13) | _BV(WGM12); + break; + case 3: + TCCR3B = _BV(WGM33) | _BV(WGM32); + break; + case 4: + TCCR4B = _BV(WGM43) | _BV(WGM42); + break; + case 5: + TCCR5B = _BV(WGM53) | _BV(WGM52); + break; + } + } + + void attachInterrupt(void (*isr)()) { + isrCallback = isr; + + switch (timer_num) + { + case 1: + TIMSK1 = _BV(TOIE1); + break; + case 3: + TIMSK3 = _BV(TOIE3); + break; + case 4: + TIMSK4 = _BV(TOIE4); + break; + case 5: + TIMSK5 = _BV(TOIE5); + break; + } + } + + void detachInterrupt() { + switch (timer_num) + { + case 1: + TIMSK1 = 0; + break; + case 3: + TIMSK3 = 0; + break; + case 4: + TIMSK4 = 0; + break; + case 5: + TIMSK5 = 0; + break; + } + } + +}; + +extern Timer TimerA; +extern Timer TimerB; +extern Timer TimerC; +extern Timer TimerD; + + + +#endif \ No newline at end of file diff --git a/ATMEGA328/Timer.h b/ATMEGA328/Timer.h new file mode 100644 index 0000000..6204953 --- /dev/null +++ b/ATMEGA328/Timer.h @@ -0,0 +1,208 @@ +#ifndef ATMEGA328Timer_h +#define ATMEGA328Timer_h + +#include "../VirtualTimer.h" +#include + +class Timer : public VirtualTimer { +private: + int pwmPeriod; + unsigned long timer_resolution; + unsigned char clockSelectBits; + int timer_num; + unsigned long lastMicroseconds; +public: +void (*isrCallback)(); + Timer(int timer_num) { + switch (timer_num) + { + //case 0: + case 2: + timer_resolution = 256; + break; + case 1: + timer_resolution = 65536; + break; + } + this->timer_num = timer_num; + lastMicroseconds = 0; + } + + void initialize() { + switch (timer_num) + { + // case 0: + // TCCR0B = _BV(WGM02); + // TCCR0A = _BV(WGM00) | _BV(WGM01); + // break; + case 1: + TCCR1B = _BV(WGM13) | _BV(WGM12); + TCCR1A = _BV(WGM11); + break; + case 2: + TCCR2B = _BV(WGM22); + TCCR2A = _BV(WGM20) | _BV(WGM21); + break; + } + } + + void setPeriod(unsigned long microseconds) { + if(microseconds == lastMicroseconds) + return; + lastMicroseconds = microseconds; + const unsigned long cycles = (F_CPU / 1000000) * microseconds; + + switch(timer_num) { + case 2: + if (cycles < timer_resolution) { + clockSelectBits = 1 << 0; + pwmPeriod = cycles; + } else + if (cycles < timer_resolution * 8) { + clockSelectBits = 1 << 1; + pwmPeriod = cycles / 8; + } else + if (cycles < timer_resolution * 32) { + clockSelectBits = 1 << 0 | 1 << 1; + pwmPeriod = cycles / 32; + } else + if (cycles < timer_resolution * 64) { + clockSelectBits = 1 << 2; + pwmPeriod = cycles / 64; + } else + if (cycles < timer_resolution * 128) { + clockSelectBits = 1 << 2 | 1 << 0; + pwmPeriod = cycles / 128; + } else + if (cycles < timer_resolution * 256) { + clockSelectBits = 1 << 2 | 1 << 1; + pwmPeriod = cycles / 256; + } else + if (cycles < timer_resolution * 1024) { + clockSelectBits = 1 << 2 | 1 << 1 | 1 << 0; + pwmPeriod = cycles / 1024; + } else { + clockSelectBits = 1 << 2 | 1 << 1 | 1 << 0; + pwmPeriod = timer_resolution - 1; + } + break; + //case 0: + case 1: + if (cycles < timer_resolution) { + clockSelectBits = 1 << 0; + pwmPeriod = cycles; + } else + if (cycles < timer_resolution * 8) { + clockSelectBits = 1 << 1; + pwmPeriod = cycles / 8; + } else + if (cycles < timer_resolution * 64) { + clockSelectBits = (1 << 0) | (1 << 1); + pwmPeriod = cycles / 64; + } else + if (cycles < timer_resolution * 256) { + clockSelectBits = 1 << 2; + pwmPeriod = cycles / 256; + } else + if (cycles < timer_resolution * 1024) { + clockSelectBits = (1 << 2) | (1 << 0); + pwmPeriod = cycles / 1024; + } else { + clockSelectBits = (1 << 2) | (1 << 0); + pwmPeriod = timer_resolution - 1; + } + break; + } + + switch (timer_num) + { + // case 0: + // OCR0A = pwmPeriod; + // TCCR0B = _BV(WGM02) | clockSelectBits; + // break; + case 1: + ICR1 = pwmPeriod; + TCCR1B = _BV(WGM13) | _BV(WGM12) | clockSelectBits; + break; + case 2: + OCR2A = pwmPeriod; + TCCR2B = _BV(WGM22) | clockSelectBits; + break; + } + + } + void start() { + switch (timer_num) + { + // case 0: + // TCCR0B = 0; + // TCNT0 = 0; // TODO: does this cause an undesired interrupt? + // TCCR0B = _BV(WGM02) | clockSelectBits; + // break; + case 1: + TCCR1B = 0; + TCNT1 = 0; // TODO: does this cause an undesired interrupt? + TCCR1B = _BV(WGM13) | _BV(WGM12) | clockSelectBits; + break; + case 2: + TCCR2B = 0; + TCNT2 = 0; // TODO: does this cause an undesired interrupt? + TCCR2B = _BV(WGM22) | clockSelectBits; + break; + } + + + } + void stop() { + switch (timer_num) + { + // case 0: + // TCCR0B = _BV(WGM02); + // break; + case 1: + TCCR1B = _BV(WGM13) | _BV(WGM12); + break; + case 2: + TCCR2B = _BV(WGM22); + break; + } + } + + void attachInterrupt(void (*isr)()) { + isrCallback = isr; + + switch (timer_num) + { + // case 0: + // TIMSK0 = _BV(TOIE0); + // break; + case 1: + TIMSK1 = _BV(TOIE1); + break; + case 2: + TIMSK2 = _BV(TOIE2); + break; + } + } + + void detachInterrupt() { + switch (timer_num) + { + // case 0: + // TIMSK0 = 0; + // break; + case 1: + TIMSK1 = 0; + break; + case 2: + TIMSK2 = 0; + break; + } + } + +}; + +extern Timer TimerA; +extern Timer TimerB; + +#endif \ No newline at end of file diff --git a/ATMEGA4809/Timer.h b/ATMEGA4809/Timer.h new file mode 100644 index 0000000..1690ad5 --- /dev/null +++ b/ATMEGA4809/Timer.h @@ -0,0 +1,131 @@ +#ifndef ATMEGA328Timer_h +#define ATMEGA328Timer_h + +#include "../VirtualTimer.h" +#include + +// We only define behavior for timer 0 (TCA0), because TCB0 is very limited in functionality. + +class Timer : public VirtualTimer { +private: + int pwmPeriod; + unsigned long timer_resolution; + unsigned char clockSelectBits; + int timer_num; + unsigned long lastMicroseconds; +public: + void (*isrCallback)(); + Timer(int timer_num) { + switch (timer_num) + { + case 0: + timer_resolution = 65536; + break; + } + this->timer_num = timer_num; + lastMicroseconds = 0; + } + + void initialize() { + switch (timer_num) + { + case 0: + break; + } + } + + void setPeriod(unsigned long microseconds) { + if(microseconds == lastMicroseconds) + return; + lastMicroseconds = microseconds; + const unsigned long cycles = (F_CPU / 1000000) * microseconds; + + switch(timer_num) { + case 0: + if (cycles < timer_resolution) { + clockSelectBits = 0x0; + pwmPeriod = cycles; + } else + if (cycles < timer_resolution * 2) { + clockSelectBits = 0x1; + pwmPeriod = cycles / 8; + } else + if (cycles < timer_resolution * 4) { + clockSelectBits = 0x2; + pwmPeriod = cycles / 32; + } else + if (cycles < timer_resolution * 8) { + clockSelectBits = 0x3; + pwmPeriod = cycles / 64; + } else + if (cycles < timer_resolution * 64) { + clockSelectBits = 0x5; + pwmPeriod = cycles / 128; + } else + if (cycles < timer_resolution * 256) { + clockSelectBits = 0x6; + pwmPeriod = cycles / 256; + } else + if (cycles < timer_resolution * 1024) { + clockSelectBits = 0x7; + pwmPeriod = cycles / 1024; + } else { + clockSelectBits = 0x7; + pwmPeriod = timer_resolution - 1; + } + break; + } + + switch (timer_num) + { + case 0: + TCA0.SINGLE.PER = pwmPeriod; + TCA0.SINGLE.CTRLA = clockSelectBits << 1; + break; + } + } + + void start() { + switch (timer_num) + { + case 0: + bitSet(TCA0.SINGLE.CTRLA, 0); + break; + } + + + } + void stop() { + switch (timer_num) + { + case 0: + bitClear(TCA0.SINGLE.CTRLA, 0); + break; + } + } + + void attachInterrupt(void (*isr)()) { + isrCallback = isr; + + switch (timer_num) + { + case 0: + TCA0.SINGLE.INTCTRL = 0x1; + break; + } + } + + void detachInterrupt() { + switch (timer_num) + { + case 0: + TCA0.SINGLE.INTCTRL = 0x0; + break; + } + } + +}; + +extern Timer TimerA; + +#endif \ No newline at end of file diff --git a/ATSAMC21G/Timer.h b/ATSAMC21G/Timer.h new file mode 100644 index 0000000..40ef453 --- /dev/null +++ b/ATSAMC21G/Timer.h @@ -0,0 +1,129 @@ +#ifndef ATSAMC21Timer_h +#define ATSAMC21Timer_h + +#include "../VirtualTimer.h" +#include + +class Timer : public VirtualTimer +{ +private: + int pwmPeriod; + unsigned long timer_resolution; + unsigned long lastMicroseconds; +public: + void (*isrCallback)(); + Tcc* timer; + + Timer(Tcc* timer) { + this->timer = timer; + if(timer == TCC0 || timer == TCC1) { + timer_resolution = 16777216; + } else { + timer_resolution = 65536; + } + lastMicroseconds = 0; + } + + void initialize() { + if(timer == TCC0 || timer == TCC1) { + MCLK->APBCMASK.bit.TCC0_ = 1; + MCLK->APBCMASK.bit.TCC1_ = 1; + GCLK->GENCTRL[4].reg = ( GCLK_GENCTRL_DIV(2) | GCLK_GENCTRL_SRC_DPLL96M | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_OE ); + while ((GCLK->SYNCBUSY.bit.GENCTRL >> 4) & 1); // Wait for synchronization + GCLK->PCHCTRL[28].reg = ( GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(4) ); // 28 = TCC0_TCC1 + while ((GCLK->SYNCBUSY.bit.GENCTRL >> 4) & 1); // Wait for synchronization + } + else if (timer == TCC2) { + MCLK->APBCMASK.bit.TCC2_ = 1; + GCLK->GENCTRL[5].reg = ( GCLK_GENCTRL_DIV(2) | GCLK_GENCTRL_SRC_DPLL96M | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_OE ); + while ((GCLK->SYNCBUSY.bit.GENCTRL >> 5) & 1); // Wait for synchronization + GCLK->PCHCTRL[29].reg = ( GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(5) ); // 29 = TCC2 + while ((GCLK->SYNCBUSY.bit.GENCTRL >> 5) & 1); // Wait for synchronization + } + + timer->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform + while (timer->SYNCBUSY.bit.WAVE); // Wait for synchronization + + } + void setPeriod(unsigned long microseconds) { + if(microseconds == lastMicroseconds) + return; + lastMicroseconds = microseconds; + + const unsigned long cycles = F_CPU / 1000000 * microseconds; // cycles corresponds to how many clock ticks per microsecond times number of microseconds we want + timer->CTRLA.bit.PRESCALER = 0; + if(cycles < timer_resolution) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val); + pwmPeriod = cycles; + } else + if(cycles < timer_resolution * 2) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV2_Val); + pwmPeriod = cycles / 2; + } else + if(cycles < timer_resolution * 4) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV4_Val); + pwmPeriod = cycles / 4; + } else + if(cycles < timer_resolution * 8) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV8_Val); + pwmPeriod = cycles / 8; + } else + if(cycles < timer_resolution * 16) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV16_Val); + pwmPeriod = cycles / 16; + } else + if(cycles < timer_resolution * 64) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV64_Val); + pwmPeriod = cycles / 64; + } else + if(cycles < timer_resolution * 1024) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1024_Val); + pwmPeriod = cycles / 1024; + } + timer->PER.reg = pwmPeriod; + while (timer->SYNCBUSY.bit.PER); + } + void start() { + timer->CTRLA.bit.ENABLE = 1; // Turn on the output + while (timer->SYNCBUSY.bit.ENABLE); // Wait for synchronization + } + void stop() { + timer->CTRLA.bit.ENABLE = 0; // Turn on the output + while (timer->SYNCBUSY.bit.ENABLE); // Wait for synchronization + } + + void attachInterrupt(void (*isr)()) { + isrCallback = isr; // Store the interrupt callback function + timer->INTENSET.reg = TCC_INTENSET_OVF; // Set the interrupt to occur on overflow + + if(timer == TCC0) { + NVIC_EnableIRQ((IRQn_Type) TCC0_IRQn); // Enable the interrupt (clock is still off) + } + else if(timer == TCC1) { + NVIC_EnableIRQ((IRQn_Type) TCC1_IRQn); // Enable the interrupt (clock is still off) + } + else if(timer == TCC2) { + NVIC_EnableIRQ((IRQn_Type) TCC2_IRQn); // Enable the interrupt (clock is still off) + } + } + + void detachInterrupt() { + if(timer == TCC0) { + NVIC_DisableIRQ((IRQn_Type) TCC0_IRQn); // Disable the interrupt + } + else if(timer == TCC1) { + NVIC_DisableIRQ((IRQn_Type) TCC1_IRQn); // Disable the interrupt + } + else if(timer == TCC2) { + NVIC_DisableIRQ((IRQn_Type) TCC2_IRQn); // Disable the interrupt + } + } +}; + +extern Timer TimerA; +extern Timer TimerB; +extern Timer TimerC; + + + +#endif // ATSAMC21Timer_h diff --git a/ATSAMD21G/Timer.h b/ATSAMD21G/Timer.h new file mode 100644 index 0000000..19e7dee --- /dev/null +++ b/ATSAMD21G/Timer.h @@ -0,0 +1,144 @@ +#ifndef ATSAMD21GTimer_h +#define ATSAMD21GTimer_h + +#include "../VirtualTimer.h" +#include + +class Timer : public VirtualTimer +{ +private: + int pwmPeriod; + unsigned long timer_resolution; + unsigned long lastMicroseconds; +public: + void (*isrCallback)(); + Tcc* timer; + + Timer(Tcc* timer) { + this->timer = timer; + if(timer == TCC0 || timer == TCC1) { + timer_resolution = 16777216; + } else { + timer_resolution = 65536; + } + lastMicroseconds = 0; + } + + void initialize() { + if(timer == TCC0 || timer == TCC1) { + REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 + GCLK_GENDIV_ID(4); // Apply to GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_GENCTRL = GCLK_GENCTRL_GENEN | // Enable GCLK + GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source + GCLK_GENCTRL_ID(4); // Select GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable generic clock + 4 << GCLK_CLKCTRL_GEN_Pos | // Apply to GCLK4 + GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + } + else if (timer == TCC2) { + REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 + GCLK_GENDIV_ID(5); // Apply to GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_GENCTRL = GCLK_GENCTRL_GENEN | // Enable GCLK + GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source + GCLK_GENCTRL_ID(5); // Select GCLK4 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + + REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable generic clock + 5 << GCLK_CLKCTRL_GEN_Pos | // Apply to GCLK4 + GCLK_CLKCTRL_ID_TCC2_TC3; // Feed GCLK to TCC0/1 + while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization + } + + + timer->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform + while (timer->SYNCBUSY.bit.WAVE); // Wait for synchronization + + } + void setPeriod(unsigned long microseconds) { + if(microseconds == lastMicroseconds) + return; + lastMicroseconds = microseconds; + + const unsigned long cycles = F_CPU / 1000000 * microseconds; // cycles corresponds to how many clock ticks per microsecond times number of microseconds we want + if(cycles < timer_resolution) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val); + pwmPeriod = cycles; + } else + if(cycles < timer_resolution * 2) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV2_Val); + pwmPeriod = cycles / 2; + } else + if(cycles < timer_resolution * 4) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV4_Val); + pwmPeriod = cycles / 4; + } else + if(cycles < timer_resolution * 8) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV8_Val); + pwmPeriod = cycles / 8; + } else + if(cycles < timer_resolution * 16) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV16_Val); + pwmPeriod = cycles / 16; + } else + if(cycles < timer_resolution * 64) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV64_Val); + pwmPeriod = cycles / 64; + } else + if(cycles < timer_resolution * 1024) { + timer->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1024_Val); + pwmPeriod = cycles / 1024; + } + timer->PER.reg = pwmPeriod; + while (timer->SYNCBUSY.bit.PER); + } + void start() { + timer->CTRLA.bit.ENABLE = 1; // Turn on the output + while (timer->SYNCBUSY.bit.ENABLE); // Wait for synchronization + } + void stop() { + timer->CTRLA.bit.ENABLE = 0; // Turn on the output + while (timer->SYNCBUSY.bit.ENABLE); // Wait for synchronization + } + + void attachInterrupt(void (*isr)()) { + isrCallback = isr; // Store the interrupt callback function + timer->INTENSET.reg = TCC_INTENSET_OVF; // Set the interrupt to occur on overflow + + if(timer == TCC0) { + NVIC_EnableIRQ((IRQn_Type) TCC0_IRQn); // Enable the interrupt (clock is still off) + } + else if(timer == TCC1) { + NVIC_EnableIRQ((IRQn_Type) TCC1_IRQn); // Enable the interrupt (clock is still off) + } + else if(timer == TCC2) { + NVIC_EnableIRQ((IRQn_Type) TCC2_IRQn); // Enable the interrupt (clock is still off) + } + } + + void detachInterrupt() { + if(timer == TCC0) { + NVIC_DisableIRQ((IRQn_Type) TCC0_IRQn); // Disable the interrupt + } + else if(timer == TCC1) { + NVIC_DisableIRQ((IRQn_Type) TCC1_IRQn); // Disable the interrupt + } + else if(timer == TCC2) { + NVIC_DisableIRQ((IRQn_Type) TCC2_IRQn); // Disable the interrupt + } + } +}; + +extern Timer TimerA; +extern Timer TimerB; +extern Timer TimerC; + + + +#endif \ No newline at end of file diff --git a/ArduinoTimers.h b/ArduinoTimers.h new file mode 100644 index 0000000..ba0569c --- /dev/null +++ b/ArduinoTimers.h @@ -0,0 +1,24 @@ +// This file is copied from https://github.com/davidcutting42/ArduinoTimers +// All Credit and copyright David Cutting +// The files included below come from the same source. +// This library had been included with the DCC code to avoid issues with +// library management for inexperienced users. "It just works (TM)" + +#ifndef ArduinoTimers_h +#define ArduinoTimers_h + +#if defined(SAMC21) + #include "ATSAMC21G/Timer.h" +#elif defined(ARDUINO_SAMD_ZERO) + #include "ATSAMD21G/Timer.h" +#elif defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) + #include "ATMEGA2560/Timer.h" +#elif defined(ARDUINO_AVR_UNO) + #include "ATMEGA328/Timer.h" +#elif defined(ARDUINO_ARCH_MEGAAVR) + #include "ATMEGA4809/Timer.h" +#else + #error "Cannot compile - ArduinoTimers library does not support your board, or you are missing compatible build flags." +#endif + +#endif diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index bf0a1c6..f253014 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -21,7 +21,7 @@ #include "DCCWaveform.h" #include "DIAG.h" #include "MotorDriver.h" -#include // use IDE menu Tools..Manage Libraries to locate and install TimerOne +#include "ArduinoTimers.h" DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true); DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false); diff --git a/Timer.cpp b/Timer.cpp new file mode 100644 index 0000000..1430e9c --- /dev/null +++ b/Timer.cpp @@ -0,0 +1,94 @@ +// This file is copied from https://github.com/davidcutting42/ArduinoTimers +// All Credit to David Cutting + +#include + +#if defined(ARDUINO_SAMD_ZERO) + +#if defined(SAMC21) +#include "ATSAMC21G/Timer.h" +#else +#include "ATSAMD21G/Timer.h" +#endif + +Timer TimerA(TCC0); +Timer TimerB(TCC1); +Timer TimerC(TCC2); + +void TCC0_Handler() { + if(TCC0->INTFLAG.bit.OVF) { + TCC0->INTFLAG.bit.OVF = 1; + TimerA.isrCallback(); + } +} + +void TCC1_Handler() { + if(TCC1->INTFLAG.bit.OVF) { + TCC1->INTFLAG.bit.OVF = 1; + TimerB.isrCallback(); + } +} + +void TCC2_Handler() { + if(TCC2->INTFLAG.bit.OVF) { + TCC2->INTFLAG.bit.OVF = 1; + TimerC.isrCallback(); + } +} +#elif defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) + +#include "ATMEGA2560/Timer.h" + +Timer TimerA(1); +Timer TimerB(3); +Timer TimerC(4); +Timer TimerD(5); + +ISR(TIMER1_OVF_vect) +{ + TimerA.isrCallback(); +} + +ISR(TIMER3_OVF_vect) +{ + TimerB.isrCallback(); +} + +ISR(TIMER4_OVF_vect) +{ + TimerC.isrCallback(); +} + +ISR(TIMER5_OVF_vect) +{ + TimerD.isrCallback(); +} + +#elif defined(ARDUINO_AVR_UNO) // Todo: add other 328 boards for compatibility + +#include "ATMEGA328/Timer.h" + +Timer TimerA(1); +Timer TimerB(2); + +ISR(TIMER1_OVF_vect) +{ + TimerA.isrCallback(); +} + +ISR(TIMER2_OVF_vect) +{ + TimerB.isrCallback(); +} + +#elif defined(ARDUINO_ARCH_MEGAAVR) + +#include "ATMEGA4809/Timer.h" + +Timer TimerA(0); + +ISR(TCA0_OVF_vect) { + TimerA.isrCallback(); +} + +#endif diff --git a/VirtualTimer.h b/VirtualTimer.h new file mode 100644 index 0000000..5e3832f --- /dev/null +++ b/VirtualTimer.h @@ -0,0 +1,21 @@ +// This file is copied from https://github.com/davidcutting42/ArduinoTimers +// All Credit to David Cutting + +#ifndef VirtualTimer_h +#define VirtualTimer_h + +class VirtualTimer +{ +public: + virtual void initialize() = 0; + virtual void setPeriod(unsigned long microseconds) = 0; + virtual void start() = 0; + virtual void stop() = 0; + + virtual void attachInterrupt(void (*isr)()) = 0; + virtual void detachInterrupt() = 0; +private: + +}; + +#endif