mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-24 21:21:24 +01:00
SAMD21 DCC waveform working
This commit is contained in:
parent
a52551babe
commit
8fa1ba3039
@ -86,7 +86,7 @@ void setup()
|
|||||||
#endif // ETHERNET_ON
|
#endif // ETHERNET_ON
|
||||||
|
|
||||||
// Initialise HAL layer before reading EEprom or setting up MotorDrivers
|
// Initialise HAL layer before reading EEprom or setting up MotorDrivers
|
||||||
// IODevice::begin();
|
IODevice::begin();
|
||||||
|
|
||||||
// Responsibility 3: Start the DCC engine.
|
// Responsibility 3: Start the DCC engine.
|
||||||
// Note: this provides DCC with two motor drivers, main and prog, which handle the motor shield(s)
|
// Note: this provides DCC with two motor drivers, main and prog, which handle the motor shield(s)
|
||||||
@ -107,10 +107,10 @@ void setup()
|
|||||||
#undef SETUP
|
#undef SETUP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// #if defined(LCN_SERIAL)
|
#if defined(LCN_SERIAL)
|
||||||
// LCN_SERIAL.begin(115200);
|
LCN_SERIAL.begin(115200);
|
||||||
// LCN::init(LCN_SERIAL);
|
LCN::init(LCN_SERIAL);
|
||||||
// #endif
|
#endif
|
||||||
LCD(3, F("Ready"));
|
LCD(3, F("Ready"));
|
||||||
CommandDistributor::broadcastPower();
|
CommandDistributor::broadcastPower();
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ void loop()
|
|||||||
|
|
||||||
// Responsibility 1: Handle DCC background processes
|
// Responsibility 1: Handle DCC background processes
|
||||||
// (loco reminders and power checks)
|
// (loco reminders and power checks)
|
||||||
// DCC::loop();
|
DCC::loop();
|
||||||
|
|
||||||
// Responsibility 2: handle any incoming commands on USB connection
|
// Responsibility 2: handle any incoming commands on USB connection
|
||||||
SerialManager::loop();
|
SerialManager::loop();
|
||||||
@ -134,18 +134,18 @@ void loop()
|
|||||||
EthernetInterface::loop();
|
EthernetInterface::loop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// RMFT::loop(); // ignored if no automation
|
RMFT::loop(); // ignored if no automation
|
||||||
|
|
||||||
#if defined(LCN_SERIAL)
|
#if defined(LCN_SERIAL)
|
||||||
LCN::loop();
|
LCN::loop();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// LCDDisplay::loop(); // ignored if LCD not in use
|
LCDDisplay::loop(); // ignored if LCD not in use
|
||||||
|
|
||||||
// Handle/update IO devices.
|
// Handle/update IO devices.
|
||||||
//IODevice::loop();
|
IODevice::loop();
|
||||||
|
|
||||||
//Sensor::checkAll(); // Update and print changes
|
Sensor::checkAll(); // Update and print changes
|
||||||
|
|
||||||
// Report any decrease in memory (will automatically trigger on first call)
|
// Report any decrease in memory (will automatically trigger on first call)
|
||||||
static int ramLowWatermark = __INT_MAX__; // replaced on first loop
|
static int ramLowWatermark = __INT_MAX__; // replaced on first loop
|
||||||
|
@ -70,54 +70,58 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
|
|||||||
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1
|
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK to TCC0/1
|
||||||
while (GCLK->STATUS.bit.SYNCBUSY);
|
while (GCLK->STATUS.bit.SYNCBUSY);
|
||||||
|
|
||||||
// PMA - assume we're using TCC0
|
// PMA - assume we're using TCC0... as we're bit-bashing the DCC waveform output pins anyway
|
||||||
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1
|
// for "normal accuracy" DCC waveform generation. For high accuracy we're going to need
|
||||||
GCLK_GENDIV_ID(4); // Apply to GCLK4
|
// to a good deal more. The TCC waveform output pins are mux'd on the SAMD, and OP pins
|
||||||
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
|
// for each TCC are only available on certain pins
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform
|
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform
|
||||||
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for sync
|
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for sync
|
||||||
TCC0->INTENSET.reg = TCC_INTENSET_OVF; // Interrupt on overflow
|
|
||||||
|
|
||||||
// PMA - set the frequency
|
// PMA - set the frequency
|
||||||
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val);
|
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val);
|
||||||
unsigned long cycles = F_CPU / 10000000 * 58; // 58uS to cycles
|
TCC0->PER.reg = CLOCK_CYCLES * 2;
|
||||||
unsigned long pwmPeriod = cycles / 2;
|
|
||||||
TCC0->PER.reg = pwmPeriod;
|
|
||||||
while (TCC0->SYNCBUSY.bit.PER);
|
while (TCC0->SYNCBUSY.bit.PER);
|
||||||
|
|
||||||
// PMA - start it
|
// PMA - start it
|
||||||
TCC0->CTRLA.bit.ENABLE = 1;
|
TCC0->CTRLA.bit.ENABLE = 1;
|
||||||
while (TCC0->SYNCBUSY.bit.ENABLE);
|
while (TCC0->SYNCBUSY.bit.ENABLE);
|
||||||
|
|
||||||
|
// PMA - set interrupt condition, priority and enable
|
||||||
|
TCC0->INTENSET.reg = TCC_INTENSET_OVF; // Only interrupt on overflow
|
||||||
|
NVIC_SetPriority((IRQn_Type)TCC0_IRQn, 0); // Make this highest priority
|
||||||
NVIC_EnableIRQ((IRQn_Type)TCC0_IRQn); // Enable the interrupt
|
NVIC_EnableIRQ((IRQn_Type)TCC0_IRQn); // Enable the interrupt
|
||||||
interrupts();
|
interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// PMA - IRQ handler copied from rf24 branch
|
// PMA - Timer IRQ handlers replace the dummy handlers (cortex_handlers)
|
||||||
|
// copied from rf24 branch
|
||||||
// TODO: test
|
// TODO: test
|
||||||
void TCC0_Handler() {
|
void TCC0_Handler() {
|
||||||
if(TCC0->INTFLAG.bit.OVF) {
|
if(TCC0->INTFLAG.bit.OVF) {
|
||||||
TCC0->INTFLAG.bit.OVF = 1;
|
TCC0->INTFLAG.bit.OVF = 1; // writing a 1 clears the flag
|
||||||
|
interruptHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCC1_Handler() {
|
||||||
|
if(TCC1->INTFLAG.bit.OVF) {
|
||||||
|
TCC1->INTFLAG.bit.OVF = 1; // writing a 1 clears the flag
|
||||||
|
interruptHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCC2_Handler() {
|
||||||
|
if(TCC2->INTFLAG.bit.OVF) {
|
||||||
|
TCC2->INTFLAG.bit.OVF = 1; // writing a 1 clears the flag
|
||||||
interruptHandler();
|
interruptHandler();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DCCTimer::isPWMPin(byte pin) {
|
bool DCCTimer::isPWMPin(byte pin) {
|
||||||
//TODO: SAMD digitalPinHasPWM
|
//TODO: SAMD test this works!
|
||||||
(void) pin;
|
// return digitalPinHasPWM(pin);
|
||||||
return false; // TODO what are the relevant pins?
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCCTimer::setPWM(byte pin, bool high) {
|
void DCCTimer::setPWM(byte pin, bool high) {
|
||||||
|
@ -47,7 +47,8 @@
|
|||||||
//
|
//
|
||||||
// Arduino standard Motor Shield
|
// Arduino standard Motor Shield
|
||||||
#if defined(ARDUINO_ARCH_SAMD)
|
#if defined(ARDUINO_ARCH_SAMD)
|
||||||
// PMA - senseFactor for 3.3v systems is 1.95 as calculated when using 10-bit A/D samples,
|
// PMA - Setup for SAMD21 Sparkfun DEV board
|
||||||
|
// senseFactor for 3.3v systems is 1.95 as calculated when using 10-bit A/D samples,
|
||||||
// and for 12-bit samples it's more like 0.488, but we probably need to tweak both these
|
// and for 12-bit samples it's more like 0.488, but we probably need to tweak both these
|
||||||
#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \
|
#define STANDARD_MOTOR_SHIELD F("STANDARD_MOTOR_SHIELD"), \
|
||||||
new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 1.95, 2000, UNUSED_PIN), \
|
new MotorDriver(3, 12, UNUSED_PIN, 9, A0, 1.95, 2000, UNUSED_PIN), \
|
||||||
|
Loading…
Reference in New Issue
Block a user