Single shot ADC measurements corrupted by multiple timer ISR's

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a project that has been rather stable for a long time which used a single timer ISR to run the control and logging loops at 1/4 second and 1 second resp. then sleeps until overflow.

My platform is Nano V3 (atmega328p), with two ADC inputs using VCC ref, and a bunch of outputs including PWM.

 

I have just added a software UART from https://github.com/blalor/avr-so... with some modification to the project so I can get a feed from another micro (maybe I should have used i2c??),

This library sets up an ISR on timer0 https://github.com/blalor/avr-so... / https://github.com/blalor/avr-so... IMER0_COMPA_vect,

which if runs causes the ADC measurements to become corrupted, periodically it seems! If I include the library, make no calls to it and comment out the ISR completely then the problem goes away. If even the ISR with _no_ code inside it is run then the corruption reappears.

 

The two ADC measurements are done as single shot as:

/**
 * @brief Read ADC pin, returning value
 *
 * @param pin, The ADC pin to be read. 0-7
 * @param vref, The voltage reference. 0 = 1.1, 1 = external, >=2 = Vcc
 * @return uint16, The 10bit value from the init_ADC
 **/
uint16_t read_ADC_pin(uint8_t pin, uint8_t vref)
{
    //Clear the Power reduction register to enable the ADC in case we have gone to sleep between ADC reads
    PRR &= ~(1 << PRADC);

    //According to Vref, start the ADC read on pin
    switch(vref) {
        // 1.1V Vref
        case 0:
            ADMUX = (1 << REFS0) | (1 << REFS1) | (pin & 0xF);
            break;
        // External Vref
        case 1:
            ADMUX = (pin & 0xF);
            break;
        // Defaults to VCC as Vref
        default :
            ADMUX = (1 << REFS0)| (pin & 0xF);
            break;
    }

    // Enable the ADC, start measuring whilst setting the prescaler to 128
    ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    //Wait for conversion to finish
    while ((ADCSRA & (1 << ADSC)) != 0);

    //Return the ADC code
    return ADC;
}

and read in code as:

inputs->current = read_ADC_pin(A_SENSE_ADC_PIN, A_SENSE_ADC_REF);

 

The timer ISR etc. is as:

ISR(TIMER2_COMPA_vect) {
    /* increment clock */
    ticks += 1;
    mediumTime +=1;
    fastCallback += 1; //Would be better to lump all this together and force medim and fast as a mod(125,fast/med time) check 

    if ( fastCallback && (fastTime >= FAST_TIME_INTERVAL) ) {
        fastTime = 0;
        fastCallback();
    }

    if (mediumCallback && (mediumTime >= MEDIUM_TIME_INTERVAL) ) {
        mediumTime = 0;
        mediumCallback();
    }

    if (ticks >= TICKS_PER_SECOND) {
        ticks = 0;
        timestamp += 1;
        if (timestamp >= 86401) { //roll over for 24 hours
            timestamp = 0;
        }
        if (oncePerSecondCallback) {
            oncePerSecondCallback();
        }
    }
}

void init_clock() {
    ticks = 0;
    timestamp = 0;

    TCCR2A = (1 << WGM21); /* clear timer on compare match */
    TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); /* 1024 pre-scaler */
    TIMSK2 = (1 << OCIE2A); /* compare match interrupt */
    OCR2A = 125 - 1;
}

 

1. See above

2. See above

3. Tell us how the FUSES are set and what you use as a clock source.

Using Optiboot bootloader? and in main:

...
uint8_t resetFlags __attribute__ ((section(".noinit")));
void resetFlagsInit(void) __attribute__ ((naked)) __attribute__ ((section (".init0")));
void resetFlagsInit(void)
{
  // save the reset flags passed from the bootloader
  __asm__ __volatile__ ("mov %0, r2\n" : "=r" (resetFlags) :);
}

...

 Hmm, fuses, I am not setting them as far as I am aware...

