Unit testing and development for 9DOF sparkfun sensor stick

Dependencies:   ADXL345 HMC5883L ITG3200 mbed

adxl345unit.cpp

Committer:
tylerjw
Date:
2012-11-06
Revision:
4:8a77e21d08f1
Parent:
3:5e21a352e236

File content as of revision 4:8a77e21d08f1:

/*
 * @file adxl345unit.cpp
 * @author Tyler Weaver
 *
 * @section LICENSE
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * Unit test for the ADXL345 library.
 *
 * Reference:
 */

#include "adxl345unit.h"

ADXL345UNIT::ADXL345UNIT(I2C &i2c, Timer &t) : adxl345_(i2c), pc_(USBTX, USBRX), open_file_(LED1), t_(t)
{
    pc_.baud(9600);
    open_file_ = 0;
    init();
}

void ADXL345UNIT::init()
{
    // place initilazaition code here
}

bool ADXL345UNIT::builtInSelfTest(bool store_raw)
{
    LocalFileSystem local("local");
    FILE *fp; // file pointer

    bool test_pass[4] = {true,true,true,true};
    bool full_test = true;

    int16_t st_off[100][3]; // {x,y,z}, self test off
    int16_t st_off_avg[3];  // self test off average
    int16_t st_on[100][3];  // {x,y,z}, self test off
    int16_t st_on_avg[3];   // self test on average
    int16_t delta[3];       // st_on - st_off

    const char axisK[3] = {'X','Y','Z'};
    const int16_t resolutionsK[4] = {16,8,4,2};
    const char data_formatK[4] = {ADXL345_16G, ADXL345_8G, ADXL345_4G, (ADXL345_2G | ADXL345_FULL_RES)};
    const int16_t delta_minK[4][3] = {{6,-67,10},{12,-135,19},{25,-270,38},{50,-540,75}}; // {{16g},{8g},{4g},{2g}} from datasheet
    const int16_t delta_maxK[4][3] = {{67,-6,110},{135,-12,219},{270,-25,438},{540,-50,875}};

    float period = 0.01; // period of sample rate

    adxl345_.setDataRate(ADXL345_100HZ); // 100Hz data rate
    adxl345_.setPowerMode(0); // high power

    for(int res = 0; res < 4; res++) {
        //print starting message
        pc_.printf("ADXL345: Starting Built In Self Test (%dg resolution)... \n\r", resolutionsK[res]);

        //wait 1.1ms
        wait(0.0111);

        pc_.puts("Calibrating... ");
        //initial command sequence
        adxl345_.setDataFormatControl(data_formatK[res]);
        adxl345_.setPowerControl(0x08); // start measurement
        //adxl345_.setInterruptEnableControl(0x80); // enable data_ready interupt (not needed?)
        pc_.puts("Done!\r\n");

        //wait 11.1ms
        wait(0.0111);

        pc_.puts("Sampling: ");
        //take 100 data points and average (100Hz)
        sample100avg(period, st_off, st_off_avg, &t_);

        //activate self test
        adxl345_.setDataFormatControl(data_formatK[res] | ADXL345_SELF_TEST); // self test enabled

        //wait 11.1ms
        wait(0.0111);
        
        //take 100 data points and average (100Hz)
        sample100avg(period, st_on, st_on_avg, &t_);
        pc_.puts("Done!\r\n");

        //inactivate self test
        adxl345_.setDataFormatControl(data_formatK[res]); // self test off

        //calculate self test delta(change) and compare to limits in data sheet
        //open file
        open_file_ = 1;
        fp = fopen("/local/BIST.csv", "a"); // open append, or create
        fprintf(fp, "ADXL345 Built In Self-Test\n\rResolution,%d,g\r\n\r\nAxis,Min,Max,Actual,Pass\r\n", resolutionsK[res]);
        for(int axis = 0; axis < 3; axis++) {
            delta[axis] = st_on_avg[axis] - st_off_avg[axis];
            bool test = (delta[axis] >= delta_minK[res][axis] && delta[axis] <= delta_maxK[res][axis]);
            if(test == false)
                test_pass[res] = full_test = false;
            fprintf(fp, "%c,%4d,%4d,%4d,%s\r\n", axisK[axis],delta_minK[res][axis],delta_maxK[res][axis],delta[axis],(test)?"pass":"fail");
        }
        fprintf(fp, "Test Result: %s\r\n\r\n", (test_pass[res])?"pass":"fail");
        // close file
        fclose(fp);
        open_file_ = 0;
        pc_.printf("Test Result: %s\r\n", (test_pass[res])?"pass":"fail");

        pc_.puts("Dumping raw data to BIT_RAW.csv... ");
        open_file_ = 1;

        if(store_raw) {
            //dump raw data to ADXL_RAW.csv
            fp = fopen("/local/BIST_RAW.csv", "a"); // open append, or create
            fprintf(fp, "ADXL345 Built In Self-Test Raw Data\n\rResolution,%d,g\r\nSample,X st_off,X st_on,Y st_off,Y st_on,Z st_off, Z st_off\r\n", resolutionsK[res]);
            for(int sample = 0; sample < 100; sample++)
                fprintf(fp, "%3d,%4d,%4d,%4d,%4d,%4d,%4d\r\n", (sample+1),st_on[sample][0],st_off[sample][0],st_on[sample][1],st_off[sample][1],st_on[sample][2],st_off[sample][2]);
            fputs("\r\n",fp);
            fclose(fp);
            open_file_ = 0;
        }

        pc_.puts("Done!\r\n");
    }

    //return result
    return full_test;
}

