A test program for the MMA8452 accelerometer

Dependencies:   MMA8452 mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "MMA8452.h"
00003 
00004 DigitalOut myled(LED1);
00005 
00006 Serial pc(USBTX,USBRX);
00007 
00008 #define LOG(...) pc.printf(__VA_ARGS__); pc.printf("\r\n");
00009 #define LOGX(...) pc.printf(__VA_ARGS__);
00010 
00011 void printByte(char b) {
00012    LOG("%d%d%d%d%d%d%d%d",
00013        (b&0x80)>>7,
00014        (b&0x40)>>6,
00015        (b&0x20)>>5,
00016        (b&0x10)>>4,
00017        (b&0x08)>>3,
00018        (b&0x04)>>2,
00019        (b&0x02)>>1,
00020        (b&0x01)
00021    );
00022 }
00023 
00024 enum SampleType {
00025    SAMPLE_RAW=0,
00026    SAMPLE_COUNT,
00027    SAMPLE_GRAVITY
00028 };
00029 
00030 void sampleTypeToString(SampleType t, char *dst) {
00031    switch(t) {
00032       case SAMPLE_RAW:
00033          sprintf(dst,"SAMPLE_RAW");
00034       break;
00035       case SAMPLE_COUNT:
00036          sprintf(dst,"SAMPLE_COUNT");
00037       break;
00038       case SAMPLE_GRAVITY:
00039          sprintf(dst,"SAMPLE_GRAVITY");
00040       break;
00041    };
00042 }
00043 
00044 int testSampleTaking(MMA8452 *acc, int nsamples, SampleType sampleType) {
00045    int samples = 0;
00046    int bufLen = 6;
00047    
00048    // buffers for multi and single raw sampling
00049    char bufferMulti[6];
00050    char bufferSingle[6];
00051    memset(&bufferMulti,0x00,bufLen);
00052    memset(&bufferSingle,0x00,bufLen);
00053    
00054    // variables for multi and single count sampling
00055    int xCountM = 0, yCountM = 0, zCountM = 0;
00056    int xCountS = 0, yCountS = 0, zCountS = 0;
00057    
00058    // variables for multi and single gravity sampling
00059    double xGravityM = 0, yGravityM = 0, zGravityM = 0;
00060    double xGravityS = 0, yGravityS = 0, zGravityS = 0;
00061    
00062    // keep track of errors
00063    int error = 0;
00064    // mismatches between multi and single read calls are inevitable
00065    // since the MMA8452 has an internal sampling mechanism which is
00066    // not synchronous to this test routine. At low internal sampling
00067    // rates, these mismatches should be rare, so keep track to
00068    // check that this is sane
00069    int mismatchCount = 0;
00070    
00071    // take samples
00072    while(samples<nsamples) {
00073       // wait for device to be ready
00074       if(!acc->isXYZReady()) {
00075          wait(0.01);
00076          continue;
00077       }
00078       
00079       switch(sampleType) {
00080          case SAMPLE_RAW:
00081             // read raw data via multi and single calls
00082             memset(&bufferMulti,0x00,bufLen);
00083             memset(&bufferSingle,0x00,bufLen);
00084             error = 0;
00085             error += acc->readXYZRaw((char*)&bufferMulti);
00086             error += acc->readXRaw((char*)&bufferSingle[0]);
00087             error += acc->readYRaw((char*)&bufferSingle[2]);
00088             error += acc->readZRaw((char*)&bufferSingle[4]);
00089             if(error) {
00090                LOG("Error reading raw accelerometer data. Fail.");
00091                return false;
00092             }
00093             // compare multi and single samples for equivalence
00094             // note that this is bound to fail for high data rates
00095             if(acc->getBitDepth()==MMA8452::BIT_DEPTH_12) {
00096                if(memcmp(bufferMulti,bufferSingle,bufLen)) {
00097                   LOG("Multi and single sampling mismatch");
00098                   LOG("Multi: %x %x %x %x %x %x",
00099                      bufferMulti[0],bufferMulti[1],
00100                      bufferMulti[2],bufferMulti[3],
00101                      bufferMulti[4],bufferMulti[5]
00102                   );
00103                   LOG("Single: %x %x %x %x %x %x",
00104                      bufferSingle[0],bufferSingle[1],
00105                      bufferSingle[2],bufferSingle[3],
00106                      bufferSingle[4],bufferSingle[5]
00107                   ); 
00108                   mismatchCount++;
00109                }
00110                LOG("12bit raw sample %d/%d: %x %x %x %x %x %x",
00111                   samples,nsamples,
00112                   bufferMulti[0],bufferMulti[1],
00113                   bufferMulti[2],bufferMulti[3],
00114                   bufferMulti[4],bufferMulti[5]
00115                );
00116             } else {
00117                if(bufferMulti[0]!=bufferSingle[0]||
00118                   bufferMulti[1]!=bufferSingle[2]||
00119                   bufferMulti[2]!=bufferSingle[4]) {
00120                   LOG("Multi and single sampling mismatch");
00121                   mismatchCount++;
00122                }
00123                LOG("8 bit raw sample %d/%d: %x %x %x",
00124                   samples,nsamples,
00125                   bufferMulti[0],bufferMulti[1],bufferMulti[2]
00126                );
00127             }
00128          break;
00129          case SAMPLE_COUNT:
00130             error = 0;
00131             error += acc->readXYZCounts(&xCountM,&yCountM,&zCountM);
00132             error += acc->readXCount(&xCountS);
00133             error += acc->readYCount(&yCountS);
00134             error += acc->readZCount(&zCountS);
00135             if(error) {
00136                LOG("Error reading signed counts. Fail.");
00137                break;
00138             }
00139             // check for equivlance (note this fails sometimes but this is expected)
00140             if(xCountS!=xCountM || yCountS!=yCountM || zCountS!=zCountM) {
00141                LOG("Multi and single sampling mismatch");
00142                mismatchCount++;
00143             }
00144             LOG("Count sample %d/%d: %d %d %d",samples,nsamples,xCountM,yCountM,zCountM);
00145          break;
00146          case SAMPLE_GRAVITY:
00147             error = 0;
00148             error += acc->readXYZGravity(&xGravityM,&yGravityM,&zGravityM);
00149             error += acc->readXGravity(&xGravityS);
00150             error += acc->readYGravity(&yGravityS);
00151             error += acc->readZGravity(&zGravityS);
00152             if(error) {
00153                LOG("Error reading gravities. Fail.");
00154                break;
00155             }
00156             if(xGravityS!=xGravityM || yGravityS!=yGravityM || zGravityS!=zGravityM) {
00157                LOG("Multi and single sampling mismatch");
00158                mismatchCount++;
00159             }
00160             LOG("Gravity sample %d/%d: %lf %lf %lf",samples,nsamples,xGravityM,yGravityM,zGravityM);
00161          break;
00162       }
00163       samples++;
00164    }
00165    LOG("Mismatches between single and multi-byte reads %d/%d (mismatches are to be expected)",mismatchCount,nsamples);
00166    return true;
00167 }
00168 
00169 int sampleMMA8452Raw(MMA8452 *acc, int nsamples) {
00170    int samples = 0;
00171    int bufLen = 6;
00172    char buffer[6];
00173    memset(&buffer,0x00,bufLen);
00174    while(samples<nsamples) {
00175       if(!acc->isXYZReady()) {
00176          wait(0.01);
00177          continue;
00178       }
00179       memset(&buffer,0x00,bufLen);
00180       acc->readXYZRaw(buffer);
00181       LOGX("Sample %d of %d: ",samples,nsamples);
00182       for(int i=0; i<bufLen; i++) {
00183          LOGX("%.2x ",buffer[i]);
00184       }
00185       LOG(" ");
00186       samples++;
00187    }
00188    return true;
00189 }
00190 
00191 int sampleMMA8452Counts(MMA8452 *acc, int nsamples) {
00192    int samples = 0;
00193    int bufLen = 6;
00194    char buffer[6];
00195    int x = 0, y = 0, z = 0;
00196    memset(&buffer,0x00,bufLen);
00197    while(samples<nsamples) {
00198       if(!acc->isXYZReady()) {
00199          wait(0.01);
00200          continue;
00201       }
00202       memset(&buffer,0x00,bufLen);
00203       if(acc->readXYZCounts(&x,&y,&z)) {
00204          LOG("Error reading sample");
00205          break;
00206       }
00207       LOG("Sample %d of %d: %d, %d, %d",samples,nsamples,x,y,z);
00208       samples++;
00209    }
00210    return true;
00211 }
00212 
00213 int sampleMMA8452Gravities(MMA8452 *acc, int nsamples) {
00214    int samples = 0;
00215    int bufLen = 6;
00216    char buffer[6];
00217    double x = 0, y = 0, z = 0;
00218    memset(&buffer,0x00,bufLen);
00219    while(samples<nsamples) {
00220       if(!acc->isXYZReady()) {
00221          wait(0.01);
00222          continue;
00223       }
00224       memset(&buffer,0x00,bufLen);
00225       if(acc->readXYZGravity(&x,&y,&z)) {
00226          LOG("Error reading sample");
00227          break;
00228       }
00229       LOG("Sample %d of %d: %lf, %lf, %lf",samples,nsamples,x,y,z);
00230       samples++;
00231    }
00232    return true;
00233 }
00234 
00235 void bitDepthToString(MMA8452::BitDepth d, char *dst) {
00236    switch(d) {
00237        case MMA8452::BIT_DEPTH_12:
00238           sprintf(dst,"BIT_DEPTH_12");
00239        break;
00240        case MMA8452::BIT_DEPTH_8:
00241           sprintf(dst,"BIT_DEPTH_8");
00242        break;
00243     }
00244 }
00245 
00246 void dynamicRangeToString(MMA8452::DynamicRange r, char *dst) {
00247    switch(r) {
00248       case MMA8452::DYNAMIC_RANGE_2G:
00249          sprintf(dst,"DYNAMIC_RANGE_2G");
00250       break;
00251       case MMA8452::DYNAMIC_RANGE_4G:
00252          sprintf(dst,"DYNAMIC_RANGE_4G");
00253       break;
00254       case MMA8452::DYNAMIC_RANGE_8G:
00255          sprintf(dst,"DYNAMIC_RANGE_8G");
00256       break;
00257    }
00258 }
00259 
00260 void dataRateToString(MMA8452::DataRateHz r, char *dst) {
00261    switch(r) {
00262        case MMA8452::RATE_800:
00263           sprintf(dst,"RATE_800");
00264        break;
00265        case MMA8452::RATE_400:
00266           sprintf(dst,"RATE_400");
00267        break;
00268        case MMA8452::RATE_200:
00269           sprintf(dst,"RATE_200");
00270        break;
00271        case MMA8452::RATE_100:
00272           sprintf(dst,"RATE_100");
00273        break;
00274        case MMA8452::RATE_50:
00275           sprintf(dst,"RATE_50");
00276        break;
00277        case MMA8452::RATE_12_5:
00278           sprintf(dst,"RATE_12_5");
00279        break;
00280        case MMA8452::RATE_6_25:
00281           sprintf(dst,"RATE_6_25");
00282        break;
00283        case MMA8452::RATE_1_563:
00284           sprintf(dst,"RATE_1_563");
00285        break;
00286     }
00287 }
00288 
00289 int test() {
00290     MMA8452 acc(p28, p27, 40000);
00291     
00292     acc.debugRegister(MMA8452_CTRL_REG_1);
00293     
00294     LOG("Entering standby");
00295     if(acc.standby()) {
00296        LOG("Error putting MMA8452 in standby");
00297        return false;
00298     }
00299     
00300     acc.debugRegister(MMA8452_CTRL_REG_1);
00301     
00302     LOG("Activating MMA8452");
00303     if(acc.activate()) {
00304        LOG("Error activating MMA8452");
00305        return false;
00306     }
00307     
00308     char devID = 0;
00309     if(acc.getDeviceID(&devID)) {
00310        LOG("Error getting device ID");
00311        return false;
00312     }
00313     LOG("DeviceID: 0x%x",devID);
00314     if(devID!=0x2a) {
00315        LOG("Error, fetched device ID: 0x%x does not match expected 0x2a",devID);
00316        return false;
00317     } else {
00318        LOG("Device ID OK");
00319     }
00320     
00321     // test setting dynamic range
00322     MMA8452::DynamicRange setRange = MMA8452::DYNAMIC_RANGE_UNKNOWN;
00323     MMA8452::DynamicRange readRange = MMA8452::DYNAMIC_RANGE_UNKNOWN;
00324     for(int i=0; i<=(int)MMA8452::DYNAMIC_RANGE_8G; i++) {
00325        setRange = (MMA8452::DynamicRange)i;
00326        if(acc.setDynamicRange(setRange)) {
00327           LOG("Error setting dynamic range. Failing.");
00328           return false;
00329        }
00330        readRange = acc.getDynamicRange();
00331        if(readRange!=setRange) {
00332           LOG("Read dynamic range: 0x%x does not match set: 0x%x",readRange,setRange);
00333           return false;
00334        }
00335        LOG("Success on dynamic range %d",i);
00336     }
00337     
00338     // test setting data rate
00339     for(int i=0; i<=(int)MMA8452::RATE_1_563; i++) {
00340        if(acc.setDataRate((MMA8452::DataRateHz)i)) {
00341           LOG("Error setting data rate. Failing.");
00342           return false;
00343        }
00344        if(acc.getDataRate()!=(MMA8452::DataRateHz)i) {
00345           LOG("Read data rate: 0x%x does not match set: 0x%x",acc.getDataRate(),(MMA8452::DataRateHz)i);
00346           return false;
00347        }
00348        LOG("Success on data rate %d",i);
00349     }
00350     
00351     char depthString[32], rangeString[32], rateString[32], sampleTypeString[32];
00352     // draw some samples at each bit depth, rate, and dynamic range
00353     for(int depth=0; depth<=(int)MMA8452::BIT_DEPTH_8; depth++) {
00354        bitDepthToString((MMA8452::BitDepth)depth,(char*)&depthString);
00355        LOG("Setting bit depth to %s",depthString);
00356        if(acc.setBitDepth((MMA8452::BitDepth)depth)) {
00357           LOG("Error setting bit depth to %s. Fail.",depthString);
00358           return false;
00359        }
00360        for(int range=0; range<=(int)MMA8452::DYNAMIC_RANGE_8G; range++) {
00361           dynamicRangeToString((MMA8452::DynamicRange)range,(char*)&rangeString);
00362           LOG("Setting dynamic range to %s",rangeString);
00363           if(acc.setDynamicRange((MMA8452::DynamicRange)range)) {
00364              LOG("Error setting dynamic range to %s. Fail.",rangeString);
00365              return false;
00366           }
00367           for(int rate=0; rate<=(int)MMA8452::RATE_1_563; rate++) {
00368              dataRateToString((MMA8452::DataRateHz)rate,(char*)&rateString);
00369              LOG("Setting data rate to %s",rateString);
00370              if(acc.setDataRate((MMA8452::DataRateHz)rate)) {
00371                 LOG("Error setting data rate to %s",rateString);
00372                 return false;
00373              }
00374              // take samples
00375              for(int sampleType=0; sampleType<=(int)SAMPLE_GRAVITY; sampleType++) {
00376                 sampleTypeToString((SampleType)sampleType,sampleTypeString);
00377                 LOG("Setting sample type to %s",sampleTypeString);
00378                 if(testSampleTaking(&acc, 10, (SampleType)sampleType)!=true) {
00379                   LOG("Sample taking failed for %s, %s, %s, %s",sampleTypeString,depthString,rangeString,rateString);
00380                   return false;
00381                 }
00382              }
00383           }
00384        }
00385     }
00386 
00387     LOG("Samping gravities for interactive examination");
00388     if(acc.setBitDepth(MMA8452::BIT_DEPTH_8)) {
00389        LOG("Error setting bit depth. Fail.");
00390        return false;
00391     }
00392     if(acc.setDynamicRange(MMA8452::DYNAMIC_RANGE_4G)) {
00393        LOG("Error setting dynamic range. Fail.");
00394        return false;
00395     }
00396     if(acc.setDataRate(MMA8452::RATE_100)) {
00397        LOG("Error setting data rate. Fail");
00398        return false;
00399     }
00400     if(sampleMMA8452Gravities(&acc,1000)!=true) {
00401        LOG("Sampling gravities failed");
00402        return false;
00403     }
00404 
00405     return true;
00406 }
00407 
00408 void loop() {
00409    while(1) {
00410       wait(1);
00411    }
00412 }
00413 
00414 void u16d(uint16_t n) {
00415    int shift = 16;
00416    uint16_t mask = 0x8000;
00417    while(--shift>=0) {
00418       LOGX("%d",(n&mask)>>shift);
00419       mask >>= 1;
00420    }
00421    LOG(" ");
00422 }
00423 
00424 int eightBitToSigned(char *buf) {
00425    return (int8_t)*buf;
00426 }
00427 
00428 int twelveBitToSigned(char *buf) {
00429    //LOG("Doing twos complement conversion for 0x%x 0x%x",buf[0],buf[1]);
00430    
00431    // cheat by using the int16_t internal type
00432    // all we need to do is convert to little-endian format and shift right
00433    int16_t x = 0;
00434    ((char*)&x)[1] = buf[0];
00435    ((char*)&x)[0] = buf[1];
00436    // note this only works because the below is an arithmetic right shift
00437    return x>>4; 
00438 
00439    // for reference, here is the full conversion, in case you port this somewhere where the above won't work
00440    /*
00441    uint16_t number = 0x0000;
00442    //u16d(number);
00443    int negative = false;
00444    
00445    // bit depth 12, is spread over two bytes
00446    // put it into a uint16_t for easy manipulation
00447    number |= (buf[0]<<8);
00448    number |= buf[1];
00449 
00450    // if this is a negative number take the twos complement
00451    if(number&0x8000) {
00452        negative = true;
00453        // flip all bits (doesn't matter about lower 4 bits)
00454        number ^= 0xFFFF;
00455 
00456        // add 1 (but do so in a way that deals with overflow and respects our current leftwise shift)
00457        number += 0x0010;
00458    }
00459    
00460    // shifting down the result by 4 bits gives us the absolute number
00461    number >>= 4;
00462 
00463    int result = number;
00464    if(negative) {
00465       result *= -1;
00466    }
00467    return result;
00468    */
00469 }
00470 
00471 int twosCompTest() {
00472     // 12 bits of number gives 2048 steps
00473     int16_t i = -2047;
00474     while(1) {
00475        //LOG("number: %d",i);
00476        //u16d(number);
00477        uint16_t shiftedNumber = i<<4;
00478        //LOG("shifted:");
00479        //u16d(shiftedNumber);
00480        // ARM is little endian whereas 12 bit 2's comp rep is big endian
00481        uint16_t flippedNumber = 0x0000;
00482        //LOG("switching bytes");
00483        //u16d(flippedNumber);
00484        ((char*)&flippedNumber)[0] = ((char*)&shiftedNumber)[1];
00485        
00486        //u16d(flippedNumber);
00487        ((char*)&flippedNumber)[1] = ((char*)&shiftedNumber)[0]; 
00488        
00489        //u16d(flippedNumber);
00490        int value = twelveBitToSigned((char*)&flippedNumber);
00491        //LOG("%d converts to %d",i,value);
00492        if(i!=value) {
00493           return false;
00494        }
00495        if(i==2047) {
00496           break;
00497        }
00498        i++;
00499     }
00500     
00501     int8_t n = -127;
00502     while(1) {
00503        int value = eightBitToSigned((char*)&n);
00504        //LOG("%d converts to %d",n,value);
00505        if(n!=value) {
00506           return false;
00507        }
00508        if(n==127) {
00509           break;
00510        }
00511        n++;
00512     }
00513  
00514     return true;
00515 }
00516 
00517 int main() {
00518     pc.baud(115200);
00519     LOG("Begin");
00520     LOG("Executing twos complement test");
00521     if(!twosCompTest()) {
00522        LOG("Twos complement test failed");
00523        loop();
00524     }
00525     LOG("Twos complement test passed");
00526 
00527     LOG("Executing MMA8452 tests");
00528     if(!test()) {
00529        LOG("MMA8452 test failed.");
00530        loop();
00531     }
00532     LOG("MMA8452 test passed");
00533     LOG("All tests passed");
00534     loop();
00535 }