mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-26 17:46:14 +01:00
Embed ArduinoTimers library
Makes it so much easier for novice users as the ArduinoTimers libraray is not yet available from the IDE Library Manager.
This commit is contained in:
parent
d3b486a071
commit
6a986d2b0c
194
ATMEGA2560/Timer.h
Normal file
194
ATMEGA2560/Timer.h
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
#ifndef ATMEGA2560Timer_h
|
||||||
|
#define ATMEGA2560Timer_h
|
||||||
|
|
||||||
|
#include "../VirtualTimer.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
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
|
208
ATMEGA328/Timer.h
Normal file
208
ATMEGA328/Timer.h
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
#ifndef ATMEGA328Timer_h
|
||||||
|
#define ATMEGA328Timer_h
|
||||||
|
|
||||||
|
#include "../VirtualTimer.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
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
|
131
ATMEGA4809/Timer.h
Normal file
131
ATMEGA4809/Timer.h
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#ifndef ATMEGA328Timer_h
|
||||||
|
#define ATMEGA328Timer_h
|
||||||
|
|
||||||
|
#include "../VirtualTimer.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// 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
|
129
ATSAMC21G/Timer.h
Normal file
129
ATSAMC21G/Timer.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#ifndef ATSAMC21Timer_h
|
||||||
|
#define ATSAMC21Timer_h
|
||||||
|
|
||||||
|
#include "../VirtualTimer.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
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
|
144
ATSAMD21G/Timer.h
Normal file
144
ATSAMD21G/Timer.h
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
#ifndef ATSAMD21GTimer_h
|
||||||
|
#define ATSAMD21GTimer_h
|
||||||
|
|
||||||
|
#include "../VirtualTimer.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
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
|
24
ArduinoTimers.h
Normal file
24
ArduinoTimers.h
Normal file
|
@ -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
|
|
@ -21,7 +21,7 @@
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
#include "MotorDriver.h"
|
#include "MotorDriver.h"
|
||||||
#include <ArduinoTimers.h> // use IDE menu Tools..Manage Libraries to locate and install TimerOne
|
#include "ArduinoTimers.h"
|
||||||
|
|
||||||
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
DCCWaveform DCCWaveform::mainTrack(PREAMBLE_BITS_MAIN, true);
|
||||||
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
||||||
|
|
94
Timer.cpp
Normal file
94
Timer.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// This file is copied from https://github.com/davidcutting42/ArduinoTimers
|
||||||
|
// All Credit to David Cutting
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#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
|
21
VirtualTimer.h
Normal file
21
VirtualTimer.h
Normal file
|
@ -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
|
Loading…
Reference in New Issue
Block a user