From adb8b56c92eafd4a925cf5d21cd58c1d8315a27c Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sat, 30 Dec 2023 21:23:44 +0100 Subject: [PATCH] variable frequency step #1 --- DCCTimer.h | 1 + DCCTimerAVR.cpp | 71 ++++++++++++++++++++++++++++++++++++ DCCTimerESP.cpp | 16 +++++++- DCCTimerSTM32.cpp | 15 +++++++- MotorDriver.cpp | 93 ++++++++--------------------------------------- 5 files changed, 115 insertions(+), 81 deletions(-) diff --git a/DCCTimer.h b/DCCTimer.h index 3b14fd6..5cc5ce8 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -85,6 +85,7 @@ class DCCTimer { static void reset(); private: + static void DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency); static int freeMemory(); static volatile int minimum_free_memory; static const int DCC_SIGNAL_TIME=58; // this is the 58uS DCC 1-bit waveform half-cycle diff --git a/DCCTimerAVR.cpp b/DCCTimerAVR.cpp index 3e6c436..b27a906 100644 --- a/DCCTimerAVR.cpp +++ b/DCCTimerAVR.cpp @@ -29,6 +29,7 @@ #include #include #include "DCCTimer.h" +#include "DIAG.h" #ifdef DEBUG_ADC #include "TrackManager.h" #endif @@ -125,6 +126,76 @@ void DCCTimer::reset() { } +void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) { + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f); +} +void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t fbits) { +#if defined(ARDUINO_AVR_UNO) + // Not worth doin something here as: + // If we are on pin 9 or 10 we are on Timer1 and we can not touch Timer1 as that is our DCC source. + // If we are on pin 5 or 6 we are on Timer 0 ad we can not touch Timer0 as that is millis() etc. + // We are most likely not on pin 3 or 11 as no known motor shield has that as brake. +#endif +#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) + uint8_t abits; + uint8_t bbits; + if (pin == 9 || pin == 10) { // timer 2 is different + + if (fbits >= 3) + abits = B11; + else + abits = B01; + + if (fbits >= 3) + bbits = B0001; + else if (fbits == 2) + bbits = B0010; + else if (fbits == 1) + bbits = B0100; + else + bbits = B0110; + + TCCR2A = (TCCR2A & B11111100) | abits; // set WGM0 and WGM1 + TCCR2B = (TCCR2B & B11110000) | bbits; // set WGM2 and 3 bits of prescaler + DIAG(F("Timer 2 A=%x B=%x"), TCCR2A, TCCR2B); + + } else { // not timer 9 or 10 + abits = B01; + + if (fbits >= 3) + bbits = B1001; + else if (fbits == 2) + bbits = B0010; + else if (fbits == 1) + bbits = B0011; + else + bbits = B0100; + + switch (pin) { + // case 9 and 10 taken care of above by if() + case 6: + case 7: + case 8: + // Timer4 + TCCR4A = (TCCR4A & B11111100) | abits; // set WGM0 and WGM1 + TCCR4B = (TCCR4B & B11100000) | bbits; // set WGM2 and WGM3 and divisor + DIAG(F("Timer 4 A=%x B=%x"), TCCR4A, TCCR4B); + break; + case 46: + case 45: + case 44: + // Timer5 + TCCR5A = (TCCR5A & B11111100) | abits; // set WGM0 and WGM1 + TCCR5B = (TCCR5B & B11100000) | bbits; // set WGM2 and WGM3 and divisor + DIAG(F("Timer 5 A=%x B=%x"), TCCR5A, TCCR5B); + break; + default: + break; + } + } +#endif +} + #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) #define NUM_ADC_INPUTS 16 #else diff --git a/DCCTimerESP.cpp b/DCCTimerESP.cpp index 7ed3f28..dbd4e9d 100644 --- a/DCCTimerESP.cpp +++ b/DCCTimerESP.cpp @@ -151,10 +151,22 @@ void DCCTimer::reset() { ESP.restart(); } +void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) { + if (f >= 16) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f); + else if (f >= 3) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 62500); + else if (f == 2) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3400); + else if (f == 1) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480); + else + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 131); +} + #include "esp32-hal.h" #include "soc/soc_caps.h" - #ifdef SOC_LEDC_SUPPORT_HS_MODE #define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1) #else @@ -164,7 +176,7 @@ void DCCTimer::reset() { static int8_t pin_to_channel[SOC_GPIO_PIN_COUNT] = { 0 }; static int cnt_channel = LEDC_CHANNELS; -void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency) { +void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency) { if (pin < SOC_GPIO_PIN_COUNT) { if (pin_to_channel[pin] != 0) { ledcSetup(pin_to_channel[pin], frequency, 8); diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index f24adc2..c220620 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -257,6 +257,19 @@ void DCCTimer::reset() { while(true) {}; } +void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t f) { + if (f >= 16) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, f); + else if (f >= 3) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 62500); + else if (f == 2) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 3400); + else if (f == 1) + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 480); + else + DCCTimer::DCCEXanalogWriteFrequencyInternal(pin, 131); +} + // TODO: rationalise the size of these... could really use sparse arrays etc. static HardwareTimer * pin_timer[100] = {0}; static uint32_t channel_frequency[100] = {0}; @@ -267,7 +280,7 @@ static uint32_t pin_channel[100] = {0}; // sophisticated about detecting any clash between the timer we'd like to use for PWM and the ones // currently used for HA so they don't interfere with one another. For now we'll just make PWM // work well... then work backwards to integrate with HA mode if we can. -void DCCTimer::DCCEXanalogWriteFrequency(uint8_t pin, uint32_t frequency) +void DCCTimer::DCCEXanalogWriteFrequencyInternal(uint8_t pin, uint32_t frequency) { if (pin_timer[pin] == NULL) { // Automatically retrieve TIM instance and channel associated to pin diff --git a/MotorDriver.cpp b/MotorDriver.cpp index bd25be4..cdbd667 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -328,45 +328,19 @@ uint16_t taurustones[28] = { 165, 175, 196, 220, void MotorDriver::setDCSignal(byte speedcode) { if (brakePin == UNUSED_PIN) return; - switch(brakePin) { -#if defined(ARDUINO_AVR_UNO) - // Not worth doin something here as: - // If we are on pin 9 or 10 we are on Timer1 and we can not touch Timer1 as that is our DCC source. - // If we are on pin 5 or 6 we are on Timer 0 ad we can not touch Timer0 as that is millis() etc. - // We are most likely not on pin 3 or 11 as no known motor shield has that as brake. -#endif -#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) - case 9: - case 10: - // Timer2 (is differnet) - TCCR2A = (TCCR2A & B11111100) | B00000001; // set WGM1=0 and WGM0=1 phase correct PWM - TCCR2B = (TCCR2B & B11110000) | B00000110; // set WGM2=0 ; set divisor on timer 2 to 1/256 for 122.55Hz - //DIAG(F("2 A=%x B=%x"), TCCR2A, TCCR2B); - break; - case 6: - case 7: - case 8: - // Timer4 - TCCR4A = (TCCR4A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for normal PWM 8-bit - TCCR4B = (TCCR4B & B11100000) | B00000100; // set WGM2=0 and WGM3=0 for normal PWM 8 bit and div 1/256 for 122.55Hz - break; - case 46: - case 45: - case 44: - // Timer5 - TCCR5A = (TCCR5A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for normal PWM 8-bit - TCCR5B = (TCCR5B & B11100000) | B00000100; // set WGM2=0 and WGM3=0 for normal PWM 8 bit and div 1/256 for 122.55Hz - break; -#endif - default: - break; - } // spedcoode is a dcc speed & direction byte tSpeed=speedcode & 0x7F; // DCC Speed with 0,1 stop and speed steps 2 to 127 byte tDir=speedcode & 0x80; byte brake; + + if (tSpeed <= 1) brake = 255; + else if (tSpeed >= 127) brake = 0; + else brake = 2 * (128-tSpeed); + if (invertBrake) + brake=255-brake; + + { // new block because of variable f #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) - { int f = 131; #ifdef VARIABLE_TONES if (tSpeed > 2) { @@ -376,18 +350,13 @@ void MotorDriver::setDCSignal(byte speedcode) { } #endif DCCTimer::DCCEXanalogWriteFrequency(brakePin, f); // set DC PWM frequency to 100Hz XXX May move to setup + DCCTimer::DCCEXanalogWrite(brakePin,brake); +#else // all AVR here + DCCTimer::DCCEXanalogWriteFrequency(brakePin, 0); // 0 is lowest possible f, like 120Hz + analogWrite(brakePin,brake); +#endif } -#endif - if (tSpeed <= 1) brake = 255; - else if (tSpeed >= 127) brake = 0; - else brake = 2 * (128-tSpeed); - if (invertBrake) - brake=255-brake; -#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_STM32) - DCCTimer::DCCEXanalogWrite(brakePin,brake); -#else - analogWrite(brakePin,brake); -#endif + //DIAG(F("DCSignal %d"), speedcode); if (HAVE_PORTA(fastSignalPin.shadowinout == &PORTA)) { noInterrupts(); @@ -455,39 +424,7 @@ void MotorDriver::throttleInrush(bool on) { } #else if(on){ - switch(brakePin) { -#if defined(ARDUINO_AVR_UNO) - // Not worth doin something here as: - // If we are on pin 9 or 10 we are on Timer1 and we can not touch Timer1 as that is our DCC source. - // If we are on pin 5 or 6 we are on Timer 0 ad we can not touch Timer0 as that is millis() etc. - // We are most likely not on pin 3 or 11 as no known motor shield has that as brake. -#endif -#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) - case 9: - case 10: - // Timer2 (is different) - TCCR2A = (TCCR2A & B11111100) | B00000011; // set WGM0=1 and WGM1=1 for fast PWM - TCCR2B = (TCCR2B & B11110000) | B00000001; // set WGM2=0 and prescaler div=1 (max) - DIAG(F("2 A=%x B=%x"), TCCR2A, TCCR2B); - break; - case 6: - case 7: - case 8: - // Timer4 - TCCR4A = (TCCR4A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for fast PWM 8-bit - TCCR4B = (TCCR4B & B11100000) | B00001001; // set WGM2=1 and WGM3=0 for fast PWM 8 bit and div=1 (max) - break; - case 46: - case 45: - case 44: - // Timer5 - TCCR5A = (TCCR5A & B11111100) | B00000001; // set WGM0=1 and WGM1=0 for fast PWM 8-bit - TCCR5B = (TCCR5B & B11100000) | B00001001; // set WGM2=1 and WGM3=0 for fast PWM 8 bit and div=1 (max) - break; -#endif - default: - break; - } + DCCTimer::DCCEXanalogWriteFrequency(brakePin, 3); } analogWrite(brakePin,duty); #endif