Skewed Data from I2C Sensor - Did I fry my board?.....

Status
Not open for further replies.
Hello everyone,

I'm fairly new at this, having tinkered quite a bit, but never taking a full project from start to finish....

I need to detect a few strings vibrations (heavy metal strings) for which I bought the MMA8452Q accelerometer, and planning to use the teensy for simulating a string being plucked....

The sensor works beautifully on an Arduino (showing smooth, sensible data -- having worked with accelerometers before, I know what to expect)
Yet, when changing nothing in the sketch, and only changing the 4 wires (3.3v, GND, SCL, SDA) from the Arduino to the Teensy, I'm suddenly getting insensible data, only showing very low results 0.xxx to very high 15.9xxxx (which is double the expected range) and nothing in between these extremes for even small movements across all 3 axis........ In short, data that does not make sense, seems perhaps clipped.

You can see this data in the photo attached. as well as my wiring and the code I downloaded online....

I am using 2 pull-up resistors (5K as recommended here) .....

I'm wondering if this could be due to different I2C configurations between the Arduino (Mega) & Teensy 3.2 , or is the only logical possibility is damage to the hardware?....

What am I missing?..... H E L P !



Thanks,
Ariel
 

Attachments

  • Acc-Basic.ino
    2.9 KB · Views: 81
  • IMG_4833.jpg
    IMG_4833.jpg
    132.5 KB · Views: 120
  • IMG_4834.jpg
    IMG_4834.jpg
    88.4 KB · Views: 115
  • insensible-data.jpg
    insensible-data.jpg
    72.3 KB · Views: 110
Still stuck.... giving up .....

You think it's the pull-up resistors then?....


I'm really close to giving up , I've tried it already with 3 different Teensy's , 2 X 3.2 and 1 X 3.6 -- always the same weird data...
To reiterate, this works fine on an Arduino....
I think it worked yesterday for a few moments somehow, before returning to its odd behavior...

I'm really at a loss, I wanted to use the Teensy for its audio capabilities but truly have no idea how to proceed.....
 
Get rid of any resistors. Hook Teensy SDA and SCL to the breakout's SDA and SCL. Power with 3v3 and GND.

It's possible the library has some 8-bit processor data types incompatible with Teensy 32-bit data types, but I didn't see any in a quick review of library source.

You might try from the IDE the Examples > Wire > Scanner sketch and see if the scanner sees the I2C address of the breakout board.
 
Thanks man........ :)

I've tried omitting the pull-up resistors, to no avail..... Still the same weird freaking data I can't make sense of.

I have here 3 Teensy's and 4 sensors, all sensors work on Arduino, and I can't get any of the same results on the Teensy..
At least I know it's not a hardware/soldering issue....

thanks for the scanner sketch, that will surely come in handy within the next few days (it does find the device by the way... [it is showing the data ....])

Big Up!
 
your 5k resistors should go from sda to 3.3v and scl to 3.3v, then your breakout connects to the sda/scl line directly, not the vcc 3.3v side
 
Big Development....

your 5k resistors should go from sda to 3.3v and scl to 3.3v, then your breakout connects to the sda/scl line directly, not the vcc 3.3v side

Thanks again !

I just did that...

It did not solve the problem, yet, I found something very strange......

I've measured 3.3V comparing the 3.3Vout from Arduino with the GND, yet when I measure the 3.3Vin on the sensor with the sensor's GND, I am reading 5V........
Could this somehow be related to all the problems I'm having?

This I really don't get!.......

How is this possible?!

The I2C bus is somehow upping the voltage to 5V (If I disconnect sensor's SDA, SCL from arduilno's SDA, SCL -- voltage on sensor returns to normal --3.3V)
I found this out because I first measured the voltage on the sensor when fed by the Teensy, and it showed 2.9V , which made me think it could be a powering issue....

I guess I'll bring in tomorrow some analog sensors and be done with it....



Any help appreciated!
 
on arduino, it has built in pullups that drive it to 5volts, thats why, on teensy itll still be 3.3v with pullups..
 
The original sketch for UNO suggests 330 ohm in-line resistors for level shifting, but you'd still see 5v with meter on SDA or SCL
Code:
Hardware hookup:
  Arduino --------------- MMA8452Q Breakout
    3.3V  ---------------     3.3V
    GND   ---------------     GND
  SDA (A4) --\/330 Ohm\/--    SDA
  SCL (A5) --\/330 Ohm\/--    SCL

The MMA8452Q is a 3.3V max sensor, so you'll need to do some 
level-shifting between the Arduino and the breakout. Series
resistors on the SDA and SCL lines should do the trick.