F_CPU = 16000000

4. Tell us what PROCESSOR you are using.

atmega328p

5. Tell us if you have tried to SIMULATE the operation of the code. If you did, tell us what you found.

No, but before implementing in main application I had MWE examples operating on the hardware with no problem - until I added ADC reads, then observe the problem - hence happy with problem isolation.

6. Provide us with some DETAILED OBSERVATIONS about what it is or is not doing. This should relate to 1(b)(, above. "Doesn't work" covers a lot of territory! Is your LED off when it should be flashing, is your motor turning or not. Tell us what test equipment (volt meter, oscilloscope, etc) are available to you, what measurements you have actually made, and what the measurement results were.

One other strange observation is that the ADC measuements were stable in on version of the code until the massive power supplies I am controlling turned on. Very very strange as there should be no feedback from the PSU's., no groundind loop issues etc. I have tried on two micros on breadboard to further ensure the problem is not this, and have reproduced it in a minimal physical environment.

7. If you have some suspicions about why it does not work, tell us what the evidence is for your diagnosis.

Second ISR -see above

8. If you think that there is a hardware problem, provide a circuit diagram. Or, tell us what development board you are using and HOW you connect to it.

No

9. N/A

10. OK.

11. ASAP deleted 8)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SpmP wrote:
fastCallback += 1;

// ...

fastCallback();

 

I wonder, if incrementing a function pointer would give useful behaviour instead rubbish.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sharing variables between the old and new interrupts service routines? If so have you declared them Volatile?

 

Dumb question but had to ask :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is this a split from another thread?

 

Post #1 seems to give answers to numbered questions posed before that post. But it's post #1???

 


 

+1 on Dannis comment on doing an inccrement on a variable and use the variable as a function pointer. Seems very odd to me.

 

 

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Is this a split from another thread? Post #1 seems to give answers to numbered questions posed before that post. But it's post #1???
No split. He answered the questions from here:

http://www.avrfreaks.net/forum/help-my-doesnt-work

 

JohanEkdahl wrote:
+1 on Dannis comment on doing an inccrement on a variable and use the variable as a function pointer. Seems very odd to me.
I bet that it is a typo. Should be "fastTime += 1;" instead.

Stefan Ernst

Last Edited: Fri. Oct 27, 2017 - 10:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yea, thanks for noticing that typo - thats why the one time I tried to use fast time for process controll loop it faild so miserably.

 I do not think this is the problem tho, as the control loop is on the medium time callback and logging on the slow - once per second - callback.

 

Yea, I am to ensure that I am answering all the required questions - useful to have as some things are so obvious that they dont seem worth mentioning, like bootloader, fcpu etc 8)

 

Any ideas what may cause this?

The 'c' column is the ADC measurement at 1/4 second vAc the same thing measured at log time interval (1 second) - strange how they do not agree:

