From ee568fcd11ccff6fc715be9399b43be9da61692f Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 4 Oct 2022 21:55:13 +0200 Subject: [PATCH] make the Adc class functions the normal code path --- DCCACK.cpp | 2 +- DCCTimer.h | 8 +++++-- DCCTimerAVR.cpp | 13 ++++++++--- DCCTimerESP.cpp | 40 +++++++++++++++++++++++++++++++- DCCTimerSAMD.cpp | 59 ++++++++++++++++++++++++++++++++---------------- DCCWaveform.cpp | 4 +--- MotorDriver.cpp | 46 ++----------------------------------- MotorDriver.h | 8 +------ defines.h | 5 ---- 9 files changed, 100 insertions(+), 85 deletions(-) diff --git a/DCCACK.cpp b/DCCACK.cpp index fa3d348..8c5e8c7 100644 --- a/DCCACK.cpp +++ b/DCCACK.cpp @@ -425,7 +425,7 @@ void DCCACK::checkAck(byte sentResetsSincePacket) { return; } - int current=progDriver->getCurrentRawInInterrupt(); + int current=progDriver->getCurrentRaw(true); // true means "from interrupt" numAckSamples++; if (current > ackMaxCurrent) ackMaxCurrent=current; // An ACK is a pulse lasting between minAckPulseDuration and maxAckPulseDuration uSecs (refer @haba) diff --git a/DCCTimer.h b/DCCTimer.h index 7864d70..a9baf0e 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -95,8 +95,12 @@ private: class Adc { public: - static void reg(uint8_t pin); - static int read(uint8_t pin); + // On architectures that use the analog read during DCC waveform + // with specially configured ADC, for example AVR, init must be + // called PRIOR to the start of the waveform. It returns the + // current value so that an offset can be initialized. + static int init(uint8_t pin); + static int read(uint8_t pin, bool fromISR); private: static void scan(); static void begin(); diff --git a/DCCTimerAVR.cpp b/DCCTimerAVR.cpp index 8dbe00b..74611e1 100644 --- a/DCCTimerAVR.cpp +++ b/DCCTimerAVR.cpp @@ -129,19 +129,26 @@ int * Adc::analogvals = NULL; /* * Register a new pin to be scanned + * Returns current reading of pin and + * stores that as well */ -void Adc::reg(uint8_t pin) { +int Adc::init(uint8_t pin) { uint8_t id = pin - A0; if (id > NUM_ADC_INPUTS) - return; + return -1023; + pinMode(pin, INPUT); + int value = analogRead(pin); if (analogvals == NULL) analogvals = (int *)calloc(NUM_ADC_INPUTS+1, sizeof(int)); + analogvals[id] = value; usedpins |= (1< +#include +#include +#undef ADC_INPUT_MAX_VALUE +#define ADC_INPUT_MAX_VALUE 4095 // 12 bit ADC +#define pinToADC1Channel(X) (adc1_channel_t)(((X) > 35) ? (X)-36 : (X)-28) + +int IRAM_ATTR local_adc1_get_raw(int channel) { + uint16_t adc_value; + SENS.sar_meas_start1.sar1_en_pad = (1 << channel); // only one channel is selected + while (SENS.sar_slave_addr1.meas_status != 0); + SENS.sar_meas_start1.meas1_start_sar = 0; + SENS.sar_meas_start1.meas1_start_sar = 1; + while (SENS.sar_meas_start1.meas1_done_sar == 0); + adc_value = SENS.sar_meas_start1.meas1_data_sar; + return adc_value; +} #include "DCCTimer.h" INTERRUPT_CALLBACK interruptHandler=0; @@ -133,5 +150,26 @@ int DCCTimer::freeMemory() { void DCCTimer::reset() { ESP.restart(); } -#endif +int Adc::init(uint8_t pin) { + pinMode(pin, ANALOG); + adc1_config_channel_atten(pinToADC1Channel(pin),ADC_ATTEN_DB_11); + return local_adc1_get_raw(pinToADC1Channel(pin)); +} +/* + * Read function Adc::read(pin) to get value instead of analogRead(pin) + */ +int Adc::read(uint8_t pin, bool fromISR) { + return local_adc1_get_raw(pinToADC1Channel(pin)); +} +/* + * Scan function that is called from interrupt + */ +void Adc::scan() { +} + +void Adc::begin() { + adc1_config_width(ADC_WIDTH_BIT_12); +} + +#endif //ESP32 diff --git a/DCCTimerSAMD.cpp b/DCCTimerSAMD.cpp index e42d94c..ddd9a48 100644 --- a/DCCTimerSAMD.cpp +++ b/DCCTimerSAMD.cpp @@ -37,24 +37,6 @@ INTERRUPT_CALLBACK interruptHandler=0; void DCCTimer::begin(INTERRUPT_CALLBACK callback) { interruptHandler=callback; noInterrupts(); - - // Set up ADC to do faster reads... default for Arduino Zero platform configs is 436uS, - // and we need sub-100uS. This code sets it to a read speed of around 21uS, and for now - // enables 10-bit mode, although 12-bit is possible - ADC->CTRLA.bit.ENABLE = 0; // disable ADC - while( ADC->STATUS.bit.SYNCBUSY == 1 ); // wait for synchronization - - ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits - ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64 | // divide Clock by 64 - ADC_CTRLB_RESSEL_10BIT; // Result on 10 bits default, 12 bits possible - - ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample at a time - ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0 - ADC->SAMPCTRL.reg = 0x00; // sampling Time Length = 0 - - ADC->CTRLA.bit.ENABLE = 1; // enable ADC - while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization - // Timer setup - setup clock sources first REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide 48MHz by 1 GCLK_GENDIV_ID(4); // Apply to GCLK4 @@ -173,4 +155,43 @@ void DCCTimer::reset() { while(true) {}; } -#endif \ No newline at end of file +int Adc::init(uint8_t pin) { + return analogRead(pin); +} +/* + * Read function Adc::read(pin) to get value instead of analogRead(pin) + */ +int Adc::read(uint8_t pin, bool fromISR) { + int current; + if (!fromISR) noInterrupts(); + current = analogRead(pin); + if (!fromISR) interrupts(); + return current; +} +/* + * Scan function that is called from interrupt + */ +void Adc::scan() { +} + +void Adc::begin() { + noInterrupts(); + // Set up ADC to do faster reads... default for Arduino Zero platform configs is 436uS, + // and we need sub-100uS. This code sets it to a read speed of around 21uS, and for now + // enables 10-bit mode, although 12-bit is possible + ADC->CTRLA.bit.ENABLE = 0; // disable ADC + while( ADC->STATUS.bit.SYNCBUSY == 1 ); // wait for synchronization + + ADC->CTRLB.reg &= 0b1111100011111111; // mask PRESCALER bits + ADC->CTRLB.reg |= ADC_CTRLB_PRESCALER_DIV64 | // divide Clock by 64 + ADC_CTRLB_RESSEL_10BIT; // Result on 10 bits default, 12 bits possible + + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // take 1 sample at a time + ADC_AVGCTRL_ADJRES(0x00ul); // adjusting result by 0 + ADC->SAMPCTRL.reg = 0x00; // sampling Time Length = 0 + + ADC->CTRLA.bit.ENABLE = 1; // enable ADC + while(ADC->STATUS.bit.SYNCBUSY == 1); // wait for synchronization + interrupts(); +} +#endif diff --git a/DCCWaveform.cpp b/DCCWaveform.cpp index 3661246..4e142a7 100644 --- a/DCCWaveform.cpp +++ b/DCCWaveform.cpp @@ -82,10 +82,8 @@ void DCCWaveform::interruptHandler() { TrackManager::setDCCSignal(sigMain); TrackManager::setPROGSignal(sigProg); -#ifdef ANALOG_READ_INTERRUPT - //TrackManager::sampleCurrent(); + // Refresh the values in the Adc object buffering the values of the ADC HW Adc::scan(); -#endif // Move on in the state engine mainTrack.state=stateTransform[mainTrack.state]; diff --git a/MotorDriver.cpp b/MotorDriver.cpp index 4edf059..666013f 100644 --- a/MotorDriver.cpp +++ b/MotorDriver.cpp @@ -30,24 +30,6 @@ #if defined(ARDUINO_ARCH_ESP32) #include "ESP32-fixes.h" -#include -#include -#include -#undef ADC_INPUT_MAX_VALUE -#define ADC_INPUT_MAX_VALUE 4095 // 12 bit ADC -#define pinToADC1Channel(X) (adc1_channel_t)(((X) > 35) ? (X)-36 : (X)-28) - -int IRAM_ATTR local_adc1_get_raw(int channel) { - uint16_t adc_value; - SENS.sar_meas_start1.sar1_en_pad = (1 << channel); // only one channel is selected - while (SENS.sar_slave_addr1.meas_status != 0); - SENS.sar_meas_start1.meas1_start_sar = 0; - SENS.sar_meas_start1.meas1_start_sar = 1; - while (SENS.sar_meas_start1.meas1_done_sar == 0); - adc_value = SENS.sar_meas_start1.meas1_data_sar; - return adc_value; -} - #endif bool MotorDriver::commonFaultPin=false; @@ -110,18 +92,7 @@ MotorDriver::MotorDriver(int16_t power_pin, byte signal_pin, byte signal_pin2, i currentPin=current_pin; if (currentPin!=UNUSED_PIN) { -#ifdef ARDUINO_ARCH_ESP32 - pinMode(currentPin, ANALOG); - adc1_config_width(ADC_WIDTH_BIT_12); - adc1_config_channel_atten(pinToADC1Channel(currentPin),ADC_ATTEN_DB_11); - senseOffset = adc1_get_raw(pinToADC1Channel(currentPin)); -#else - pinMode(currentPin, INPUT); - Adc::reg(currentPin); - // run analogRead as Adc::read() does not have any values before - // the waveform has been started. - senseOffset=analogRead(currentPin); // value of sensor at zero current -#endif + senseOffset = Adc::init(currentPin); } faultPin=fault_pin; @@ -223,20 +194,7 @@ int MotorDriver::getCurrentRaw(bool fromISR) { (void)fromISR; if (currentPin==UNUSED_PIN) return 0; int current; -#ifdef ARDUINO_ARCH_ESP32 - current = local_adc1_get_raw(pinToADC1Channel(currentPin))-senseOffset; -#else -#ifdef ANALOG_READ_INTERRUPT - current = Adc::read(currentPin)-senseOffset; - //current = sampleCurrent-senseOffset; - //if ((millis() - sampleCurrentTimestamp) > 3) - // DIAG(F("Current sample old %d"), millis() - sampleCurrentTimestamp); -#else - if (!fromISR) noInterrupts(); - current = analogRead(currentPin)-senseOffset; - if (!fromISR) interrupts(); -#endif //ANALOG_READ_INTERRUPT -#endif //ARDUINO_ARCH_ESP32 + current = Adc::read(currentPin, fromISR)-senseOffset; if (current<0) current=0-current; if ((faultPin != UNUSED_PIN) && isLOW(fastFaultPin) && powerMode==POWERMODE::ON) return (current == 0 ? -1 : -current); diff --git a/MotorDriver.h b/MotorDriver.h index 9164b0a..51f7654 100644 --- a/MotorDriver.h +++ b/MotorDriver.h @@ -153,12 +153,7 @@ class MotorDriver { setDCSignal(128); #endif }; - int getCurrentRaw() { - return getCurrentRaw(false); - } - int getCurrentRawInInterrupt() { - return getCurrentRaw(true); - }; + int getCurrentRaw(bool fromISR=false); unsigned int raw2mA( int raw); unsigned int mA2raw( unsigned int mA); inline bool brakeCanPWM() { @@ -192,7 +187,6 @@ class MotorDriver { void startCurrentFromHW(); #endif private: - int getCurrentRaw(bool fromISR); bool isProgTrack = false; // tells us if this is a prog track void getFastPin(const FSH* type,int pin, bool input, FASTPIN & result); void getFastPin(const FSH* type,int pin, FASTPIN & result) { diff --git a/defines.h b/defines.h index bc99413..3d54a6f 100644 --- a/defines.h +++ b/defines.h @@ -43,11 +43,6 @@ #undef USB_SERIAL // Teensy has this defined by default... #define USB_SERIAL Serial -// All AVRs must read analog values from the DCC timer interrupt -#ifdef ARDUINO_ARCH_AVR -#define ANALOG_READ_INTERRUPT -#endif - #if defined(ARDUINO_AVR_UNO) #define ARDUINO_TYPE "UNO" #undef HAS_ENOUGH_MEMORY