unsigned long conditionally truncated to byte

I am sampling a digital pin on an Arduino Uno to capture a serial data frame. The frame is 26 bits long (including the start and stop bits) so I am storing it in an unsigned long. The problem is that it is getting truncated to 8 bits. The issue appears to be in the ISR that adds the bits to the UL. I need to invert the bit as it is read from the digital pin to get the correct result. If I do not invert it, the value does not get truncated and it works as I thought it would. When I do invert it, then it gets truncated.

Here is the code that works as I expected and keeps the 32 bit value.

//Global
volatile unsigned long rxFrame; //this is the raw unprocessed frame

ISR(TIMER1_COMPA_vect) {
  byte rxNewBit = PIND & B00001000; //Get input pin status
  rxNewBit = rxNewBit>>3; //Shift bit to position 0
  //rxNewBit ^= 0x01UL;
  rxFrame += (rxNewBit<<rxIndex); //Add to frame
  if (rxIndex == 31) {
   rxIndex = 0;
   frameToProcess = true;
   TCCR1C &= ~B10000000; //Turn off force output compare for channel A
   TIMSK1 &= ~B00000010; //Turn off output compare match interupt enable
   recievingFrame = false;
  }
  else {
  rxIndex ++; //Increment index position
  OCR1A = rxTime[rxIndex]; //Set Output compare register to next value
  }
}

When I print rxFrame in the serial monitor I get this:

Here is Frame 11111110000000000000000100101010

Which is correct other than it needs to be inverted. So if I un comment the exclusive or statement in the interrupt I get this:

Here is Frame 1111110

Even if I change the data type of newBit in the interrupt to unsigned long, my result is only a byte.

What am I doing incorrectly?

Thanks in advance!

Please post the code you think should work, not the code that you know can't work. Also post your entire sketch, not just a snippet.

Sorry about that. I maybe didn't make it clear that if I un comment the third line down in the ISR (rxNewBit ^= 0x01UL;) the code no longer works.

So if I run this code:

//Global
volatile unsigned long rxFrame; //this is the raw unprocessed frame

ISR(TIMER1_COMPA_vect) {
  byte rxNewBit = PIND & B00001000; //Get input pin status
  rxNewBit = rxNewBit>>3; //Shift bit to position 0
  rxNewBit ^= 0x01UL;
  rxFrame += (rxNewBit<<rxIndex); //Add to frame
  if (rxIndex == 31) {
   rxIndex = 0;
   frameToProcess = true;
   TCCR1C &= ~B10000000; //Turn off force output compare for channel A
   TIMSK1 &= ~B00000010; //Turn off output compare match interupt enable
   recievingFrame = false;
  }
  else {
  rxIndex ++; //Increment index position
  OCR1A = rxTime[rxIndex]; //Set Output compare register to next value
  }
}

I get this:

Here is Frame 1111110

I need all 32 bits of the unsigned long, but it is truncated down to 8.

Here is my code in its entirety:

const byte rxPin = 3; //output from sensor terminal three connected through NPN transistor. Pin 3 is interupt 1. Use PIND & (1<<rxPin) (or PIND & B00001000) to read status
const byte txPin = 4; //output from Arduino to send serial frames. Set and clear pin with bitSet(PORTD, txPin) and bitClear(PORTD, txPin)

boolean okToStartFrame;
boolean recievingFrame;

unsigned int sensorData [3]; //Stores incoming sensor data. 1 is temp, 2 is moisture 1 (frame type 2) 3 is moisture 2 (frame type 3)
unsigned int sensorDataAge[3]; //Age of last reading
unsigned int rxFrameErrors; //counter to incrememnt when a frame error is encountered

volatile boolean frameToProcess; //toggle this on when a new frame has been recieved
volatile unsigned int rxTime [] = {876,2628,4380,6132,7884,9636,11388,13140,14892,16644,18396,20148,21900,23652,25404,27156,28908,30660,32412,34164,35916,37668,39420,41172,42924,44676,46428,48180,49932,51684,53436,55188};
volatile byte rxIndex = 0; //Index that is incremented with each bit recieved
volatile unsigned long rxFrame; //this is the raw unprocessed frame as recieved from sensor
void setup() {
Serial.begin (9600); //Debug serial
pinMode (rxPin, INPUT);
//digitalWrite (rxPin, HIGH); //turn on pullup resistor
EICRA |= B0001000; //Configure external interupt 1 to FALLING
SREG |= B10000000; //Global interupts enable (same as sei()?)
TCCR1B |= (1<<CS10); //Set prescaler for 1
//TCCR1C &= ~B10000000; //Added for debug Turn off force output compare for channel A
//TIMSK1 &= ~B00000010; //Added for debug Turn off output compare match interupt enable
Serial.println("Starting up...");
}

//Add code to check if rx pin has stayed high for frame reset time before enabling okToStartFrame the first time
void loop() {
  unsigned long currentMillis = millis();
  unsigned long lastFrameRecievedTime; //Last time a frame was received. Reset when frame is sent to process. Use to check for enabling of pin interupt.
  const unsigned long frameResetTime = 25; //time for line to be idle before being able to recieve a new frame.
  if (!okToStartFrame) {
    if (currentMillis - lastFrameRecievedTime > frameResetTime) {
      okToStartFrame = true;
      EIFR |= B00000010; //Clear interupt 1 flag in case it is on.
      EIMSK |= B00000010; // Enable interupt 1
      Serial.print("Interupt 1 is now enabled. Current time is ");
      Serial.println(millis());
    }
  }
  if (frameToProcess) {
    Serial.println("Now calling process frame function...");
    processFrame();
    lastFrameRecievedTime = millis();
    okToStartFrame = false;
  }
}
void processFrame() {
  //rxFrame = ~rxFrame;
  Serial.print("Here is Frame ");
  Serial.println(rxFrame, BIN);
  unsigned long frameCheck = rxFrame &= 0xFE0001F9; //This hex number is equivalent to B11111110000000000000000111111001
  Serial.print("Here is frameCheck");
  Serial.println(frameCheck, BIN);
  if (frameCheck != 0x2000001) { //0x2000001 is equivalent to B10000000000000000000000001 which is the start and stop bit only.
    rxFrameErrors++; //Frame error
    Serial.print("Frame error. Error counter is ");
    Serial.println(rxFrameErrors);
  }
  else {
    byte address = (rxFrame &= 0x6)>>1; //0x6 is B110 and masks the two address bits and then shifts them one place to the right to remove the start bit
    Serial.print("Frame received from address ");
    Serial.println(address);
    sensorData[address] = (rxFrame &= 0x1FFFE00)>>9; // 0x1FFFE00 is equivalent to B1111111111111111000000000 which masks all except 16 data bits.
    Serial.print("Sensor data recieved is ");
    Serial.println(sensorData[address]);
    sensorDataAge[address] = millis();
  }
  frameToProcess = false;
}
ISR(INT1_vect) { //This is called when a start bit is detected
  unsigned char sreg;
  recievingFrame = true;
  EIMSK &= ~B00000011; //Disable interupt 1
  /*sreg = SREG;    // Save global interrupt flag
  cli();  // Disable interrupts                      //not sure if this is needed
  TCNT1 = 0; //Reset timer1 to zero 
  SREG = sreg;// Restore global*/
  TCNT1 = 0; //Reset timer1 to zero
  OCR1A = rxTime[rxIndex]; //Set Output compare register to first value in array
  TCCR1C |= B10000000; //Force output compare for channel A enabled
  TIMSK1 |= B00000010; //Output compare A match interupt enable TIFR1.OCFA flag is set and ISR fires when compare matches
  //Serial.println("In INT1");
}

ISR(TIMER1_COMPA_vect) {
  byte rxNewBit = PIND & B00001000; //Get input pin status
  rxNewBit = rxNewBit>>3; //Shift bit to position 0
  rxNewBit ^= 0x01UL;
  rxFrame += (rxNewBit<<rxIndex); //Add to frame
  if (rxIndex == 31) {
   rxIndex = 0;
   frameToProcess = true;
   TCCR1C &= ~B10000000; //Turn off force output compare for channel A
   TIMSK1 &= ~B00000010; //Turn off output compare match interrupt enable
   recievingFrame = false;
  }
  else {
  rxIndex ++; //Increment index position
  OCR1A = rxTime[rxIndex]; //Set Output compare register to next value
  }
}

How do you know that it is truncated? You do realize that leading zeros are supressed, right?

I should have caught that. Thank you!