with the teensy and the board powered at 3v3 and gnd, you should verify you are seeing 3.3v with meter on breakout's SDA or SCL. Though the fact that the Scanner sketch finds the device, suggests I2C should be working.
 
>>> only showing very low results 0.xxx to very high 15.9xxxx (which is double the expected range) and nothing in between these extremes for even small movements across all 3 axis........ In short

It seems your expected data should be in a range of +-8 and you are seeing a range of zero to 16? If so it would appear the sign of your data has been lost and has become the MSB of just a positive number. I suspect it happens in these calculations in the library, but I cannot say why without some investigation into the size of the short type on teensy.

Here maybe....
Code:
void MMA8452Q::read()
{
	byte rawData[6];  // x/y/z accel register data stored here

	readRegisters(OUT_X_MSB, rawData, 6);  // Read the six raw data registers into data array
	
	x = ((short)(rawData[0]<<8 | rawData[1])) >> 4;
	y = ((short)(rawData[2]<<8 | rawData[3])) >> 4;
	z = ((short)(rawData[4]<<8 | rawData[5])) >> 4;
	cx = (float) x / (float)(1<<11) * (float)(scale);
	cy = (float) y / (float)(1<<11) * (float)(scale);
	cz = (float) z / (float)(1<<11) * (float)(scale);
}
 
>>> only showing very low results 0.xxx to very high 15.9xxxx (which is double the expected range) and nothing in between these extremes for even small movements across all 3 axis........ In short

It seems your expected data should be in a range of +-8 and you are seeing a range of zero to 16? If so it would appear the sign of your data has been lost and has become the MSB of just a positive number. I suspect it happens in these calculations in the library, but I cannot say why without some investigation into the size of the short type on teensy.

Here maybe....
Code:
void MMA8452Q::read()
{
	byte rawData[6];  // x/y/z accel register data stored here

	readRegisters(OUT_X_MSB, rawData, 6);  // Read the six raw data registers into data array
	
	x = ((short)(rawData[0]<<8 | rawData[1])) >> 4;
	y = ((short)(rawData[2]<<8 | rawData[3])) >> 4;
	z = ((short)(rawData[4]<<8 | rawData[5])) >> 4;
	cx = (float) x / (float)(1<<11) * (float)(scale);
	cy = (float) y / (float)(1<<11) * (float)(scale);
	cz = (float) z / (float)(1<<11) * (float)(scale);
}


Hey Rcarr, big thanks to you and everyone who helped out and provided reference, I am so much smarter already.....

Yes, rcarr, I totally agree - what yoy are suggesting sounds very plausible.... I also thought that 0-16 is a -8 — +8 range with an offset , but as i said, all the data seems to be centered around the edges?..

Should I try to write my ownbinary decrypting function? How is it possible that the cpp file produces different results across different MCUs?

anyhow - thanks a lot - i think ill go for analog sensors forthis project to save the trouble but would definitely come back to this later.....

gratefully!!:))
A
 
One problem could be that denominations like "short", "unsigned int", etc. might look and behave differently on different platforms, i.e. depending on that platform's native support which is 8bit for the old AVR based Arduino stuff, 32bit for the modern Teensy 3.x and LC platforms, and 64bit for most PCs.

Many of the Arduino libraries are very poorly coded, their developers never anticipated the possible use on something more advanced than the outdated 8bit AVR platform. And thus, there are lots of ambiguities, especially when it comes to variable declarations (or to direct hardware register access but this is another problem).

But that can be easily fixed by going through the library's code and replacing the ambiguous declarations with the universally accepted and defined ones, like uint8_t, int16_t, *int32_t, and so on. In order to do so successfully, you'll have to go through the code line by line and try to understand which type and width is needed or required for each variable.
 
I don't have one of the breakout boards, so I can't properly test all theories. I did a quick review of the library looking for AVR vs ARM data-type problems, but haven't found any (yet). I did a test of data handling in MMA8452Q::read() on UNO and T3.2
Code:
void setup() {
 Serial.begin(9600); while(!Serial);
 delay(2000);
 short x;
 byte rawData[6];

 rawData[0] = 0x7f;
 rawData[1] = 0xf0;

 x = ((short)(rawData[0]<<8 | rawData[1])) >> 4;
 Serial.println(x); 
 float cx = (float) x / (float)(1<<11) * (float)(8);
 Serial.println(cx,3);
}

void loop() {
}
and the signed 12-bit numbers seems to be handled the same.

@ArielsAngels, in your sketch, you might print out accel.x, y, and z with Serial.println() in loop() and see how the values compare between Teensy and Arduino. (Don't use printAccels() or at least don't use the " , 3").

