Unit testing and development for 9DOF sparkfun sensor stick
Dependencies: ADXL345 HMC5883L ITG3200 mbed
adxl345unit.cpp@5:63b115f85aa7, 2012-11-09 (annotated)
- 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?
User | Revision | Line number | New 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 | } |