Go Down

Topic: Need help troubleshooting variable not getting set by interrupt (Read 1 time) previous topic - next topic

MatCat

This is running on an ATTINY84.  I am stumped in that the statusMask variable is not ever being set by the main loop, though I know for a fact the interrupts are being called because a diagnostic LED tell's me so, I have ran the diagnostic LED in every conceivable spot, and the one place I never get a response is inside of if (statusMask), which makes no sense because the interrupt does indeed get triggered, any ideas?


Code: [Select]
#include <PinChangeInterrupt.h>


/*
MatCat Airplane Lighting Contoller

PWM and I2C connectivity to drive 3 channels of lighting.

This code is open source and free to be used by whomever
for non-commercial purposes.  Please keep the proper
copyright when distributing this code, thank you!
*/


// PWM Outputs
unsigned int headlights = 2;
unsigned int navlights = 3;
unsigned int floodlights = 4;

// PWM Inputs
unsigned int headlightInput = 5;
unsigned int navlightInput = 6;
unsigned int floodlightInput = 7;

// Operational Parameters
int strobeFrequency = 1000;        // 1 second between pulses
int strobeLength = 30;             // 30ms strobe length
int strobeBreak = 50;              // 50ms break between fast pulses

volatile byte headlightLevel = 0;           // Output buffer level for headlights
volatile byte navlightLevel = 0;            // Output buffer level for navlights
volatile byte floodlightLevel = 0;          // Output buffer level for floodlights
volatile uint16_t oldHeadLevel = 0;          // Old lighting level
volatile uint16_t oldNavLevel = 0;
volatile uint16_t oldFloodLevel = 0;
volatile uint8_t oldHeadOut = 0;
volatile uint8_t oldNavOut = 0;
volatile uint8_t oldFloodOut = 0;
// Bit mask for keeping track of whats going on

static uint8_t HEADLIGHT_FLAG = 1;
static uint8_t NAVLIGHT_FLAG = 2;
static uint8_t FLOODLIGHT_FLAG = 4;
static uint8_t I2C_FLAG = 8;                 // Indicates the usage of I2C over PWM

uint8_t hasBound = 0;               // A variable to keep track of being bound

volatile uint8_t statusMask;        // This is the actual mask variable

// Timers to keep track of pulse widths
volatile unsigned long headlightTimer = 0;
volatile unsigned long navlightTimer = 0;
volatile unsigned long floodlightTimer = 0;

// Timers for other operations
unsigned long lastStrobeTime;       // Used for strobe timing
unsigned long lastFrameTime;        // When was the last PWM frame?
unsigned int secondTime;           // A special timer for measuring a second 
uint8_t rxFrequency = 0;                // Rated in HZ, normal is 50
uint16_t frameCount = 0;            // Count of frames per second

void setup()  {
  // Setup inputs
  pinMode(headlightInput, INPUT);
  pinMode(navlightInput, INPUT);
  pinMode(floodlightInput, INPUT);

  // Setup outputs
  pinMode(headlights,OUTPUT);
  pinMode(navlights,OUTPUT);
  pinMode(floodlights,OUTPUT);

  // Setup a few variables
  lastStrobeTime = millis();
  secondTime = millis();
  // Let's do a little init. routine
  strobeLight(headlights,160,100);
  delay(100);
  strobeLight(navlights,160,100);
  delay(100);
  strobeLight(floodlights,160,100);
  delay(500);
  for (int a = 0; a < 5; a++) {
    strobeAll(160,160,160,30);
    delay(100);
  }
  // Ok now let's setup some interupts
  attachPcInterrupt(headlightInput,headlightOn,RISING);
  attachPcInterrupt(headlightInput,headlightOff,FALLING);
  attachPcInterrupt(navlightInput,navlightOn,RISING);
  attachPcInterrupt(navlightInput,navlightOff,FALLING);
  attachPcInterrupt(floodlightInput,floodlightOn,RISING);
  attachPcInterrupt(floodlightInput,floodlightOff,FALLING);

}