l 00011 c 01019 v 01001 vBMS 00000 B 000 S 000 vAc 01020 p 00102 pwm 04094 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00050 M Retrying num. 001
A stop condition was breached. Shutting down. and retrying
l 00012 c 00746 v 00962 vBMS 00000 B 000 S 000 vAc 01012 p 00071 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00049 M Retrying num. 002
A stop condition was breached. Shutting down. and retrying
l 00013 c 00646 v 00927 vBMS 00000 B 000 S 000 vAc 01020 p 00059 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00049 M Retrying num. 003
A stop condition was breached. Shutting down. and retrying
l 00014 c 01018 v 00918 vBMS 00000 B 000 S 000 vAc 01019 p 00093 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00049 M Retrying num. 004
A stop condition was breached. Shutting down. and retrying
l 00015 c 00633 v 00922 vBMS 00000 B 000 S 000 vAc 01019 p 00058 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00049 M Retrying num. 005
A stop condition was breached. Shutting down. and retrying
Maximum number of retries reached, aborting...
l 00016 c 00637 v 00922 vBMS 00000 B 000 S 000 vAc 01019 p 00058 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error
A stop condition was breached. Shutting down. and retrying
Maximum number of retries reached, aborting...
l 00017 c 01015 v 00918 vBMS 00000 B 000 S 000 vAc 01019 p 00093 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error
A stop condition was breached. Shutting down. and retrying
Maximum number of retries reached, aborting...
l 00018 c 01018 v 00919 vBMS 00000 B 000 S 000 vAc 01018 p 00093 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error
A stop condition was breached. Shutting down. and retrying
Maximum number of retries reached, aborting...
l 00019 c 01018 v 00921 vBMS 00000 B 000 S 000 vAc 01019 p 00093 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error
A stop condition was breached. Shutting down. and retrying
Maximum number of retries reached, aborting...
l 00020 c 00639 v 00923 vBMS 00000 B 000 S 000 vAc 01018 p 00058 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error
A stop condition was breached. Shutting down. and retrying
Maximum number of retries reached, aborting...
l 00021 c 00647 v 00926 vBMS 00000 B 000 S 000 vAc 01019 p 00059 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error
l 00022 c 01018 v 00917 vBMS 00000 B 000 S 000 vAc 01019 p 00093 pwm 04093 PiD  00000 Csp 00000 Vsp 00000 Psp 00000 W 00000 M Off Error

With a very cut down version of the same base project I get  quite a consistent reading, similar to vAc... strange as I have had the 'c' fluctuating here too... but not this time

Rx  testing Soft UART recieve00002 x
 c: 01018
 c: 01019
 c: 01019
 c: 01020 mV: 02278 status: 007 balancing: 001
 c: 01019
 c: 01019
 c: 01020
 c: 01020 mV: 02279 status: 007 balancing: 001

If instead of the raw ADC measurement I output a floating point linear calibration on it the fluctuation is a little more present:

    Rx  testing Soft UART recieve00002 x
 c: 11476
 c: 11562 mV: 02369 status: 007 balancing: 001
 c: 11562
 c: 11562
 c: 11390
 c: 10787 mV: 02370 status: 007 balancing: 001
 c: 11562
 c: 11476
 c: 11562
 c: 11476 mV: 02371 status: 007 balancing: 001
 c: 11562
 c: 11476
 c: 11390 mV: 02372 status: 007 balancing: 001
 c: 11476
 c: 11562
 c: 11476
 c: 11304 mV: 02373 status: 007 balancing: 001

Without the softuart:

Rx  testing Soft UART recieve00002 x
 c: 11476
 c: 11476
 c: 11562
 c: 11562
 c: 11476
 c: 11476
 c: 11562
 c: 11562
 c: 11476
 c: 11390
 c: 11562
 c: 11476
 c: 11476
 c: 11476

Just weird, and a little intermittent.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you need to add some diagnostic code to narrow down the problem. Is it the actual ADC causing the problem? Or is it downstream? Fake up the adc value at strategic points in the code and see if the problem presents it self.

Since you've got all those callbacks, this might suggest you have atomicity problems, however without seeing the code, this is just a guess. Callbacks from interrupts is not a real good strategy unless you're real careful to avoid such problems. The 'proper' way would be to use a RTOS and use its inter-process mechanisms.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The callbacks actually just set flags 8)

I have put dummy values in place of ADC measurements, and the result is constant and correct. I am really baffled by this.

 

I have gone through a bisection essentially, slowly adding code from the original working 'good' to see where the weirdness creeps in, and it really does/did seem to be just having the second ISR even an empty ISR!

 The second ISR from softuart does rather a lot of processing compared to the timer ISR, but still not heaps.

 

I am porting this project to Arduino or similar soon (still need this working so I can charge my car reliably in the meantime), can anyone recommend a good cross platform (i.e AVR, ESP32, STM32, etc) RTOS with a whole bunch of the driver work done and good peripheral support?

 

This one is driving me cracra!