Stopping interrupts (home easy)

Hi,

I've had my arduino for a week, and have got it controlling home easy devices, listening for home easy (HE) commands, communicating via MQTT to a server but I've run into an annoying problem!

I'm using the home easy code here - (breaking link as it's my first message http:..) code.google.com/p/homeeasyhacking/source/browse/#svn/trunk/Arduino

When the device receives home easy remote control messages, it sometime crashes, possibly because in the callback from the home easy receiver, I'm sending a MQTT message to the server, and some HE devices (like the motion detector) send 10-15 messages in quick succession, so I think it is stopping the MQTT message half way, leaving the thing in a weird state (i.e. it hangs, not running loop(), until another HE command is received, then it works as before).

I'm very new to interrupts, but think that I should try disabling the HE code when I've received a HE message, and enabling it at the end of it to guarantee only one thing will be processed at any one time. I've tried putting a simple lock in place, but it still crashes. Also tried cei()/sli() with no luck.

Can anyone tell me how to stop the HE receiver? I think the relevant bits of code are:

/**
 * Initialise the system.
 * 
 * Configure the interupt for the receiver.
 */
void HomeEasy::init()
{
      pinMode(interuptPin, INPUT);
      
      // disable PWM (default)
      TCCR1A = 0x00;
      
      // set prescaler to 1/8.  TCNT1 increments every 0.5 micro seconds
      // falling edge used as trigger
      TCCR1B = 0x02;
      
      // enable input capture interrupt for timer 1
      TIMSK1 = _BV(ICIE1);
}

and

/**
 * The interupt handler.
 * 
 * This is where the message is received and decoded.
 */
ISR(TIMER1_CAPT_vect)
{
      // reset counter
      TCNT1 = 0;
      
      // get value of input compare register, divide by two to get microseconds
      pulseWidth = (ICR1 / 2);

Thanks in advance, Ed

Perhaps the problem lies in what your interrupt service routine is doing. Would you post that?

The ISR is meant to be very brief. Basically, it should just set some global variable, and return.

The actual handling of that interrupt is then done in the loop() function, based on the value of the global variable. The loop function is interruptable. Your ISR may or may not be.

Ah, interesting, that could be it.

The routine is from the home easy project on google code, but copied here:

ISR(TIMER1_CAPT_vect)
{
      // reset counter
      TCNT1 = 0;
      
      // get value of input compare register, divide by two to get microseconds
      pulseWidth = (ICR1 / 2);
      
      if(bit_is_clear(TCCR1B, ICES1))
      {      // falling edge was detected, HIGH pulse end
            
            if(latchStage == 1 && pulseWidth > 230 && pulseWidth < 280)
            {      // advanced protocol latch
                  
                  latchStage = 2;
            }
            else if(latchStage == 3 && (pulseWidth < 150 || pulseWidth > 500))
            {      // advanced protocol data out of timing range
                  
                  latchStage = 0;
                  bitCount = 0;
                  
                  sender = 0;
                  recipient = 0;
            }
            else if(latchStage == 1)
            {      // simple protocol data
                  
                  bitCount++;
                  
                  if(pulseWidth > 320 && pulseWidth < 430)
                  {
                        bit = 0;
                  }
                  else if(pulseWidth > 1030 && pulseWidth < 1150 && bitCount % 2 == 0)
                  {
                        bit = 0x08;
                  }
                  else
                  {      // start over if the low pulse was out of range
                        
                        latchStage = 0;
                        bitCount = 0;
                        
                        sender = 0;
                        recipient = 0;
                  }
                  
                  if(bitCount % 2 == 0)
                  {
                        if(bitCount < 9)
                        {
                              sender >>= 1;
                              sender |= bit;
                        }
                        else if(bitCount < 17)
                        {
                              recipient >>= 1;
                              recipient |= bit;
                        }
                        else
                        {
                              command >>= 1;
                              command |= bit;
                        }
                  }
                  
                  if(bitCount == 25)
                  {      // message is complete
                        
                        if(command == 14 || command == 6)
                        {
                              if(HomeEasy::simpleProtocolHandler != NULL)
                              {      HomeEasy::simpleProtocolHandler((int)sender, recipient, (command == 14));
                              }
                        }
                        
                        latchStage = 0;
                        bitCount = 0;
                        
                        sender = 0;
                        recipient = 0;
                  }
            }
      }
      else
      {      // raising edge was detected, LOW pulse end
            
            if(latchStage == 0 && pulseWidth > 9480 && pulseWidth < 11500)
            {      // pause between messages
            
                  latchStage = 1;
            }
            else if(latchStage == 2 && pulseWidth > 2550 && pulseWidth < 2750)
            {      // advanced protocol latch
                  
                  latchStage = 3;
            }
            else if(latchStage == 3)
            {      // advanced protocol data
                  
                  if(pulseWidth > 200 && pulseWidth < 365)
                  {
                        bit = 0;
                  }
                  else if(pulseWidth > 1000 && pulseWidth < 1360)
                  {
                        bit = 1;
                  }
                  else
                  {      // start over if the low pulse was out of range
                        latchStage = 0;
                        bitCount = 0;
                        
                        sender = 0;
                        recipient = 0;
                  }
                  
                  if(bitCount % 2 == 1)
                  {
                        if((prevBit ^ bit) == 0)
                        {      // must be either 01 or 10, cannot be 00 or 11
                              
                              latchStage = 0;
                              bitCount = -1;
                        }
                        else if(bitCount < 53)
                        {      // first 26 data bits
                              
                              sender <<= 1;
                              sender |= prevBit;
                        }
                        else if(bitCount == 53)
                        {      // 26th data bit
                              
                              group = prevBit;
                        }
                        else if(bitCount == 55)
                        {      // 27th data bit
                              
                              command = prevBit;
                        }
                        else
                        {      // last 4 data bits
                              
                              recipient <<= 1;
                              recipient |= prevBit;
                        }
                  }
                  
                  prevBit = bit;
                  bitCount++;
                  
                  if(bitCount == 64)
                  {      // message is complete
                        
                        if(HomeEasy::advancedProtocolHandler != NULL)
                        {      HomeEasy::advancedProtocolHandler(sender, recipient, (bool)command, group);
                        }
                        
                        sender = 0;
                        recipient = 0;
                        
                        latchStage = 0;
                        bitCount = 0;
                  }
            }
      }
      
      // toggle bit value to trigger on the other edge
      TCCR1B ^= _BV(ICES1);
}

There is a non-interrupt version on the playground, which takes its time to get through the loop (and therefore means incoming MQTT messages are delayed) - would you suggest I experiment with that version instead?

Thanks for your reply - much appreciated! I’m a Java developer, haven’t touched C or embedded systems before this, so this is all very new!!

Ed

With the exception of the calls to HomeEasy::simpleProtocolHandler and/or HomeEasy::advancedProtocolHandler, nothing in that ISR appears to take long to execute. I have no idea what these functions do, or whether there are even any handlers registered that would need to be called.

I suppose I'd try the non-interrupt version. Perhaps the Arduino is simply not fast enough to handle the speed at which the interrupts arrive.

Ah, the advanced handler does nothing, but I've registered a simple handler in my code that gets called by the code above. In my simple handler, I make and send a MQTT message, which would take time.

I guess I could make some kind of queue of messages, and append to that queue in the simple handler, then in the loop() I could pull messages out of the queue and do the MQTT sending there. If only Java was supported, queues would be easy!!

Cheers, Ed