diff --git a/DCCTimer.h b/DCCTimer.h index 7a9d940..7402f16 100644 --- a/DCCTimer.h +++ b/DCCTimer.h @@ -105,9 +105,14 @@ private: // that an offset can be initialized. class ADCee { public: - // init does add the pin to the list of scanned pins (if this + // 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 // platform's implementation scans pins) and returns the first - // read value. It is called before the regular scan is started. + // read value (which is why it required begin to have been called first!) + // It must be 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 @@ -116,19 +121,15 @@ 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. static void scan(); // bit array of used pins (max 16) static uint16_t usedpins; + static uint8_t highestPin; // 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 40ce0fb..80cd245 100644 --- a/DCCTimerAVR.cpp +++ b/DCCTimerAVR.cpp @@ -1,6 +1,6 @@ /* * © 2021 Mike S - * © 2021-2022 Harald Barth + * © 2021-2023 Harald Barth * © 2021 Fred Decker * © 2021 Chris Harlow * © 2021 David Cutting @@ -29,6 +29,9 @@ #include #include #include "DCCTimer.h" +#ifdef DEBUG_ADC +#include "TrackManager.h" +#endif INTERRUPT_CALLBACK interruptHandler=0; // Arduino nano, uno, mega etc @@ -128,8 +131,8 @@ void DCCTimer::reset() { #define NUM_ADC_INPUTS 8 #endif uint16_t ADCee::usedpins = 0; +uint8_t ADCee::highestPin = 0; int * ADCee::analogvals = NULL; -byte *ADCee::idarr = NULL; static bool ADCusesHighPort = false; /* @@ -139,28 +142,17 @@ static bool ADCusesHighPort = false; */ int ADCee::init(uint8_t pin) { uint8_t id = pin - A0; - byte n; if (id >= NUM_ADC_INPUTS) return -1023; if (id > 7) ADCusesHighPort = true; pinMode(pin, INPUT); int value = analogRead(pin); - if (analogvals == NULL) { + if (analogvals == NULL) analogvals = (int *)calloc(NUM_ADC_INPUTS, sizeof(int)); - for (n=0 ; n < NUM_ADC_INPUTS; n++) // set unreasonable value at startup as marker - analogvals[n] = -32768; // 16 bit int min value - idarr = (byte *)calloc(NUM_ADC_INPUTS+1, sizeof(byte)); // +1 for terminator value - for (n=0 ; n <= NUM_ADC_INPUTS; n++) - idarr[n] = 255; // set 255 as end of array marker - } - analogvals[id] = value; // store before enable by idarr[n] - for (n=0 ; n <= NUM_ADC_INPUTS; n++) { - if (idarr[n] == 255) { - idarr[n] = id; - break; - } - } + analogvals[id] = value; + usedpins |= (1< highestPin) highestPin = id; return value; } int16_t ADCee::ADCmax() { @@ -170,14 +162,14 @@ int16_t ADCee::ADCmax() { * Read function ADCee::read(pin) to get value instead of analogRead(pin) */ int ADCee::read(uint8_t pin, bool fromISR) { - (void)fromISR; // AVR does ignore this arg uint8_t id = pin - A0; - int a; + if ((usedpins & (1<setBrake(0); +#endif waiting = false; + id++; + mask = mask << 1; + if (id > highestPin) { // the 1 has been shifted out + id = 0; + mask = 1; + } } if (!waiting) { - // cycle around in-use analogue pins - num++; - if (idarr[num] == 255) - num = 0; - // start new ADC aquire on id + 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 #if defined(ADCSRB) && defined(MUX5) - 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); - } + 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 << REFS0) | (idarr[num] & 0x07); // select AVCC as reference and set MUX - bitSet(ADCSRA, ADSC); // start conversion - waiting = true; + ADMUX=(1<setBrake(1); +#endif + waiting = true; + return; + } + id++; + mask = mask << 1; + if (id > highestPin) { + id = 0; + mask = 1; + } + } } } #pragma GCC pop_options @@ -231,4 +247,4 @@ void ADCee::begin() { //bitSet(ADCSRA, ADSC); //do not start the ADC yet. Done when we have set the MUX interrupts(); } -#endif \ No newline at end of file +#endif diff --git a/version.h b/version.h index c3d47d9..6355f6b 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,8 @@ #include "StringFormatter.h" -#define VERSION "4.2.54" +#define VERSION "4.2.55" +// 4.2.55 - Optimize analog read for AVR // 4.2.54 - EX8874 shield in config.example.h // - Fix: Better warnings for pin number errors // - Fix: Default roster list possible in Withrottle and