The main.cpp program below demonstrates a simple way to interface with the MMA8452 accelerometer. The function reads in the acceleration data in the X, Y, and Z directions and displays them through a serial com port on a PC. The Putty Output figure below shows the output of the accelerometer using Putty. The program also dims or brightens the mbed LEDs 1-3 based on whether or not they are at 'level'( 0 Gs) or above respectively. The video below previews the code in action.
Fork of MMA8452_Test by
main.cpp
- Committer:
- ashleymills
- Date:
- 2014-03-07
- Revision:
- 6:e3100f66ed6a
- Parent:
- 5:756f9b157319
- Child:
- 8:46eab8a51f91
File content as of revision 6:e3100f66ed6a:
#include "mbed.h" #include "MMA8452.h" DigitalOut myled(LED1); Serial pc(USBTX,USBRX); #define LOG(...) pc.printf(__VA_ARGS__); pc.printf("\r\n"); #define LOGX(...) pc.printf(__VA_ARGS__); void printByte(char b) { LOG("%d%d%d%d%d%d%d%d", (b&0x80)>>7, (b&0x40)>>6, (b&0x20)>>5, (b&0x10)>>4, (b&0x08)>>3, (b&0x04)>>2, (b&0x02)>>1, (b&0x01) ); } enum SampleType { SAMPLE_RAW=0, SAMPLE_COUNT, SAMPLE_GRAVITY }; void sampleTypeToString(SampleType t, char *dst) { switch(t) { case SAMPLE_RAW: sprintf(dst,"SAMPLE_RAW"); break; case SAMPLE_COUNT: sprintf(dst,"SAMPLE_COUNT"); break; case SAMPLE_GRAVITY: sprintf(dst,"SAMPLE_GRAVITY"); break; }; } int testSampleTaking(MMA8452 *acc, int nsamples, SampleType sampleType) { int samples = 0; int bufLen = 6; // buffers for multi and single raw sampling char bufferMulti[6]; char bufferSingle[6]; memset(&bufferMulti,0x00,bufLen); memset(&bufferSingle,0x00,bufLen); // variables for multi and single count sampling int xCountM = 0, yCountM = 0, zCountM = 0; int xCountS = 0, yCountS = 0, zCountS = 0; // variables for multi and single gravity sampling double xGravityM = 0, yGravityM = 0, zGravityM = 0; double xGravityS = 0, yGravityS = 0, zGravityS = 0; // keep track of errors int error = 0; // mismatches between multi and single read calls are inevitable // since the MMA8452 has an internal sampling mechanism which is // not synchronous to this test routine. At low internal sampling // rates, these mismatches should be rare, so keep track to // check that this is sane int mismatchCount = 0; // take samples while(samples<nsamples) { // wait for device to be ready if(!acc->isXYZReady()) { wait(0.01); continue; } switch(sampleType) { case SAMPLE_RAW: // read raw data via multi and single calls memset(&bufferMulti,0x00,bufLen); memset(&bufferSingle,0x00,bufLen); error = 0; error += acc->readXYZRaw((char*)&bufferMulti); error += acc->readXRaw((char*)&bufferSingle[0]); error += acc->readYRaw((char*)&bufferSingle[2]); error += acc->readZRaw((char*)&bufferSingle[4]); if(error) { LOG("Error reading raw accelerometer data. Fail."); return false; } // compare multi and single samples for equivalence // note that this is bound to fail for high data rates if(acc->getBitDepth()==MMA8452::BIT_DEPTH_12) { if(memcmp(bufferMulti,bufferSingle,bufLen)) { LOG("Multi and single sampling mismatch"); LOG("Multi: %x %x %x %x %x %x", bufferMulti[0],bufferMulti[1], bufferMulti[2],bufferMulti[3], bufferMulti[4],bufferMulti[5] ); LOG("Single: %x %x %x %x %x %x", bufferSingle[0],bufferSingle[1], bufferSingle[2],bufferSingle[3], bufferSingle[4],bufferSingle[5] ); mismatchCount++; } LOG("12bit raw sample %d/%d: %x %x %x %x %x %x", samples,nsamples, bufferMulti[0],bufferMulti[1], bufferMulti[2],bufferMulti[3], bufferMulti[4],bufferMulti[5] ); } else { if(bufferMulti[0]!=bufferSingle[0]|| bufferMulti[1]!=bufferSingle[2]|| bufferMulti[2]!=bufferSingle[4]) { LOG("Multi and single sampling mismatch"); mismatchCount++; } LOG("8 bit raw sample %d/%d: %x %x %x", samples,nsamples, bufferMulti[0],bufferMulti[1],bufferMulti[2] ); } break; case SAMPLE_COUNT: error = 0; error += acc->readXYZCounts(&xCountM,&yCountM,&zCountM); error += acc->readXCount(&xCountS); error += acc->readYCount(&yCountS); error += acc->readZCount(&zCountS); if(error) { LOG("Error reading signed counts. Fail."); break; } // check for equivlance (note this fails sometimes but this is expected) if(xCountS!=xCountM || yCountS!=yCountM || zCountS!=zCountM) { LOG("Multi and single sampling mismatch"); mismatchCount++; } LOG("Count sample %d/%d: %d %d %d",samples,nsamples,xCountM,yCountM,zCountM); break; case SAMPLE_GRAVITY: error = 0; error += acc->readXYZGravity(&xGravityM,&yGravityM,&zGravityM); error += acc->readXGravity(&xGravityS); error += acc->readYGravity(&yGravityS); error += acc->readZGravity(&zGravityS); if(error) { LOG("Error reading gravities. Fail."); break; } if(xGravityS!=xGravityM || yGravityS!=yGravityM || zGravityS!=zGravityM) { LOG("Multi and single sampling mismatch"); mismatchCount++; } LOG("Gravity sample %d/%d: %lf %lf %lf",samples,nsamples,xGravityM,yGravityM,zGravityM); break; } samples++; } LOG("Mismatches between single and multi-byte reads %d/%d (mismatches are to be expected)",mismatchCount,nsamples); return true; } int sampleMMA8452Raw(MMA8452 *acc, int nsamples) { int samples = 0; int bufLen = 6; char buffer[6]; memset(&buffer,0x00,bufLen); while(samples<nsamples) { if(!acc->isXYZReady()) { wait(0.01); continue; } memset(&buffer,0x00,bufLen); acc->readXYZRaw(buffer); LOGX("Sample %d of %d: ",samples,nsamples); for(int i=0; i<bufLen; i++) { LOGX("%.2x ",buffer[i]); } LOG(" "); samples++; } return true; } int sampleMMA8452Counts(MMA8452 *acc, int nsamples) { int samples = 0; int bufLen = 6; char buffer[6]; int x = 0, y = 0, z = 0; memset(&buffer,0x00,bufLen); while(samples<nsamples) { if(!acc->isXYZReady()) { wait(0.01); continue; } memset(&buffer,0x00,bufLen); if(acc->readXYZCounts(&x,&y,&z)) { LOG("Error reading sample"); break; } LOG("Sample %d of %d: %d, %d, %d",samples,nsamples,x,y,z); samples++; } return true; } int sampleMMA8452Gravities(MMA8452 *acc, int nsamples) { int samples = 0; int bufLen = 6; char buffer[6]; double x = 0, y = 0, z = 0; memset(&buffer,0x00,bufLen); while(samples<nsamples) { if(!acc->isXYZReady()) { wait(0.01); continue; } memset(&buffer,0x00,bufLen); if(acc->readXYZGravity(&x,&y,&z)) { LOG("Error reading sample"); break; } LOG("Sample %d of %d: %lf, %lf, %lf",samples,nsamples,x,y,z); samples++; } return true; } void bitDepthToString(MMA8452::BitDepth d, char *dst) { switch(d) { case MMA8452::BIT_DEPTH_12: sprintf(dst,"BIT_DEPTH_12"); break; case MMA8452::BIT_DEPTH_8: sprintf(dst,"BIT_DEPTH_8"); break; } } void dynamicRangeToString(MMA8452::DynamicRange r, char *dst) { switch(r) { case MMA8452::DYNAMIC_RANGE_2G: sprintf(dst,"DYNAMIC_RANGE_2G"); break; case MMA8452::DYNAMIC_RANGE_4G: sprintf(dst,"DYNAMIC_RANGE_4G"); break; case MMA8452::DYNAMIC_RANGE_8G: sprintf(dst,"DYNAMIC_RANGE_8G"); break; } } void dataRateToString(MMA8452::DataRateHz r, char *dst) { switch(r) { case MMA8452::RATE_800: sprintf(dst,"RATE_800"); break; case MMA8452::RATE_400: sprintf(dst,"RATE_400"); break; case MMA8452::RATE_200: sprintf(dst,"RATE_200"); break; case MMA8452::RATE_100: sprintf(dst,"RATE_100"); break; case MMA8452::RATE_50: sprintf(dst,"RATE_50"); break; case MMA8452::RATE_12_5: sprintf(dst,"RATE_12_5"); break; case MMA8452::RATE_6_25: sprintf(dst,"RATE_6_25"); break; case MMA8452::RATE_1_563: sprintf(dst,"RATE_1_563"); break; } } int test() { MMA8452 acc(p28, p27, 40000); acc.debugRegister(MMA8452_CTRL_REG_1); LOG("Entering standby"); if(acc.standby()) { LOG("Error putting MMA8452 in standby"); return false; } acc.debugRegister(MMA8452_CTRL_REG_1); LOG("Activating MMA8452"); if(acc.activate()) { LOG("Error activating MMA8452"); return false; } char devID = 0; if(acc.getDeviceID(&devID)) { LOG("Error getting device ID"); return false; } LOG("DeviceID: 0x%x",devID); if(devID!=0x2a) { LOG("Error, fetched device ID: 0x%x does not match expected 0x2a",devID); return false; } else { LOG("Device ID OK"); } // test setting dynamic range MMA8452::DynamicRange setRange = MMA8452::DYNAMIC_RANGE_UNKNOWN; MMA8452::DynamicRange readRange = MMA8452::DYNAMIC_RANGE_UNKNOWN; for(int i=0; i<=(int)MMA8452::DYNAMIC_RANGE_8G; i++) { setRange = (MMA8452::DynamicRange)i; if(acc.setDynamicRange(setRange)) { LOG("Error setting dynamic range. Failing."); return false; } readRange = acc.getDynamicRange(); if(readRange!=setRange) { LOG("Read dynamic range: 0x%x does not match set: 0x%x",readRange,setRange); return false; } LOG("Success on dynamic range %d",i); } // test setting data rate for(int i=0; i<=(int)MMA8452::RATE_1_563; i++) { if(acc.setDataRate((MMA8452::DataRateHz)i)) { LOG("Error setting data rate. Failing."); return false; } if(acc.getDataRate()!=(MMA8452::DataRateHz)i) { LOG("Read data rate: 0x%x does not match set: 0x%x",acc.getDataRate(),(MMA8452::DataRateHz)i); return false; } LOG("Success on data rate %d",i); } char depthString[32], rangeString[32], rateString[32], sampleTypeString[32]; // draw some samples at each bit depth, rate, and dynamic range for(int depth=0; depth<=(int)MMA8452::BIT_DEPTH_8; depth++) { bitDepthToString((MMA8452::BitDepth)depth,(char*)&depthString); LOG("Setting bit depth to %s",depthString); if(acc.setBitDepth((MMA8452::BitDepth)depth)) { LOG("Error setting bit depth to %s. Fail.",depthString); return false; } for(int range=0; range<=(int)MMA8452::DYNAMIC_RANGE_8G; range++) { dynamicRangeToString((MMA8452::DynamicRange)range,(char*)&rangeString); LOG("Setting dynamic range to %s",rangeString); if(acc.setDynamicRange((MMA8452::DynamicRange)range)) { LOG("Error setting dynamic range to %s. Fail.",rangeString); return false; } for(int rate=0; rate<=(int)MMA8452::RATE_1_563; rate++) { dataRateToString((MMA8452::DataRateHz)rate,(char*)&rateString); LOG("Setting data rate to %s",rateString); if(acc.setDataRate((MMA8452::DataRateHz)rate)) { LOG("Error setting data rate to %s",rateString); return false; } // take samples for(int sampleType=0; sampleType<=(int)SAMPLE_GRAVITY; sampleType++) { sampleTypeToString((SampleType)sampleType,sampleTypeString); LOG("Setting sample type to %s",sampleTypeString); if(testSampleTaking(&acc, 10, (SampleType)sampleType)!=true) { LOG("Sample taking failed for %s, %s, %s, %s",sampleTypeString,depthString,rangeString,rateString); return false; } } } } } LOG("Samping gravities for interactive examination"); if(acc.setBitDepth(MMA8452::BIT_DEPTH_8)) { LOG("Error setting bit depth. Fail."); return false; } if(acc.setDynamicRange(MMA8452::DYNAMIC_RANGE_4G)) { LOG("Error setting dynamic range. Fail."); return false; } if(acc.setDataRate(MMA8452::RATE_100)) { LOG("Error setting data rate. Fail"); return false; } if(sampleMMA8452Gravities(&acc,1000)!=true) { LOG("Sampling gravities failed"); return false; } return true; } void loop() { while(1) { wait(1); } } void u16d(uint16_t n) { int shift = 16; uint16_t mask = 0x8000; while(--shift>=0) { LOGX("%d",(n&mask)>>shift); mask >>= 1; } LOG(" "); } int eightBitToSigned(char *buf) { return (int8_t)*buf; } int twelveBitToSigned(char *buf) { //LOG("Doing twos complement conversion for 0x%x 0x%x",buf[0],buf[1]); // cheat by using the int16_t internal type // all we need to do is convert to little-endian format and shift right int16_t x = 0; ((char*)&x)[1] = buf[0]; ((char*)&x)[0] = buf[1]; // note this only works because the below is an arithmetic right shift return x>>4; // for reference, here is the full conversion, in case you port this somewhere where the above won't work /* uint16_t number = 0x0000; //u16d(number); int negative = false; // bit depth 12, is spread over two bytes // put it into a uint16_t for easy manipulation number |= (buf[0]<<8); number |= buf[1]; // if this is a negative number take the twos complement if(number&0x8000) { negative = true; // flip all bits (doesn't matter about lower 4 bits) number ^= 0xFFFF; // add 1 (but do so in a way that deals with overflow and respects our current leftwise shift) number += 0x0010; } // shifting down the result by 4 bits gives us the absolute number number >>= 4; int result = number; if(negative) { result *= -1; } return result; */ } int twosCompTest() { // 12 bits of number gives 2048 steps int16_t i = -2047; while(1) { //LOG("number: %d",i); //u16d(number); uint16_t shiftedNumber = i<<4; //LOG("shifted:"); //u16d(shiftedNumber); // ARM is little endian whereas 12 bit 2's comp rep is big endian uint16_t flippedNumber = 0x0000; //LOG("switching bytes"); //u16d(flippedNumber); ((char*)&flippedNumber)[0] = ((char*)&shiftedNumber)[1]; //u16d(flippedNumber); ((char*)&flippedNumber)[1] = ((char*)&shiftedNumber)[0]; //u16d(flippedNumber); int value = twelveBitToSigned((char*)&flippedNumber); //LOG("%d converts to %d",i,value); if(i!=value) { return false; } if(i==2047) { break; } i++; } int8_t n = -127; while(1) { int value = eightBitToSigned((char*)&n); //LOG("%d converts to %d",n,value); if(n!=value) { return false; } if(n==127) { break; } n++; } return true; } int main() { pc.baud(115200); LOG("Begin"); LOG("Executing twos complement test"); if(!twosCompTest()) { LOG("Twos complement test failed"); loop(); } LOG("Twos complement test passed"); LOG("Executing MMA8452 tests"); if(!test()) { LOG("MMA8452 test failed."); loop(); } LOG("MMA8452 test passed"); LOG("All tests passed"); loop(); }