From efb26660603eb02d056b1d6c9c7a7b4124213269 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Tue, 7 Feb 2023 23:18:59 +0000 Subject: [PATCH] DCCTimer_AVR - incorporate Haba's optimisations to ADC scanning --- DCCTimer.h | 16 ++++----- DCCTimerAVR.cpp | 91 +++++++++++++++++++++++-------------------------- 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/DCCTimer.h b/DCCTimer.h index 75be8cd..2214851 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -1,5 +1,5 @@ /* - * © 2022-2023 Paul M. Antoine + * © 2022 Paul M. Antoine * © 2021 Mike S * © 2021-2022 Harald Barth * © 2021 Fred Decker @@ -102,14 +102,9 @@ private: // that an offset can be initialized. class ADCee { public: - // begin is called for any setup that must be done before - // **init** can be called. On some architectures this involves ADC - // initialisation and clock routing, sampling times etc. - static void begin(); - // init adds the pin to the list of scanned pins (if this + // init does add the pin to the list of scanned pins (if this // platform's implementation scans pins) and returns the first - // read value (which is why it required begin to have been called first!) - // It must be called before the regular scan is started. + // read value. It is called before the regular scan is started. static int init(uint8_t pin); // read does read the pin value from the scanned cache or directly // if this is a platform that does not scan. fromISR is a hint if @@ -118,6 +113,9 @@ public: static int read(uint8_t pin, bool fromISR=false); // returns possible max value that the ADC can return static int16_t ADCmax(); + // begin is called for any setup that must be done before + // scan can be called. + static void begin(); private: // On platforms that scan, it is called from waveform ISR // only on a regular basis. @@ -126,6 +124,8 @@ private: static uint16_t usedpins; // cached analog values (malloc:ed to actual number of ADC channels) static int *analogvals; + // ids to scan (new way) + static byte *idarr; // friend so that we can call scan() and begin() friend class DCCWaveform; }; diff --git a/DCCTimerAVR.cpp b/DCCTimerAVR.cpp index 9b16c47..40ce0fb 100644 --- a/DCCTimerAVR.cpp +++ b/DCCTimerAVR.cpp @@ -123,13 +123,14 @@ void DCCTimer::reset() { } #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) -#define NUM_ADC_INPUTS 15 +#define NUM_ADC_INPUTS 16 #else -#define NUM_ADC_INPUTS 7 +#define NUM_ADC_INPUTS 8 #endif uint16_t ADCee::usedpins = 0; int * ADCee::analogvals = NULL; -bool ADCusesHighPort = false; +byte *ADCee::idarr = NULL; +static bool ADCusesHighPort = false; /* * Register a new pin to be scanned @@ -138,16 +139,28 @@ bool ADCusesHighPort = false; */ int ADCee::init(uint8_t pin) { uint8_t id = pin - A0; - if (id > NUM_ADC_INPUTS) + byte n; + if (id >= NUM_ADC_INPUTS) return -1023; if (id > 7) ADCusesHighPort = true; pinMode(pin, INPUT); int value = analogRead(pin); - if (analogvals == NULL) - analogvals = (int *)calloc(NUM_ADC_INPUTS+1, sizeof(int)); - analogvals[id] = value; - usedpins |= (1<setBrake(0); + analogvals[idarr[num]] = (high << 8) | low; waiting = false; - id++; - mask = mask << 1; - if (id == NUM_ADC_INPUTS+1) { - id = 0; - mask = 1; - } } if (!waiting) { - if (usedpins == 0) // otherwise we would loop forever - return; - // look for a valid track to sample or until we are around - while (true) { - if (mask & usedpins) { - // start new ADC aquire on id + // cycle around in-use analogue pins + num++; + if (idarr[num] == 255) + num = 0; + // start new ADC aquire on id #if defined(ADCSRB) && defined(MUX5) - if (ADCusesHighPort) { // if we ever have started to use high pins) - if (id > 7) // if we use a high ADC pin - bitSet(ADCSRB, MUX5); // set MUX5 bit - else - bitClear(ADCSRB, MUX5); - } -#endif - ADMUX=(1<setBrake(1); - waiting = true; - return; - } - id++; - mask = mask << 1; - if (id == NUM_ADC_INPUTS+1) { - id = 0; - mask = 1; - } + if (ADCusesHighPort) { // if we ever have started to use high pins) + if (idarr[num] > 7) // if we use a high ADC pin + bitSet(ADCSRB, MUX5); // set MUX5 bit + else + bitClear(ADCSRB, MUX5); } +#endif + ADMUX = (1 << REFS0) | (idarr[num] & 0x07); // select AVCC as reference and set MUX + bitSet(ADCSRA, ADSC); // start conversion + waiting = true; } } #pragma GCC pop_options @@ -236,4 +231,4 @@ void ADCee::begin() { //bitSet(ADCSRA, ADSC); //do not start the ADC yet. Done when we have set the MUX interrupts(); } -#endif +#endif \ No newline at end of file