Interrupt handlers?

Where can I find the rules to what one can and can't do with Interrupt handlers? Because I can't make the silly things work at all. I'd post the code but its not on this machine.

Thanks!

-jim lee

I think the only rule is don't call any Serial methods. There is a high probability your program will deadlock.

There is a list of things you should and shouldn't do: 1. Don't call delay (and its ilk); 2. Shared data should be volatile; 3. Shared data should be protect with a critical section; 4. Don't take too long; 5. Don't write to the EEPROM; etcetera.

These may help...

http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
https://www.google.com/search?q=avr+interrupts

Can the volatile globals and the handler calls be declared in a .cpp file? I know the Arduino gets kind weird about .cpp files.

-jim lee

jimLee:
Can the volatile globals and the handler calls be declared in a .cpp file? I know the Arduino gets kind weird about .cpp files.

-jim lee

from http://arduino.cc/en/Hacking/BuildProcess

A sketch can contain multiple files (tabs). To manage them, click on the right-facing arrow just above the scroll bar near the top of the environment. Tabs have one of four extensions: no extension, .c, .cpp, or .h (if you provide any other extension, the period will be converted to an underscore). When your sketch is compiled, all tabs with no extension are concatenated together to form the "main sketch file". Tabs with .c or .cpp extensions are compiled separately. To use tabs with a .h extension, you need to #include it (using "double quotes" not ).

jimLee:
Can the volatile globals and the handler calls be declared in a .cpp file?

Yes.

jimLee:
I know the Arduino gets kind weird about .cpp files.

Example? All the libraries are done as .cpp files.

Example? For one it ignores #includes of .h files for accessing libraries in .cpp files. It can't open a .cpp file unless its in the same folder and on a tab. All of these things make me think its has some odd behavior to .cpp files.

-jim lee

What I think they have done is avoid needing either make files, or "projects" which a lot of other development systems do. Either one tells the system which files form part of your "project" and thus need to be compiled.

Instead, you just add tabs and put the files in your project into it. Or, as a shortcut, simply copy the .cpp and .h files into your folder, and then open the main .pde/.ino file. It then throws all the other files into separate tabs. Pretty simple really.

So really, the project is "whatever is in that folder". Perhaps you could use more flexibility for big projects, but it's simple.

A similar concept applies to the #include files for libraries needed in your project. Again, it avoids having to set up project files to say "use libraries X, Y and Z".

Try some of the other development tools and your eyes start glazing over as they talk about all the preliminary steps you need to go through (set up projects, etc.) before you even start coding.

I understand how complex it is to get a "normal" development system up and running the first time. I hated it for my entire time as s-ware engineer. Never got used to in fact. These Arduino people did a great job of making the IDE a snap for a beginner to use. But I also know they bent some rules and pulled a little hocus-pocus in the background to achieve this. I just worry I'm treading in a magical grey area with this interrupt stuff is all.

-jim lee

jimLee:
I just worry I'm treading in a magical grey area with this interrupt stuff is all.

Not at all.

Because I can't make the silly things work at all.

Post your code when you can. It's nothing to do with the development environment I assure you.

Ok here's the code..

sonarObj.h

#ifndef sonarObj_h
#define sonarObj_h

#include "timeObj.h"

class sonarObj {

public:
  sonarObj(int inPin);

  void idle(void);
  float distanceCm(void);

private:
  void attachHandler(void);
  void detachHandler(void);
  bool pulseDone(void);
  long readTime();
  void clearTime(void);
  
  int           state;
  int           pin;
  float         result;
  timeObj*      endTimer;
};

#endif

And sonerObj.cpp

#include "sonarObj.h"
#include "mapper.h"

#define pulseOut   5     //µs
#define pulseMin   0.115 //ms
#define pulseMax   18.5  //ms
#define minCm      2     //cm
#define maxCm      300   //cm

#define delaayTime 0.2   //ms

// *****************************
// Glue code for intrupt handling

volatile unsigned long time0H;
volatile unsigned long time0L;
volatile unsigned long time1H;
volatile unsigned long time1L;


void handler0() { 
  if (time0H==0) {
    time0H = micros();
  } 
  else if(time0L==0) {
    time0L = micros();
  }
  else return;
}


void handler1() { 
  if (!time1H) {
    time1H = micros();
  } 
  else if(!time1L) {
    time1L = micros();
  }
}


//*****************************
// The sonarObj stuff..

mapper cmMapper(pulseMin,pulseMax,minCm,maxCm);

enum { 
  ready, waitforPulse, waitToComplete };

sonarObj::sonarObj(int inPin) {

  endTimer = new timeObj(delaayTime);
  pin = inPin;
  result = 0;  // default value.
  state = ready;
}