void ADXL345UNIT::offsetCalibration(bool store_raw)
{
    int16_t data[100][3]; // {x,y,z}, data
    int16_t data_avg[3];
    int16_t calibration_offset[3];

    LocalFileSystem local("local");

    float period = 0.01; // period of sample rate

    // place sensor in x = 0g, y = 0g, z = 1g orientation
    pc_.puts("Offset Calibration: Sensor should be in x=0g,y=0g,z=1g orientation\r\n");

    // wait 11.1ms
    wait(0.0111);

    // initalize command sequence
    adxl345_.setDataFormatControl((ADXL345_16G | ADXL345_FULL_RES));
    adxl345_.setDataRate(ADXL345_100HZ); // 100Hz data rate
    adxl345_.setPowerMode(0); // high power
    adxl345_.setPowerControl(0x08); // start measurement

    // wait 1.1ms
    wait(0.0111);

    //take 100 data points and average (100Hz)
    sample100avg(period, data, data_avg, &t_);

    // calculate calibration value
    calibration_offset[0] = -1 * (data_avg[0] / 4); // x
    calibration_offset[1] = -1 * (data_avg[1] / 4); // y
    calibration_offset[2] = -1 * ((data_avg[2] - 256) / 4); // z

    // display and store values
    pc_.printf("X offset: %d\r\n", calibration_offset[0]);
    pc_.printf("Y offset: %d\r\n", calibration_offset[1]);
    pc_.printf("Z offset: %d\r\n", calibration_offset[2]);

    open_file_ = 1;
    FILE *fp = fopen("/local/OFF_CAL.csv", "w"); // write
    fprintf(fp, "ADXL345 Calibration offsets\r\nx,%d\r\ny,%d\r\nz,%d\r\n\r\n", calibration_offset[0], calibration_offset[1], calibration_offset[2]);
    if(store_raw) {
        fputs("Raw Data:\r\nX,Y,Z\r\n", fp);
        for(int sample = 0; sample < 100; sample++)
            fprintf(fp, "%d,%d,%d\r\n",data[sample][0],data[sample][1],data[sample][2]);
    }
    fclose(fp);
    open_file_ = 0;
}

//void ADXL345UNIT::sampleTimeTest()
//{
    // constructors and size of obj tests
    // destructor test
    // get device id [0xE5]
    // set power mode > get bw rate
    //
//}

int16_t ADXL345UNIT::arr_avg(int16_t* arr,int16_t length)
{
    double average;
    for(int i = 0; i < length; i++)
        average += static_cast<double>(arr[i]) / static_cast<double>(length);
    return static_cast<int16_t>(average);
}

void ADXL345UNIT::sample100avg(float period, int16_t buffer[][3], int16_t *avg, Timer* t)
{
    double start_time;
    
    for(int sample = 0; sample < 100; sample++) {
        start_time = t->read();

        adxl345_.getXYZ(buffer[sample]);

        wait(period - (start_time - t->read()));
    }

    for(int axis = 0; axis < 3; axis++) {
        double average = 0.0;
        for(int sample = 0; sample < 100; sample++)
            average += buffer[sample][axis];
        average /= 100.0;
        avg[axis] = static_cast<int16_t>(average);
    }
}