Go Down

Topic: Uneven respone to interrupt command (Read 2932 times) previous topic - next topic



1) Analog read with a prescaler set to 16: 104 microseconds (and I have two of them)

The Arduino implementation of Analog Read is blocking.

Code: [Select]

int analogRead(uint8_t pin)
uint8_t low, high;

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#elif defined(__AVR_ATmega32U4__)
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#elif defined(__AVR_ATmega1284__)
if (pin >= 24) pin -= 24; // allow for channel or pin numbers
if (pin >= 14) pin -= 14; // allow for channel or pin numbers

#if defined(__AVR_ATmega32U4__)
pin = analogPinToChannel(pin);
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#elif defined(ADCSRB) && defined(MUX5)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
// set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits).  this also sets ADLAR (left-adjust result)
// to 0 (the default).
#if defined(ADMUX)
ADMUX = (analog_reference << 6) | (pin & 0x07);

// without a delay, we seem to read from the wrong channel

#if defined(ADCSRA) && defined(ADCL)
// start the conversion

// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));

// we have to read ADCL first; doing so locks both ADCL
// and ADCH until ADCH is read.  reading ADCL second would
// cause the results of each conversion to be discarded,
// as ADCL and ADCH would be locked when it completed.
low  = ADCL;
high = ADCH;
// we dont have an ADC, return 0
low  = 0;
high = 0;

// combine the two bytes
return (high << 8) | low;

The issue is this:
Code: [Select]

// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));

In your situation I would have rolled my own non blocking Analog Read funtion. Of course this implies that the whole code is implemented "state engine style".
Check out my experiments http://blog.blinkenlight.net


1) Analog read with a prescaler set to 16: 104 microseconds (and I have two of them)
2) LCD write with 4bit: takes more than 20 microseconds as well

Both single functions are far to slow to "wait" for the trigger

You do them after the pulse, as far as I can see you have nearly 5mS, you could spell check War and Peace in that time :)

Your psuedo code still uses attachInterrupt() right away you are behind the 8 ball with regard to latency and jitter. It never puts pin13 low and "jumps" to calculate_only_once_after_interrupt which you really can't (or shouldn't) do in C.

Am I correct in saying that the width of the pulse doesn't matter? That seems to be the case because you invoke that huge calculate function from inside the ISR.

I think you are doing the same as I did but still using interrupts and it's the interrupts that are the root of the problem.

Rob Gray aka the GRAYnomad www.robgray.com


Yes I see.

//THIS interrupt should be disabled inside the ISR, to prevent multiple calls to the ISR. You should not use millis() & micros() from an ISR

Code: [Select]
ISR (INT0_vect) {

 mi = micros();
 PORTB != (1 << PB5);
 microshigh2 = micros();
 deltamicros = microshigh2-microshigh1;
 PORTB &= ~(1 << PB5);
  // never call an large function from an ISR, set a flag and call it from loop()
 do_calc = true;

void setup() {

void loop() {

 if (do_calc) {
   do_calc = false;



You are using micros() which IIRC in turn needs timer0 to be running and that will cause some jitter for the reasons we stated above.
It may also be worth disabling the timer0 interrupt and getting your micros information directly from the timer hardware. But I haven't delved deeply into your logic so understand what's needed.

NOTE: Why is deltamicros a float, expecting fractional values?



If you want the best repeatability you need to turn off all other interrupts. Times and Serial all use interrupts and can affect response time to an incoming interrupt. You also have to consider what instructions might be executing. What is the longest time for any instruction a- that will make for your worst case response time. If another interrupt is executing - that will be your longest response time.


Dear all,
the essence I am reading is (and please correct me if I am wrong):

  • Change the analoge reading method (posted by Udo Klein). Sounds feasible although I need to regret that I do not have ANY clue regarding lines like "ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);". I need to read and learn!

  • Do not use any other interrupts beside the "ignite" one. No micros(), no millis(). Although this might be correct, I do not know how to establish a variable time delay on microseconds base to change ignition retard... :~

Go Up