// Start timing the incoming pulse..
void sonarObj::attachHandler(void) {

  switch (pin) {
  case 2 :
    attachInterrupt(0, handler0, CHANGE);
    break;
  case 3 :
    attachInterrupt(1, handler0, CHANGE);
    break;
  }
}


// We are done with the handler now. Let it go.
void sonarObj::detachHandler(void) {

  switch (pin) {
  case 2 :
    detachInterrupt(0);
    break;
  case 3 :
    detachInterrupt(1);
    break;
  }
}


// If we have non zero values the pulse has passed.
bool  sonarObj::pulseDone(void) {

  switch (pin) {
  case 2 :
    return time0L && time0H;  // When both are non zero we are done.
  case 3 :
    return time1L && time1H;
  }
}  


// How long wa the pulse?
long sonarObj::readTime(void) {

  switch (pin) {
  case 2 :
    return time0L - time0H;
  case 3 :
    return time1L - time1H;
  }
}


// Set them both to zero.
void sonarObj::clearTime(void) {

  switch (pin) {
  case 2 :
    Serial.print("T0H : "); 
    Serial.println(time0H);
    Serial.print("T0L : "); 
    Serial.println(time0L);
    Serial.print("Dif : "); 
    Serial.println(time0L - time0H);
    Serial.println(" ");
    time0L = 0;
    time0H = 0;
    break;
  case 3 :
    time1L = 0;
    time1H = 0;
    break;
  }
}


void sonarObj::idle(void) {

  if (pin==2||pin==3) {
    switch (state) {
    case ready :
      clearTime();                    // Set both to zero as flags..
      pinMode(pin, OUTPUT);           // Pulse out to start hardware.
      digitalWrite(pin, HIGH);
      delayMicroseconds(pulseOut);
      digitalWrite(pin, LOW);
      pinMode(pin, INPUT);            // I assume this is ok, we are going to listen.
      attachHandler();                // Hook up the handler.
      state = waitforPulse;           // All done, let the processor do other things.
      break;
    case waitforPulse :
      if (pulseDone()) {                     // Checks to see if both are non zero.
        detachHandler();                     // Maybe someone else needs this.
        endTimer->start();                   // we need to wait for a minimum settle time.
        if (readTime()>0)  {                 // If the numbers make sense, do the calculations.
          result = cmMapper.Map(readTime());
        }
        state = waitToComplete;              // Wait for the settling timer expires.
      }
      break;
    case waitToComplete :
      if (endTimer->ding())                  // If the timer dings, we are done. Reset state and go.
        state = ready;
      break;
    }
  }
}


float sonarObj::distanceCm(void) {

  return result;
}

I know its got to be something I'm just not seeing. It just returns the same number over and over. Changes now and them but pretty much the same.

-jim lee

It just returns the same number over and over.

"It"? clearTime?

What number?

T0H : 4496088
T0L : 4496856
Dif : 768
 
T0H : 4541848
T0L : 4542616
Dif : 768
 
T0H : 4587608
T0L : 4588372
Dif : 764

-jim lee

What is connected to the pin?

I've got a parallax sonar deal. You send it a 5µs pulse and it returns, on the same line a pulse that you can time for distance measurements.

My sketch..

#include "sonarObj.h"

sonarObj sonar(2);
float distance = -1;
void setup(){
  Serial.begin(9600);
}

void loop() {


  float temp;

  sonar.idle();
  temp = sonar.distanceCm();
  if (temp!=distance) {
    distance = temp;
    Serial.print("distace : "); Serial.println(distance);
  }
  Serial.print("distace : "); Serial.println(distance);
  /*
   unsigned long duration;
   
   pinMode(2, OUTPUT);
   digitalWrite(2, HIGH);
   delayMicroseconds(5);
   digitalWrite(2, LOW);
   pinMode(2, INPUT);
   duration = pulseIn(2,HIGH);
   Serial.println(duration);
   */
}

Comment out the sonarObj stuff, de-comment the pulse width stuff and it works great. But that's all the poor thing can do. It spends all its time waiting for the pulses to time.

-jim lee

This?
http://www.parallax.com/tabid/768/ProductID/92/Default.aspx

yes..

I can't tell for certain but I believe this is the problem...

Shortcut to the potential solution...

Coding Badly may well be right. And I should point out this would have happened whether or not you use the Arduino IDE. It is a behaviour of the processor. One that is mentioned in my page about interrupts:

Wow! Never would have come up with that. Thanks! I bet that is whats going on. I'll try it tomorrow.

Thanks again!

-jim lee