I presume the accelerator values are changing on the Teensy when you move the breakout board.
 
Last edited:
Don't give up now. You're almost at a solution. My suspicion is that a short is 32 bits on teensy. My teensy is packed away somewhere in a box from when I cleaned up for company. I will find it after breakfast and test that theory. In the meantime, you could edit the library .h and .cpp and replace all occurrences of the word 'short' with 'int16_t' and give that a try.
 
If you look on github for the library you see this function as

Code:
void MMA8452Q::read()
{
	byte rawData[6];  // x/y/z accel register data stored here

	readRegisters(OUT_X_MSB, rawData, 6);  // Read the six raw data registers into data array
	
	x = ((short)(rawData[0]<<8 | rawData[1])) >> 4;
	y = ((short)(rawData[2]<<8 | rawData[3])) >> 4;
	z = ((short)(rawData[4]<<8 | rawData[5])) >> 4;
	cx = (float) x / (float)(1<<11) * (float)(scale);
	cy = (float) y / (float)(1<<11) * (float)(scale);
	cz = (float) z / (float)(1<<11) * (float)(scale);
}

If you download the zipfile from the sparkfun site you see this function as:

Code:
void MMA8452Q::read()
{
	byte rawData[6];  // x/y/z accel register data stored here

	readRegisters(OUT_X_MSB, rawData, 6);  // Read the six raw data registers into data array
	
	x = (rawData[0]<<8 | rawData[1]) >> 4;
	y = (rawData[2]<<8 | rawData[3]) >> 4;
	z = (rawData[4]<<8 | rawData[5]) >> 4;
	cx = (float) x / (float)(1<<11) * (float)(scale);
	cy = (float) y / (float)(1<<11) * (float)(scale);
	cz = (float) z / (float)(1<<11) * (float)(scale);
}

So you can see that the casts to short are missing in the zipfile version. x, y and z are declared as int in the header file.

To the OP, download the library using the link to github on the sparkfun site and replace your current version of the library.
 
Do you have a link to the sparkfun zip file, all i find is the github stuff.

removing (short) from the test sketch in post #15 has no effect. both teensy and arduino give the same result with or without the cast. maybe there are other differences in the zip file.
 
ah, i found the link to zip version https://cdn.sparkfun.com/assets/learn_tutorials/2/4/9/SFE_MMA8452Q-library.zip
and looking at the sketch Acc-Basic.ino in post #1, it is apparent that the sketch is using SFE_MMA8452Q.h, which has x,y, z declared as int. the example in post #15 does get different numbers on teensy if x is declared int and there is no short cast. (for the OP: int on Arduino AVR is 16-bits, whereas int on teensy is 32-bits)

Sooo, as you suggest, using the github version of library and sample sketch is worth a try! good work
 
Last edited:
Wow wow wow !!
Big thanks to u all- rcarr - manitou - theremingenieur !!!
huge appreciation for the help thus far....

it all sounds very promising and id definitely give it a try / look into it / write my own function to read and decrypt the binary data...

maybe i could even apply the motion detection wih the binary data thinking of the bit distance between the last 1 and the MSB as a simplification of acceleration - this may work well for my application.

however, since this thing needs to be done by next sunday, and i still actually need to code a synth, conjure motion detection AND set the whole physical construction including a mini-controller , i’m gonna switch to analog accelerometers at this stage, using only two axis and a teensy 3.6 for the extra pins.....

so many thanks for everybody who helped out - ill post here when i have an update ....
 
Hey manitou, I find that interesting that you get different results depending upon the size of the destination variable. I wonder if that is one of those undefined behavior things in C. I just figured teensy would be doing all integer calculations in 32 bit and the cast to short would always be needed.

To the OP if you are still with us and still wondering why your data all hovers near zero or 16, I will see if I can explain:
The data is 2's compliment and read out in bytes. There are 12 bits and in byte form they look like sddd dddd and dddd 0000. The data is shifted as far to the left as possible. s is the sign bit.

The smallest movement in the positive direction will come out as 0000 0000 0001 0000. Shifted left 4 places 0000 0000 0000 0001. one. 1
The smallest movement in the negative direction will come out as 1111 1111 1111 0000. Shifted left 4 places 1111 1111 1111 1111. minus one. -1
If you loose the fact that the most significant bit, the s bit, is a sign bit and interpret that as a positive number, when you shift it left 4 places you get
0000 1111 1111 1111. That is 0xfff or 4095. When you divide that by 2048 and multiply by 8 you get 15.996. ( instead of -0.004 ).
 
Status
Not open for further replies.
Back
Top