void loop()  {
  // Setup some local variables for reading
  // the values set by interrupts. 
  static uint16_t headLevel = 0;   
  static uint16_t navLevel = 0;
  static uint16_t floodLevel = 0;
  static uint8_t flagmask = 0;
  static uint8_t updateFlag = 0;   
  static long frameTime = 0;
  static uint8_t secondFlag = 0;
  static uint8_t strobeFlag = 0;
 
  if (statusMask) {
    // We need to update what's going on.
    noInterrupts();
    flagmask = statusMask;
    if (flagmask & HEADLIGHT_FLAG) {
     
      // Headlights have been updated
      if (headlightLevel != oldHeadLevel) {
        headLevel = headlightLevel;
        oldHeadLevel = headLevel;
        updateFlag |= HEADLIGHT_FLAG;
      }
      // Let's capture the frame time for calculation later
      frameTime = (uint16_t)(micros() - lastFrameTime);
      lastFrameTime = micros();
    }
    if (flagmask & NAVLIGHT_FLAG) {
      // Navs have been updated
      if (navlightLevel != oldNavLevel) {
        navLevel = navlightLevel;
        oldNavLevel = navLevel;
        updateFlag |= NAVLIGHT_FLAG;
      }
    }
    if (flagmask & FLOODLIGHT_FLAG) {
      // Floods have been updated
      if (floodlightLevel != oldFloodLevel) {
        floodLevel = floodlightLevel;
        oldFloodLevel = floodLevel;
        updateFlag |= FLOODLIGHT_FLAG;
      }
    }
 
    // We need to clear the status flags from interrupts
    statusMask = 0;
   
    interrupts();
  }
  // Let's handle the second timer.
  if ((millis() - secondTime) >= 1000) {
    // A second has passed, reset the timer
    secondTime = millis();
    secondFlag = 1;
  }
 
  // Let's handle the strobe timer.
  if ((millis() - lastStrobeTime) >= strobeFrequency) {
    // We need to do a strobe...
    lastStrobeTime = millis();
    strobeFlag = 1;
  }
  if (frameTime > 0) {
    // It's a new frame from the RX, let's do some math
    frameCount++;  // Add to frame count
    if (secondFlag) {
      // The frameCount variable will tell us, should be close to 50
      rxFrequency = frameCount;
      frameCount = 0;  // Reset it
    }
  }
 
  if (rxFrequency > 30) {
    // We probably have a valid PWM signal, so consider it bound
    hasBound = 1;
  } else {
    // Either we are not bound or lost bound...
    hasBound = 0;
  }
 
  if (!hasBound) {
    // We need to continue looking for an input...
    strobeLight(headlights,50,15);      // Indicate looking for PWM
    delay(50);   
    strobeLight(navlights,50,15);      // Indicate looking for PWM
    delay(50);   
    strobeLight(navlights,50,15);      // Indicate looking for PWM
    delay(50);   
    strobeLight(navlights,50,15);      // Indicate looking for PWM
    delay(50);   
    strobeLight(navlights,50,15);      // Indicate looking for PWM
    delay(500);
  } else {
    // We are bound, so let's do what needs to be done
    // First we need to see if any of the levels need to be adjusted...
    uint8_t headOut = oldHeadOut;
    uint8_t navOut = oldNavOut;
    uint8_t floodOut = oldFloodOut;

    // Before we output the the power, we need to check if we have to strobe...
    if (strobeFlag) {
      // We need to do some strobing before actually setting the output
      strobeAll(255,255,255,strobeLength);
    }
    if (updateFlag & HEADLIGHT_FLAG) {
      // We need to change output of headlights
      headOut = map(headLevel,1000,2000,0,255);
      if (headOut < 40) {headOut = 0;}
      if (headOut > 210) {headOut = 255;}
      oldHeadOut = headOut;
      analogWrite(headlights,headOut);
    }
    if (updateFlag & NAVLIGHT_FLAG) {
      // We need to change output of headlights
      navOut = map(navLevel,1000,2000,0,255);
      if (navOut < 40) {navOut = 0;}
      if (navOut > 210) {navOut = 255;}
      oldNavOut = navOut;
      analogWrite(navlights,navOut);
    }
    if (updateFlag & FLOODLIGHT_FLAG) {
      // We need to change output of headlights
      floodOut = map(floodLevel,1000,2000,0,255);
      if (floodOut < 40) {floodOut = 0;}
      if (floodOut > 210) {floodOut = 255;}
      oldFloodOut = floodOut;
      analogWrite(floodlights,floodOut);
    }
  }
}
void strobeXTimes(int x) {
  for (int a = 0;a < x;a++) {
    strobeLight(headlights,255,20);
    delay(50);
  }
}
void strobeAll(byte valuehead,byte valuenav, byte valueflood, int duration) {
  analogWrite(headlights,valuehead);
  analogWrite(navlights,valuenav);
  analogWrite(floodlights,valueflood);
  delay(duration);
  analogWrite(headlights,oldHeadOut);
  analogWrite(navlights,oldNavOut);
  analogWrite(floodlights,oldFloodOut);
}

