mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2025-01-27 12:48:52 +01:00
Clean simple Timer interface
Removes overkill files, puts all timer in a single small file. (DCCTimer)
This commit is contained in:
parent
f646f12c65
commit
8a9feaef22
@ -1,194 +0,0 @@
|
|||||||
#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
|
|
@ -1,208 +0,0 @@
|
|||||||
#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
|
|
@ -1,18 +0,0 @@
|
|||||||
// 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(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
|
|
||||||
#include "ATMEGA2560/Timer.h"
|
|
||||||
#elif defined(ARDUINO_AVR_UNO)
|
|
||||||
#include "ATMEGA328/Timer.h"
|
|
||||||
#else
|
|
||||||
#error "Cannot compile - ArduinoTimers library does not support your board, or you are missing compatible build flags."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -49,9 +49,7 @@ void setup()
|
|||||||
|
|
||||||
// STANDARD_MOTOR_SHIELD, POLOLU_MOTOR_SHIELD, FIREBOX_MK1, FIREBOX_MK1S are pre defined in MotorShields.h
|
// STANDARD_MOTOR_SHIELD, POLOLU_MOTOR_SHIELD, FIREBOX_MK1, FIREBOX_MK1S are pre defined in MotorShields.h
|
||||||
|
|
||||||
// Optionally a Timer number (1..4) may be passed to DCC::begin to override the default Timer1 used for the
|
|
||||||
// waveform generation. e.g. DCC::begin(STANDARD_MOTOR_SHIELD,2); to use timer 2
|
|
||||||
|
|
||||||
DCC::begin(MOTOR_SHIELD_TYPE);
|
DCC::begin(MOTOR_SHIELD_TYPE);
|
||||||
|
|
||||||
#if defined(RMFT_ACTIVE)
|
#if defined(RMFT_ACTIVE)
|
||||||
|
5
DCC.cpp
5
DCC.cpp
@ -45,7 +45,7 @@ const byte FN_GROUP_5=0x10;
|
|||||||
|
|
||||||
__FlashStringHelper* DCC::shieldName=NULL;
|
__FlashStringHelper* DCC::shieldName=NULL;
|
||||||
|
|
||||||
void DCC::begin(const __FlashStringHelper* motorShieldName, MotorDriver * mainDriver, MotorDriver* progDriver, byte timerNumber) {
|
void DCC::begin(const __FlashStringHelper* motorShieldName, MotorDriver * mainDriver, MotorDriver* progDriver) {
|
||||||
shieldName=(__FlashStringHelper*)motorShieldName;
|
shieldName=(__FlashStringHelper*)motorShieldName;
|
||||||
DIAG(F("<iDCC-EX V-%S / %S / %S G-%S>\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA));
|
DIAG(F("<iDCC-EX V-%S / %S / %S G-%S>\n"), F(VERSION), F(ARDUINO_TYPE), shieldName, F(GITHUB_SHA));
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ void DCC::begin(const __FlashStringHelper* motorShieldName, MotorDriver * mainDr
|
|||||||
(void)EEPROM; // tell compiler not to warn this is unused
|
(void)EEPROM; // tell compiler not to warn this is unused
|
||||||
EEStore::init();
|
EEStore::init();
|
||||||
|
|
||||||
DCCWaveform::begin(mainDriver,progDriver, timerNumber);
|
DCCWaveform::begin(mainDriver,progDriver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCC::setThrottle( uint16_t cab, uint8_t tSpeed, bool tDirection) {
|
void DCC::setThrottle( uint16_t cab, uint8_t tSpeed, bool tDirection) {
|
||||||
@ -481,7 +481,6 @@ void DCC::getLocoId(ACK_CALLBACK callback, bool blocking) {
|
|||||||
|
|
||||||
void DCC::setLocoId(int id,ACK_CALLBACK callback, bool blocking) {
|
void DCC::setLocoId(int id,ACK_CALLBACK callback, bool blocking) {
|
||||||
if (id<=0 || id>9999) callback(-1);
|
if (id<=0 || id>9999) callback(-1);
|
||||||
int wordval;
|
|
||||||
if (id<=127) ackManagerSetup(id,SHORT_LOCO_ID_PROG, callback, blocking);
|
if (id<=127) ackManagerSetup(id,SHORT_LOCO_ID_PROG, callback, blocking);
|
||||||
else ackManagerSetup(id | 0xc000,LONG_LOCO_ID_PROG, callback, blocking);
|
else ackManagerSetup(id | 0xc000,LONG_LOCO_ID_PROG, callback, blocking);
|
||||||
}
|
}
|
||||||
|
2
DCC.h
2
DCC.h
@ -64,7 +64,7 @@ const byte MAX_LOCOS = 50;
|
|||||||
class DCC
|
class DCC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void begin(const __FlashStringHelper *motorShieldName, MotorDriver *mainDriver, MotorDriver *progDriver, byte timerNumber = 1);
|
static void begin(const __FlashStringHelper *motorShieldName, MotorDriver *mainDriver, MotorDriver *progDriver);
|
||||||
static void loop();
|
static void loop();
|
||||||
|
|
||||||
// Public DCC API functions
|
// Public DCC API functions
|
||||||
|
54
DCCTimer.cpp
Normal file
54
DCCTimer.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* © 2021, Chris Harlow & David Cutting. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Asbelos DCC API
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* It is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* This timer class is used to manage the single timer required to handle the DCC waveform.
|
||||||
|
* All timer access comes through this class so that it can be compiled for
|
||||||
|
* various hardware CPU types.
|
||||||
|
*
|
||||||
|
* DCCEX works on a single timer interrupt at a regular 58uS interval.
|
||||||
|
* The DCCWaveform class generates the signals to the motor shield
|
||||||
|
* based on this timer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DCCTimer.h"
|
||||||
|
|
||||||
|
const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
|
||||||
|
const int DCC_SLOW_TIME=58*512; // for <D DCC SLOW> command diagnostics
|
||||||
|
|
||||||
|
INTERRUPT_CALLBACK interruptHandler=0;
|
||||||
|
|
||||||
|
|
||||||
|
void DCCTimer::begin(INTERRUPT_CALLBACK callback, bool slow) {
|
||||||
|
interruptHandler=callback;
|
||||||
|
// Initialise timer1 to trigger every 58us (DCC_SIGNAL_TIME)
|
||||||
|
noInterrupts();
|
||||||
|
TCCR1A = 0;
|
||||||
|
ICR1 = ((F_CPU / 1000000) * (slow? DCC_SLOW_TIME : DCC_SIGNAL_TIME)) >>1;
|
||||||
|
TCNT1 = 0;
|
||||||
|
TCCR1B = _BV(WGM13) | _BV(CS10); // Mode 8, clock select 1
|
||||||
|
TIMSK1 = _BV(TOIE1); // Enable Software interrupt
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer interrupt every 58uS
|
||||||
|
ISR(TIMER1_OVF_vect)
|
||||||
|
{
|
||||||
|
if (interruptHandler) interruptHandler();
|
||||||
|
}
|
13
DCCTimer.h
Normal file
13
DCCTimer.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef DCCTimer_h
|
||||||
|
#define DCCTimer_h
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
typedef void (*INTERRUPT_CALLBACK)();
|
||||||
|
|
||||||
|
class DCCTimer {
|
||||||
|
public:
|
||||||
|
static void begin(INTERRUPT_CALLBACK interrupt, bool slow=false);
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -20,10 +20,9 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "DCCWaveform.h"
|
#include "DCCWaveform.h"
|
||||||
|
#include "DCCTimer.h"
|
||||||
#include "DIAG.h"
|
#include "DIAG.h"
|
||||||
|
|
||||||
const int NORMAL_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle
|
|
||||||
const int SLOW_SIGNAL_TIME=NORMAL_SIGNAL_TIME*512;
|
|
||||||
|
|
||||||
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);
|
||||||
@ -31,32 +30,18 @@ DCCWaveform DCCWaveform::progTrack(PREAMBLE_BITS_PROG, false);
|
|||||||
|
|
||||||
bool DCCWaveform::progTrackSyncMain=false;
|
bool DCCWaveform::progTrackSyncMain=false;
|
||||||
bool DCCWaveform::progTrackBoosted=false;
|
bool DCCWaveform::progTrackBoosted=false;
|
||||||
VirtualTimer * DCCWaveform::interruptTimer=NULL;
|
|
||||||
|
|
||||||
void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver, byte timerNumber) {
|
void DCCWaveform::begin(MotorDriver * mainDriver, MotorDriver * progDriver) {
|
||||||
mainTrack.motorDriver=mainDriver;
|
mainTrack.motorDriver=mainDriver;
|
||||||
progTrack.motorDriver=progDriver;
|
progTrack.motorDriver=progDriver;
|
||||||
|
|
||||||
mainTrack.setPowerMode(POWERMODE::OFF);
|
mainTrack.setPowerMode(POWERMODE::OFF);
|
||||||
progTrack.setPowerMode(POWERMODE::OFF);
|
progTrack.setPowerMode(POWERMODE::OFF);
|
||||||
switch (timerNumber) {
|
DCCTimer::begin(DCCWaveform::interruptHandler);
|
||||||
case 1: interruptTimer= &TimerA; break;
|
|
||||||
case 2: interruptTimer= &TimerB; break;
|
|
||||||
#ifndef ARDUINO_AVR_UNO
|
|
||||||
case 3: interruptTimer= &TimerC; break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
DIAG(F("\n\n *** Invalid Timer number %d requested. Only 1..3 valid. DCC will not work.*** \n\n"), timerNumber);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
interruptTimer->initialize();
|
|
||||||
interruptTimer->setPeriod(NORMAL_SIGNAL_TIME); // this is the 58uS DCC 1-bit waveform half-cycle
|
|
||||||
interruptTimer->attachInterrupt(interruptHandler);
|
|
||||||
interruptTimer->start();
|
|
||||||
}
|
}
|
||||||
void DCCWaveform::setDiagnosticSlowWave(bool slow) {
|
|
||||||
interruptTimer->setPeriod(slow? SLOW_SIGNAL_TIME : NORMAL_SIGNAL_TIME);
|
void DCCWaveform::setDiagnosticSlowWave(bool slow) {
|
||||||
interruptTimer->start();
|
DCCTimer::begin(DCCWaveform::interruptHandler, slow);
|
||||||
DIAG(F("\nDCC SLOW WAVE %S\n"),slow?F("SET. DO NOT ADD LOCOS TO TRACK"):F("RESET"));
|
DIAG(F("\nDCC SLOW WAVE %S\n"),slow?F("SET. DO NOT ADD LOCOS TO TRACK"):F("RESET"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +50,6 @@ void DCCWaveform::loop() {
|
|||||||
progTrack.checkPowerOverload();
|
progTrack.checkPowerOverload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// static //
|
|
||||||
void DCCWaveform::interruptHandler() {
|
void DCCWaveform::interruptHandler() {
|
||||||
// call the timer edge sensitive actions for progtrack and maintrack
|
// call the timer edge sensitive actions for progtrack and maintrack
|
||||||
bool mainCall2 = mainTrack.interrupt1();
|
bool mainCall2 = mainTrack.interrupt1();
|
||||||
@ -112,10 +95,6 @@ POWERMODE DCCWaveform::getPowerMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DCCWaveform::setPowerMode(POWERMODE mode) {
|
void DCCWaveform::setPowerMode(POWERMODE mode) {
|
||||||
|
|
||||||
// Prevent power switch on with no timer... Otheruise track will get full power DC and locos will run away.
|
|
||||||
if (!interruptTimer) return;
|
|
||||||
|
|
||||||
powerMode = mode;
|
powerMode = mode;
|
||||||
bool ison = (mode == POWERMODE::ON);
|
bool ison = (mode == POWERMODE::ON);
|
||||||
motorDriver->setPower( ison);
|
motorDriver->setPower( ison);
|
||||||
@ -168,10 +147,6 @@ void DCCWaveform::checkPowerOverload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// process time-edge sensitive part of interrupt
|
// process time-edge sensitive part of interrupt
|
||||||
// return true if second level required
|
// return true if second level required
|
||||||
bool DCCWaveform::interrupt1() {
|
bool DCCWaveform::interrupt1() {
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#ifndef DCCWaveform_h
|
#ifndef DCCWaveform_h
|
||||||
#define DCCWaveform_h
|
#define DCCWaveform_h
|
||||||
#include "MotorDriver.h"
|
#include "MotorDriver.h"
|
||||||
#include "ArduinoTimers.h"
|
|
||||||
|
|
||||||
// Wait times for power management. Unit: milliseconds
|
// Wait times for power management. Unit: milliseconds
|
||||||
const int POWER_SAMPLE_ON_WAIT = 100;
|
const int POWER_SAMPLE_ON_WAIT = 100;
|
||||||
@ -46,7 +45,7 @@ const byte resetPacket[] = {0x00, 0x00, 0x00};
|
|||||||
class DCCWaveform {
|
class DCCWaveform {
|
||||||
public:
|
public:
|
||||||
DCCWaveform( byte preambleBits, bool isMain);
|
DCCWaveform( byte preambleBits, bool isMain);
|
||||||
static void begin(MotorDriver * mainDriver, MotorDriver * progDriver, byte timerNumber);
|
static void begin(MotorDriver * mainDriver, MotorDriver * progDriver);
|
||||||
static void setDiagnosticSlowWave(bool slow);
|
static void setDiagnosticSlowWave(bool slow);
|
||||||
static void loop();
|
static void loop();
|
||||||
static DCCWaveform mainTrack;
|
static DCCWaveform mainTrack;
|
||||||
@ -105,7 +104,7 @@ class DCCWaveform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static VirtualTimer * interruptTimer;
|
|
||||||
static void interruptHandler();
|
static void interruptHandler();
|
||||||
bool interrupt1();
|
bool interrupt1();
|
||||||
void interrupt2();
|
void interrupt2();
|
||||||
|
52
Timer.cpp
52
Timer.cpp
@ -1,52 +0,0 @@
|
|||||||
// This file is copied from https://github.com/davidcutting42/ArduinoTimers
|
|
||||||
// All Credit to David Cutting
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
#if 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,21 +0,0 @@
|
|||||||
// 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