1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-25 13:41:23 +01:00

SAMD21 DCC waveform working

This commit is contained in:
pmantoine 2022-04-12 14:32:10 +08:00
parent a52551babe
commit 8fa1ba3039
3 changed files with 42 additions and 37 deletions

View File

@ -85,8 +85,8 @@ void setup()
EthernetInterface::setup(); EthernetInterface::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

View File

@ -70,55 +70,59 @@ 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) {
// TODO: what are the relevant pins? // TODO: what are the relevant pins?

View File

@ -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), \