Unit testing and development for 9DOF sparkfun sensor stick

Dependencies:   ADXL345 HMC5883L ITG3200 mbed

Committer:
tylerjw
Date:
Fri Nov 09 18:33:29 2012 +0000
Revision:
5:63b115f85aa7
Parent:
4:8a77e21d08f1
ITG3200 curve fit test

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tylerjw 2:d7e66940541d 1 /*
tylerjw 2:d7e66940541d 2 * @file adxl345unit.cpp
tylerjw 2:d7e66940541d 3 * @author Tyler Weaver
tylerjw 2:d7e66940541d 4 *
tylerjw 2:d7e66940541d 5 * @section LICENSE
tylerjw 2:d7e66940541d 6 *
tylerjw 2:d7e66940541d 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
tylerjw 2:d7e66940541d 8 * and associated documentation files (the "Software"), to deal in the Software without restriction,
tylerjw 2:d7e66940541d 9 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
tylerjw 2:d7e66940541d 10 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
tylerjw 2:d7e66940541d 11 * furnished to do so, subject to the following conditions:
tylerjw 2:d7e66940541d 12 *
tylerjw 2:d7e66940541d 13 * The above copyright notice and this permission notice shall be included in all copies or
tylerjw 2:d7e66940541d 14 * substantial portions of the Software.
tylerjw 2:d7e66940541d 15 *
tylerjw 2:d7e66940541d 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
tylerjw 2:d7e66940541d 17 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
tylerjw 2:d7e66940541d 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
tylerjw 2:d7e66940541d 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
tylerjw 2:d7e66940541d 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
tylerjw 2:d7e66940541d 21 *
tylerjw 2:d7e66940541d 22 * @section DESCRIPTION
tylerjw 2:d7e66940541d 23 *
tylerjw 2:d7e66940541d 24 * Unit test for the ADXL345 library.
tylerjw 2:d7e66940541d 25 *
tylerjw 2:d7e66940541d 26 * Reference:
tylerjw 2:d7e66940541d 27 */
tylerjw 2:d7e66940541d 28
tylerjw 2:d7e66940541d 29 #include "adxl345unit.h"
tylerjw 2:d7e66940541d 30
tylerjw 3:5e21a352e236 31 ADXL345UNIT::ADXL345UNIT(I2C &i2c, Timer &t) : adxl345_(i2c), pc_(USBTX, USBRX), open_file_(LED1), t_(t)
tylerjw 2:d7e66940541d 32 {
tylerjw 2:d7e66940541d 33 pc_.baud(9600);
tylerjw 2:d7e66940541d 34 open_file_ = 0;
tylerjw 2:d7e66940541d 35 init();
tylerjw 2:d7e66940541d 36 }
tylerjw 2:d7e66940541d 37
tylerjw 2:d7e66940541d 38 void ADXL345UNIT::init()
tylerjw 2:d7e66940541d 39 {
tylerjw 2:d7e66940541d 40 // place initilazaition code here
tylerjw 2:d7e66940541d 41 }
tylerjw 2:d7e66940541d 42
tylerjw 3:5e21a352e236 43 bool ADXL345UNIT::builtInSelfTest(bool store_raw)
tylerjw 2:d7e66940541d 44 {
tylerjw 3:5e21a352e236 45 LocalFileSystem local("local");
tylerjw 3:5e21a352e236 46 FILE *fp; // file pointer
tylerjw 3:5e21a352e236 47
tylerjw 2:d7e66940541d 48 bool test_pass[4] = {true,true,true,true};
tylerjw 2:d7e66940541d 49 bool full_test = true;
tylerjw 2:d7e66940541d 50
tylerjw 3:5e21a352e236 51 int16_t st_off[100][3]; // {x,y,z}, self test off
tylerjw 3:5e21a352e236 52 int16_t st_off_avg[3]; // self test off average
tylerjw 3:5e21a352e236 53 int16_t st_on[100][3]; // {x,y,z}, self test off
tylerjw 3:5e21a352e236 54 int16_t st_on_avg[3]; // self test on average
tylerjw 3:5e21a352e236 55 int16_t delta[3]; // st_on - st_off
tylerjw 2:d7e66940541d 56
tylerjw 2:d7e66940541d 57 const char axisK[3] = {'X','Y','Z'};
tylerjw 3:5e21a352e236 58 const int16_t resolutionsK[4] = {16,8,4,2};
tylerjw 2:d7e66940541d 59 const char data_formatK[4] = {ADXL345_16G, ADXL345_8G, ADXL345_4G, (ADXL345_2G | ADXL345_FULL_RES)};
tylerjw 3:5e21a352e236 60 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
tylerjw 3:5e21a352e236 61 const int16_t delta_maxK[4][3] = {{67,-6,110},{135,-12,219},{270,-25,438},{540,-50,875}};
tylerjw 2:d7e66940541d 62
tylerjw 3:5e21a352e236 63 float period = 0.01; // period of sample rate
tylerjw 3:5e21a352e236 64
tylerjw 3:5e21a352e236 65 adxl345_.setDataRate(ADXL345_100HZ); // 100Hz data rate
tylerjw 3:5e21a352e236 66 adxl345_.setPowerMode(0); // high power
tylerjw 2:d7e66940541d 67
tylerjw 2:d7e66940541d 68 for(int res = 0; res < 4; res++) {
tylerjw 2:d7e66940541d 69 //print starting message
tylerjw 2:d7e66940541d 70 pc_.printf("ADXL345: Starting Built In Self Test (%dg resolution)... \n\r", resolutionsK[res]);
tylerjw 3:5e21a352e236 71
tylerjw 2:d7e66940541d 72 //wait 1.1ms
tylerjw 3:5e21a352e236 73 wait(0.0111);
tylerjw 3:5e21a352e236 74
tylerjw 3:5e21a352e236 75 pc_.puts("Calibrating... ");
tylerjw 2:d7e66940541d 76 //initial command sequence
tylerjw 3:5e21a352e236 77 adxl345_.setDataFormatControl(data_formatK[res]);
tylerjw 2:d7e66940541d 78 adxl345_.setPowerControl(0x08); // start measurement
tylerjw 3:5e21a352e236 79 //adxl345_.setInterruptEnableControl(0x80); // enable data_ready interupt (not needed?)
tylerjw 3:5e21a352e236 80 pc_.puts("Done!\r\n");
tylerjw 3:5e21a352e236 81
tylerjw 3:5e21a352e236 82 //wait 11.1ms
tylerjw 3:5e21a352e236 83 wait(0.0111);
tylerjw 3:5e21a352e236 84
tylerjw 3:5e21a352e236 85 pc_.puts("Sampling: ");
tylerjw 2:d7e66940541d 86 //take 100 data points and average (100Hz)
tylerjw 3:5e21a352e236 87 sample100avg(period, st_off, st_off_avg, &t_);
tylerjw 2:d7e66940541d 88
tylerjw 2:d7e66940541d 89 //activate self test
tylerjw 2:d7e66940541d 90 adxl345_.setDataFormatControl(data_formatK[res] | ADXL345_SELF_TEST); // self test enabled
tylerjw 2:d7e66940541d 91
tylerjw 3:5e21a352e236 92 //wait 11.1ms
tylerjw 3:5e21a352e236 93 wait(0.0111);
tylerjw 3:5e21a352e236 94
tylerjw 3:5e21a352e236 95 //take 100 data points and average (100Hz)
tylerjw 3:5e21a352e236 96 sample100avg(period, st_on, st_on_avg, &t_);
tylerjw 3:5e21a352e236 97 pc_.puts("Done!\r\n");
tylerjw 3:5e21a352e236 98
tylerjw 2:d7e66940541d 99 //inactivate self test
tylerjw 2:d7e66940541d 100 adxl345_.setDataFormatControl(data_formatK[res]); // self test off
tylerjw 3:5e21a352e236 101
tylerjw 2:d7e66940541d 102 //calculate self test delta(change) and compare to limits in data sheet
tylerjw 2:d7e66940541d 103 //open file
tylerjw 2:d7e66940541d 104 open_file_ = 1;
tylerjw 3:5e21a352e236 105 fp = fopen("/local/BIST.csv", "a"); // open append, or create
tylerjw 3:5e21a352e236 106 fprintf(fp, "ADXL345 Built In Self-Test\n\rResolution,%d,g\r\n\r\nAxis,Min,Max,Actual,Pass\r\n", resolutionsK[res]);
tylerjw 2:d7e66940541d 107 for(int axis = 0; axis < 3; axis++) {
tylerjw 2:d7e66940541d 108 delta[axis] = st_on_avg[axis] - st_off_avg[axis];
tylerjw 3:5e21a352e236 109 bool test = (delta[axis] >= delta_minK[res][axis] && delta[axis] <= delta_maxK[res][axis]);
tylerjw 2:d7e66940541d 110 if(test == false)
tylerjw 2:d7e66940541d 111 test_pass[res] = full_test = false;
tylerjw 2:d7e66940541d 112 fprintf(fp, "%c,%4d,%4d,%4d,%s\r\n", axisK[axis],delta_minK[res][axis],delta_maxK[res][axis],delta[axis],(test)?"pass":"fail");
tylerjw 2:d7e66940541d 113 }
tylerjw 2:d7e66940541d 114 fprintf(fp, "Test Result: %s\r\n\r\n", (test_pass[res])?"pass":"fail");
tylerjw 2:d7e66940541d 115 // close file
tylerjw 2:d7e66940541d 116 fclose(fp);
tylerjw 2:d7e66940541d 117 open_file_ = 0;
tylerjw 3:5e21a352e236 118 pc_.printf("Test Result: %s\r\n", (test_pass[res])?"pass":"fail");
tylerjw 3:5e21a352e236 119
tylerjw 3:5e21a352e236 120 pc_.puts("Dumping raw data to BIT_RAW.csv... ");
tylerjw 3:5e21a352e236 121 open_file_ = 1;
tylerjw 3:5e21a352e236 122
tylerjw 3:5e21a352e236 123 if(store_raw) {
tylerjw 3:5e21a352e236 124 //dump raw data to ADXL_RAW.csv
tylerjw 3:5e21a352e236 125 fp = fopen("/local/BIST_RAW.csv", "a"); // open append, or create
tylerjw 3:5e21a352e236 126 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]);
tylerjw 3:5e21a352e236 127 for(int sample = 0; sample < 100; sample++)
tylerjw 3:5e21a352e236 128 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]);
tylerjw 3:5e21a352e236 129 fputs("\r\n",fp);
tylerjw 3:5e21a352e236 130 fclose(fp);
tylerjw 3:5e21a352e236 131 open_file_ = 0;
tylerjw 3:5e21a352e236 132 }
tylerjw 3:5e21a352e236 133
tylerjw 3:5e21a352e236 134 pc_.puts("Done!\r\n");
tylerjw 2:d7e66940541d 135 }
tylerjw 3:5e21a352e236 136
tylerjw 2:d7e66940541d 137 //return result
tylerjw 2:d7e66940541d 138 return full_test;
tylerjw 2:d7e66940541d 139 }
tylerjw 2:d7e66940541d 140
tylerjw 3:5e21a352e236 141 void ADXL345UNIT::offsetCalibration(bool store_raw)
tylerjw 3:5e21a352e236 142 {
tylerjw 3:5e21a352e236 143 int16_t data[100][3]; // {x,y,z}, data
tylerjw 3:5e21a352e236 144 int16_t data_avg[3];
tylerjw 3:5e21a352e236 145 int16_t calibration_offset[3];
tylerjw 3:5e21a352e236 146
tylerjw 3:5e21a352e236 147 LocalFileSystem local("local");
tylerjw 3:5e21a352e236 148
tylerjw 3:5e21a352e236 149 float period = 0.01; // period of sample rate
tylerjw 3:5e21a352e236 150
tylerjw 3:5e21a352e236 151 // place sensor in x = 0g, y = 0g, z = 1g orientation
tylerjw 3:5e21a352e236 152 pc_.puts("Offset Calibration: Sensor should be in x=0g,y=0g,z=1g orientation\r\n");
tylerjw 3:5e21a352e236 153
tylerjw 3:5e21a352e236 154 // wait 11.1ms
tylerjw 3:5e21a352e236 155 wait(0.0111);
tylerjw 3:5e21a352e236 156
tylerjw 3:5e21a352e236 157 // initalize command sequence
tylerjw 3:5e21a352e236 158 adxl345_.setDataFormatControl((ADXL345_16G | ADXL345_FULL_RES));
tylerjw 3:5e21a352e236 159 adxl345_.setDataRate(ADXL345_100HZ); // 100Hz data rate
tylerjw 3:5e21a352e236 160 adxl345_.setPowerMode(0); // high power
tylerjw 3:5e21a352e236 161 adxl345_.setPowerControl(0x08); // start measurement
tylerjw 3:5e21a352e236 162
tylerjw 3:5e21a352e236 163 // wait 1.1ms
tylerjw 3:5e21a352e236 164 wait(0.0111);
tylerjw 3:5e21a352e236 165
tylerjw 3:5e21a352e236 166 //take 100 data points and average (100Hz)
tylerjw 3:5e21a352e236 167 sample100avg(period, data, data_avg, &t_);
tylerjw 3:5e21a352e236 168
tylerjw 3:5e21a352e236 169 // calculate calibration value
tylerjw 3:5e21a352e236 170 calibration_offset[0] = -1 * (data_avg[0] / 4); // x
tylerjw 3:5e21a352e236 171 calibration_offset[1] = -1 * (data_avg[1] / 4); // y
tylerjw 3:5e21a352e236 172 calibration_offset[2] = -1 * ((data_avg[2] - 256) / 4); // z
tylerjw 3:5e21a352e236 173
tylerjw 3:5e21a352e236 174 // display and store values
tylerjw 3:5e21a352e236 175 pc_.printf("X offset: %d\r\n", calibration_offset[0]);
tylerjw 3:5e21a352e236 176 pc_.printf("Y offset: %d\r\n", calibration_offset[1]);
tylerjw 3:5e21a352e236 177 pc_.printf("Z offset: %d\r\n", calibration_offset[2]);
tylerjw 3:5e21a352e236 178
tylerjw 3:5e21a352e236 179 open_file_ = 1;
tylerjw 3:5e21a352e236 180 FILE *fp = fopen("/local/OFF_CAL.csv", "w"); // write
tylerjw 3:5e21a352e236 181 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]);
tylerjw 3:5e21a352e236 182 if(store_raw) {
tylerjw 3:5e21a352e236 183 fputs("Raw Data:\r\nX,Y,Z\r\n", fp);
tylerjw 3:5e21a352e236 184 for(int sample = 0; sample < 100; sample++)
tylerjw 3:5e21a352e236 185 fprintf(fp, "%d,%d,%d\r\n",data[sample][0],data[sample][1],data[sample][2]);
tylerjw 3:5e21a352e236 186 }
tylerjw 3:5e21a352e236 187 fclose(fp);
tylerjw 3:5e21a352e236 188 open_file_ = 0;
tylerjw 3:5e21a352e236 189 }
tylerjw 3:5e21a352e236 190
tylerjw 4:8a77e21d08f1 191 //void ADXL345UNIT::sampleTimeTest()
tylerjw 4:8a77e21d08f1 192 //{
tylerjw 3:5e21a352e236 193 // constructors and size of obj tests
tylerjw 3:5e21a352e236 194 // destructor test
tylerjw 3:5e21a352e236 195 // get device id [0xE5]
tylerjw 3:5e21a352e236 196 // set power mode > get bw rate
tylerjw 3:5e21a352e236 197 //
tylerjw 4:8a77e21d08f1 198 //}
tylerjw 3:5e21a352e236 199
tylerjw 3:5e21a352e236 200 int16_t ADXL345UNIT::arr_avg(int16_t* arr,int16_t length)
tylerjw 2:d7e66940541d 201 {
tylerjw 2:d7e66940541d 202 double average;
tylerjw 2:d7e66940541d 203 for(int i = 0; i < length; i++)
tylerjw 2:d7e66940541d 204 average += static_cast<double>(arr[i]) / static_cast<double>(length);
tylerjw 3:5e21a352e236 205 return static_cast<int16_t>(average);
tylerjw 3:5e21a352e236 206 }
tylerjw 3:5e21a352e236 207
tylerjw 3:5e21a352e236 208 void ADXL345UNIT::sample100avg(float period, int16_t buffer[][3], int16_t *avg, Timer* t)
tylerjw 3:5e21a352e236 209 {
tylerjw 3:5e21a352e236 210 double start_time;
tylerjw 3:5e21a352e236 211
tylerjw 3:5e21a352e236 212 for(int sample = 0; sample < 100; sample++) {
tylerjw 3:5e21a352e236 213 start_time = t->read();
tylerjw 3:5e21a352e236 214
tylerjw 4:8a77e21d08f1 215 adxl345_.getXYZ(buffer[sample]);
tylerjw 3:5e21a352e236 216
tylerjw 3:5e21a352e236 217 wait(period - (start_time - t->read()));
tylerjw 3:5e21a352e236 218 }
tylerjw 3:5e21a352e236 219
tylerjw 3:5e21a352e236 220 for(int axis = 0; axis < 3; axis++) {
tylerjw 3:5e21a352e236 221 double average = 0.0;
tylerjw 3:5e21a352e236 222 for(int sample = 0; sample < 100; sample++)
tylerjw 3:5e21a352e236 223 average += buffer[sample][axis];
tylerjw 3:5e21a352e236 224 average /= 100.0;
tylerjw 3:5e21a352e236 225 avg[axis] = static_cast<int16_t>(average);
tylerjw 3:5e21a352e236 226 }
tylerjw 2:d7e66940541d 227 }