Pages: 1 [2]   Go Down
Author Topic: Uneven respone to interrupt command  (Read 1503 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Faraday Member
**
Karma: 24
Posts: 3487
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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:
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
#else
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

#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);
#endif
 
// 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);
#endif

// without a delay, we seem to read from the wrong channel
//delay(1);

#if defined(ADCSRA) && defined(ADCL)
// start the conversion
sbi(ADCSRA, ADSC);

// 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;
#else
// we dont have an ADC, return 0
low  = 0;
high = 0;
#endif

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

The issue is this:
Code:
// 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".
Logged

Check out my experiments http://blog.blinkenlight.net

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 129
Posts: 8530
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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 smiley

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

0
Offline Offline
Full Member
***
Karma: 0
Posts: 173
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
...
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) {
    zzpcalc();
    do_calc = false;
  }

  external();

}

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?

______
Rob
Logged

South Texas
Offline Offline
Edison Member
*
Karma: 8
Posts: 1025
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 140
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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... smiley-confuse
Logged

Pages: 1 [2]   Go Up
Jump to: