TinyWire.h on ATtiny45 and Wire library together

Hi Arduino Community

I hope you can help me, Im stuck and i don't know what I've done! Maybe it will stand out to you where I have gone wrong?

I had a tacho working perfectly on an ATTiny45, using the TinyWire.h library.
I was reading it with the standard wire library and getting back RPM values that I had validated as perfect with an external tacho.
I have 32 teeth on an encoder wheel connected to a generator which interrupt an led and light sensitive diode. Its one of those modules pre packaged to stand off each other so you can run an interruption between like an encoder wheel.
The output also runs through a SN74LS14 HEX SCHMITT-TRIGGER INVERTER chip to help ensure nice square pulses without bouncing

The output from my master reader last week read something like:

LowByte, HighByte, RPMValue
0, 11, 11
0, 22, 22
0, 15, 15
0, 7, 7

However now it reads:
0, 11, 2816
0, 22, 5632
0, 15, 3840
0, 7, 1792

The third value supposedly being the integer representation of my RPM, however 0 high byte + 11 low byte I think should be and 11 not a 2816

And I don't think I changed anything! I even took old copies back from time machine and they look identical!
Clearly I have changed something and I barely understood the code to begin with so Ive been back over the sources and even started from scratch but I cant get the correct values back again:(
I have no idea where these big values are coming from, is it in the rejoining of the bytes that the code is incorrect?

Slave / Tinywire.h on At Tiny

/* AT Tiny RPM Encode
 * Ben Harper April 2014
 * LED on digital pin 3 (ATtiny Pin 2)
 * IR Encoder input onto digital pin 4 (ATtiny Pin 3)     
 *
                                        ________ 
 (PCINT5/RESET/ADC0/dW) PB5         - 1|        |8 - VCC
 (PCINT3/XTAL1/CLKI/OC1B/ADC3) PB3  - 2|   AT   |7 - PB2 (SCK/USCK/SCL/ADC1/T0/INT0/PCINT2)
 PCINT4/XTAL2/CLKO/OC1B/ADC2) PB4   - 3|  TINY  |6 - PB1 (MISO/DO/AIN1/OC0B/OC1A/PCINT1)
 GND                                - 4|  45/85 |5 - 5PB0 (MOSI/DI/SDA/AIN0/OC0A/OC1A/AREF/PCINT0)
                                        -------- 
In Arduino Terminology:
AT45Pin1 = Arduino's Reset
AT45Pin2 = Arduino's Digital 3 & Analog 3
AT45Pin3 = Arduino's Digital 4 & Analog 2
AT45Pin4 = Arduino's Gnd
AT45Pin5 = Arduino's Digital 0 (PWM) & MOSI
AT45Pin6 = Arduino's Digital 1 (PWM) & MISO
AT45Pin7 = Arduino's Digital 2 & Analog 1 & SCK
AT45Pin8 = Arduino's VCC

Good Info For ATTiny45 With Arduino: http://highlowtech.org/?p=1695
*/
 
#include "TinyWireS.h"   //For I2C on ATTiny's 
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

#define I2C_SLAVE_ADDRESS 0x4 // Address of this device as an I2C slave
int pinLed = 3;  //Led to show encoder is reading. toggles on and off every interupt (removed this functionality)
int EncoderPin = 4; //Tacho TTL input - Connected to IR Encoder Sensor

volatile int pulses;  //Integer to count Encoder Pulses
unsigned long currentTime;
unsigned long loopTime;
int RPM = 0;

//boolean changed = true;
boolean firstbyte = true;
byte lowByte;
byte highByte;


void setup(){
  //pinMode(pinLed,OUTPUT);
  pinMode(4,INPUT);
  sbi(IMSK,PCIE); // Turn on Pin Change interrupt
  sbi(PCMSK,PCINT4); //Specify Which pins are affected by the interrupt
  TinyWireS.begin(I2C_SLAVE_ADDRESS); // join i2c network
  TinyWireS.onRequest(requestEvent); // Sets Functional to call on I2C request
}

void loop()
{

  currentTime = millis();
  if(currentTime >= (loopTime + 500)){  
    loopTime = currentTime;  // Updates loopTime
   // RPM = pulses*120/4/32;  //.5 Second upadtes  *120 to get up to 60seconds, /32 ridges in encoder, /4 ticks per ridge 
   //or simplified = *.9375
   RPM = pulses*.9375;
   pulses=0;
  }
  TinyWireS_stop_check(); //Not Sure what this does but Tiny I2C doesnt seem to like not having it
}



ISR(PCINT0_vect) {
  pulses++;
  //digitalWrite(pinLed,!digitalRead(pinLed));
}

void requestEvent()
{
    if(firstbyte == true){     // on the first byte we do the math
    lowByte = (byte) (RPM & 0xff);
    highByte = (byte) ((RPM >> 8) & 0xff);
    
    firstbyte = false;      //so next time though we send the next byte    
    TinyWireS.send(lowByte);
  } 
  else {
    TinyWireS.send(highByte);
    firstbyte = true;
  }
}

Master Reader on Mega2560

#include <Wire.h>
volatile int value =0;

void setup()
{ 
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  Serial.println("begin:"); 
}

void loop()
{
  
  byte hb;
  byte lb;
  Wire.requestFrom(4,1); 
  if (Wire.available()) {
    //    hb=Wire.read();
    lb=Wire.read();
  }
  Wire.requestFrom(4,1); 
  if (Wire.available()) {
    hb=Wire.read();
  }
  value =  ((hb<<8)+lb);
  Serial.print(lb);
  Serial.print(", ");
  Serial.print(hb);
  Serial.print(", ");
  Serial.println (value); 
  delay(1000);

  
}

Ill admit I have been playing with the code, I need to use a separate line for the ATTiny Slave as I have 4 other i2C native chips on the I2C line as well and for some reason the ATTiny doesnt play well with the others. I found I could use softi2c to get around it and hopefully come back to solve this problem later. But I should see why my current situation no longer works before trying to port over to SoftI2c as a master. I failed to understand how to use the softI2c so far as it seems to need to ask for data from a specific address and I dont know how to code that in the Attiny slaves TinyWire library. Not to fussed about working that out this minute but just to admit that I may have changed something and that be the reason its all broke!

Ive gotten by for months learning Arduino and AVR and associated electronic theory just reading previous posts without having to bother anyone but I just need fresh eyes here because I am stumped!
Cheers if you can give me any pointers, or for just reading this far!

Benny

Oh dear,

I just spun the generator slowly by hand and saw
0,2,512

The 512 is clearly 2 * 256 and so it appears Im mixing up the low and high byte.
I notice that Im Serial.print 'ing the low byte first in my code so the 0 is low byte and 2 is high, which is 2 * 256 not 2 * 1!

It appears that the main issue was having commented out the second Wire.requestFrom(4,1); statement!
However, a really interesting error occurs, which probably did before and I hadn't noticed it.
Even though I am sending low byte back first from the Slave, and reading low byte first in the master, it seems that the master is associating them incorrectly. Furthermore it seems that the cycle is 1/2 a step behind and that in each loop the master receives first the previous readings high byte and thinks its the current low byte. and this is where the association of bytes is getting messed up.

See this data from master loop as the rpm is accelerating, at the point in bold where the high byte (which the master thinks and has labelled below as lowbyte not highbyte!) goes from 0 to 1 suggesting we just went past 256 rpm, the reading is 14 not 14 + 256. Its not until the next reading that the high byte (marked below as low byte, sorry) comes in to play.

LB:0, HB:151, RPM:151
LB:0, HB:202, RPM:202
LB:0, HB:231, RPM:231
LB:0, HB:246, RPM:246
LB:0, HB:14, RPM:14
LB:1, HB:25, RPM:281
LB:1, HB:40, RPM:296

I understand that its hard to follow when Im getting the bytes in the wrong order in my print statements but I cant simply change the code as its 1/2 a phase out and when I get it fixed then the first byte in will be the low byte as expected.

OK so seems I have sorted it myself.
I suppose I had a chance to organise my thoughts while posting here and it helped, even if no one replied:)

Turned out cleaner to request 2 bytes and loop while Wire.available with a flag to set first available data as lb and subsequent as hb.

void loop()
{
   boolean first = true;
  byte lb;
  byte hb;
  
   Wire.requestFrom(4,2);
   while (Wire.available()) 
   {
     if (first){lb = Wire.read(); first = false;}else {hb = Wire.read(); first = true;}
   }
     value =  ((hb<<8)+lb);
     Serial.println(value);
  delay(500);