void strobeLight(int light,byte value,int duration) {
  analogWrite(light,value);
  delay(duration);
  if (light == headlights) {
      analogWrite(light,oldHeadOut);
  }
  if (light == navlights) {
      analogWrite(light,oldNavOut);
  }
  if (light == floodlights) {
      analogWrite(light,oldFloodOut);
}
}

void headlightOn() {
  // Do something when we have headlight PWM coming in...
  headlightTimer = micros();   
}
void headlightOff() {
  // Do something when we have headlight PWM Pulse finished...
  headlightLevel = (uint16_t)(micros() - headlightTimer);
  statusMask |= HEADLIGHT_FLAG;
}
void navlightOn() {
  navlightTimer = micros();
}
void navlightOff() {
  navlightLevel = (uint16_t)(micros() - navlightTimer);
  statusMask |= NAVLIGHT_FLAG;
}
void floodlightOn() {
  floodlightTimer = micros();
}
void floodlightOff() {
  floodlightLevel = (uint16_t)(micros() - floodlightTimer);
  statusMask |= FLOODLIGHT_FLAG;
}

holmes4

1. Try working with just one think (say headlight) at a time. Get that running then extend it to cover the other things.

2. I don't think you can do this
Code: [Select]

attachPcInterrupt(headlightInput,headlightOn,RISING);
attachPcInterrupt(headlightInput,headlightOff,FALLING);



Does the documentation explicitly say that you can have more that one interrupt attached to a pin AT THE SAME time?

Mark

MatCat


1. Try working with just one think (say headlight) at a time. Get that running then extend it to cover the other things.

2. I don't think you can do this
Code: [Select]

attachPcInterrupt(headlightInput,headlightOn,RISING);
attachPcInterrupt(headlightInput,headlightOff,FALLING);



Does the documentation explicitly say that you can have more that one interrupt attached to a pin AT THE SAME time?

Mark

The library does it in software, in all actuality pin change is called when there is a pin change on ANY of the pins on that port, and the library takes the ISR and does internal tracking of rising/falling and calls the appropriate callback.  The callbacks themselves are working fine, one thing I found was changing UINT references to UNSIGNED INT and such made a difference and the main loop started to see something in the variable, then my RC TX battery died so now it's charging and I can't diagnose farther until then :).

DuaneB

Hi,
   The PinChangeInt library masks pins at a hardware level so its not just any pin on a port, the hardware will not generate the interrupt if the individual pin is not configured for pin change interrupts.

I would suggest having a single interrupt using CHANGE rather than one for rising and one for falling, this is because internally the library will loop over your interrupts looking for the correct handler, more interrupts = more loops.

To keep this fast, you can use PCInt::pinState instead of using digitalRead to figure out whether it is a rising or falling edge i.e. -

This might even fix your issue.

Code: [Select]

void calcThrottlePulse()
{
  if(PCintPort::pinState)
  {
    ulThrottleInStart = micros();
  }
  else
  {
    unThrottleInShared = (micros() - ulThrottleInStart);
    bUpdateFlagsShared |= THROTTLE_FLAG;
  }
}


More optimisations here -

http://rcarduino.blogspot.com/2012/11/how-to-read-rc-channels-rcarduinofastlib.html

Duane B

rcarduino.blogspot.com

holmes4


Go Up