My attempt to made a more useful lib. You can get the accelerator and magnetometer.
Fork of LSM303DLH by
LSM303DLH.cpp
00001 /** LSM303DLH Interface Library 00002 * 00003 * Michael Shimniok http://bot-thoughts.com 00004 * Modified by @author Salco <JeSuisSalco@gmail.com> 00005 * 00006 * This file is subject to the terms and conditions of the GNU Lesser 00007 * General Public License v2.1. See the file LICENSE in the top level 00008 * directory for more details. 00009 */ 00010 #include "mbed.h" 00011 #include "LSM303DLH.h" 00012 00013 #ifndef M_PI 00014 #define M_PI 3.14159265358979323846 00015 #endif 00016 00017 #define FILTER_SHIFT 6 // used in filtering acceleromter readings 00018 00019 00020 00021 00022 00023 bool LSM303DLH::write_reg(int addr_i2c,int addr_reg, uint8_t v) 00024 { 00025 return this->write_reg(addr_i2c,addr_reg,(char)v); 00026 } 00027 00028 bool LSM303DLH::write_reg(int addr_i2c,int addr_reg, char v) 00029 { 00030 bool result=false; 00031 char data[2] = {addr_reg, v}; 00032 //__disable_irq(); 00033 result = m_ptr_I2C->write(addr_i2c, data, 2) == 0; 00034 if(result == false) debug("Unable to Write \n"); 00035 00036 //__enable_irq(); 00037 return result; 00038 } 00039 00040 bool LSM303DLH::read_reg(int addr_i2c,int addr_reg, uint8_t *v) 00041 { 00042 return this->read_reg(addr_i2c,addr_reg,(char*)v); 00043 } 00044 00045 00046 bool LSM303DLH::read_reg(int addr_i2c,int addr_reg, char *v) 00047 { 00048 char data = addr_reg; 00049 bool result = false; 00050 00051 //__disable_irq(); 00052 if(m_ptr_I2C->write(addr_i2c, &data, 1) == 0) 00053 { 00054 if (m_ptr_I2C->read(addr_i2c, &data, 1) == 0) 00055 { 00056 *v = data; 00057 result = true; 00058 } 00059 else 00060 { 00061 debug("Unable to Read \n"); 00062 } 00063 } 00064 else 00065 { 00066 debug("Unable to Write \n"); 00067 } 00068 //__enable_irq(); 00069 return result; 00070 } 00071 00072 bool LSM303DLH::read_reg_short(int addr_i2c,int addr_reg, short *v) 00073 { 00074 00075 char *pv = (char *)v; 00076 bool result; 00077 00078 result = read_reg(addr_i2c,addr_reg+0,pv+1); 00079 result &= read_reg(addr_i2c,addr_reg+1,pv+0); 00080 00081 00082 return result; 00083 } 00084 00085 bool LSM303DLH::read_reg_short(DEV_ADDRS addr_i2c,REG_ADDRS addr_reg, OUT_XYZ_t *dataRead) 00086 { 00087 bool result=true; 00088 00089 switch(addr_reg) 00090 { 00091 case OUT_X_A: 00092 case OUT_Y_A: 00093 case OUT_Z_A: 00094 00095 case OUT_X_M: 00096 case OUT_Y_M: 00097 case OUT_Z_M: 00098 result &= read_reg(addr_i2c,addr_reg ,&(dataRead->UT_L_A));//LSB at lower 00099 result &= read_reg(addr_i2c,addr_reg+1,&(dataRead->UT_H_A)); 00100 #if defined(LSM303_LITLE_ENDIAN) 00101 dataRead.value = (dataRead.byte[1]<<8)+(dataRead.byte[0]); //swap the reading 00102 #endif 00103 break; 00104 default: 00105 result = false; 00106 break; 00107 } 00108 00109 return result; 00110 } 00111 00112 LSM303DLH::~LSM303DLH() 00113 { 00114 if(m_have_createdI2C) 00115 { 00116 delete m_ptr_I2C; 00117 } 00118 } 00119 LSM303DLH::LSM303DLH(PinName sda, PinName scl) 00120 { 00121 m_ptr_I2C = new I2C(sda, scl); 00122 m_have_createdI2C = true; 00123 this->init(); 00124 } 00125 LSM303DLH::LSM303DLH(I2C* ptrI2C) 00126 { 00127 m_ptr_I2C = ptrI2C; 00128 m_have_createdI2C = false; 00129 this->init(); 00130 } 00131 00132 void LSM303DLH::init(void) 00133 { 00134 char reg_v; 00135 00136 _offset_x = 0; 00137 _offset_y = 0; 00138 _offset_z = 0; 00139 _scale_x = 0; 00140 _scale_y = 0; 00141 _scale_z = 0; 00142 _filt_ax = 0; 00143 _filt_ay = 0; 00144 _filt_az = 6000; 00145 00146 00147 m_ptr_I2C->frequency(100000); 00148 00149 ((Ctrl_Reg1_A_t*)®_v)->byte = 0; 00150 ((Ctrl_Reg1_A_t*)®_v)->ODR |= 0b0010; /* Normal mode */ 00151 ((Ctrl_Reg1_A_t*)®_v)->Xen |= 1; /* X/Y/Z axis enable. */ 00152 ((Ctrl_Reg1_A_t*)®_v)->Yen |= 1; 00153 ((Ctrl_Reg1_A_t*)®_v)->Zen |= 1; 00154 write_reg(addr_acc,CTRL_REG1_A,reg_v); 00155 //not sure if we need to read the register 00156 //reg_v = 0; 00157 //read_reg(addr_acc,CTRL_REG1_A,®_v); 00158 00159 ((Ctrl_Reg4_A_t*)®_v)->byte = 0; 00160 ((Ctrl_Reg4_A_t*)®_v)->BDU |= 1; //full read befor update 00161 //(((Ctrl_Reg4_A_t*)®_v)->HR) |= 1; //hi res 00162 #if defined(LSM303_LITLE_ENDIAN) 00163 ((Ctrl_Reg4_A_t*)®_v)->BLE |= 1; /* 1: data MSB @ lower address */ 00164 #endif 00165 ((Ctrl_Reg4_A_t*)®_v)->FS |= 0b01; ; /* +/- 4g */ 00166 write_reg(addr_acc,CTRL_REG4_A,reg_v); 00167 00168 /* -- mag --- */ 00169 debug("in MAG \n"); 00170 ((CRA_REG_M_t*)®_v)->byte = 0; 00171 ((CRA_REG_M_t*)®_v)->DO |= 0b100; /* Minimum data output rate = 15Hz */ 00172 write_reg(addr_mag,CRA_REG_M,reg_v); 00173 00174 reg_v = 0; 00175 //reg_v |= 0x01 << 5; /* +-1.3Gauss */ 00176 ((CRB_REG_M_t*)®_v)->GN |= 0b111; /* +-8.1Gauss */ 00177 write_reg(addr_mag,CRB_REG_M,reg_v); 00178 00179 ((MR_REG_M_t*)®_v)->byte = 0; 00180 //((MR_REG_M_t*)®_v)->MD |= 0; /* Continuous-conversion mode */ 00181 write_reg(addr_mag,MR_REG_M,reg_v); 00182 00183 //put here since we dont change it during the execution 00184 m_FS = get_FullScall_selection(); 00185 00186 read_reg(addr_mag,CRB_REG_M ,®_v); 00187 m_GN = (((CRB_REG_M_t*)®_v)->GN)-1; 00188 } 00189 00190 void LSM303DLH::setOffset(float x, float y, float z) 00191 { 00192 _offset_x = x; 00193 _offset_y = y; 00194 _offset_z = z; 00195 } 00196 00197 void LSM303DLH::setScale(float x, float y, float z) 00198 { 00199 _scale_x = x; 00200 _scale_y = y; 00201 _scale_z = z; 00202 } 00203 //#define _FS 4 00204 bool LSM303DLH::read(vector &a, vector &m) 00205 { 00206 00207 bool result = true; 00208 //short a_x, a_y, a_z; 00209 //short m_x, m_y, m_z; 00210 #if defined(CHECK_TIME_SEQUENCE) 00211 Timer t; 00212 int usec1, usec2; 00213 00214 t.reset(); 00215 t.start(); 00216 00217 usec1 = t.read_us(); 00218 #endif 00219 00220 static vector local_a, local_m; 00221 00222 result &= read_acc_raw(&local_a); 00223 00224 result &= read_mag_raw(&local_m); 00225 00226 00227 #if defined(CHECK_TIME_SEQUENCE) 00228 usec2 = t.read_us(); 00229 00230 debug("%d %d %d\n", usec1, usec2, usec2-usec1);//if (debug) debug->printf("%d %d %d\n", usec1, usec2, usec2-usec1); 00231 #endif 00232 if(result == true) 00233 { 00234 // Perform simple lowpass filtering 00235 // Intended to stabilize heading despite 00236 // device vibration such as on a UGV 00237 00238 00239 //float( a[i] ) * pow(2.,(fs+1)) / 32768. 00240 00241 //x/8 = reading /0xFFFF(655355) 00242 00243 00244 00245 // _filt_ax = _filt_ax + (a_x - (_filt_ax >> FILTER_SHIFT)); 00246 /* _filt_ax = _filt_ax + (ax_test - (_filt_ax >> FILTER_SHIFT)); 00247 _filt_ay += a_y - (_filt_ay >> FILTER_SHIFT); 00248 _filt_az += a_z - (_filt_az >> FILTER_SHIFT); 00249 00250 00251 00252 a.x = (float) (_filt_ax >> FILTER_SHIFT); 00253 a.y = (float) (_filt_ay >> FILTER_SHIFT); 00254 a.z = (float) (_filt_az >> FILTER_SHIFT);*/ 00255 00256 a = local_a; 00257 00258 00259 // offset and scale 00260 m.x = (/*m_*/local_m.x + _offset_x) * _scale_x; 00261 m.y = (/*m_*/local_m.y + _offset_y) * _scale_y; 00262 m.z = (/*m_*/local_m.z + _offset_z) * _scale_z; 00263 00264 } 00265 00266 return result; 00267 } 00268 00269 00270 // Returns the number of degrees from the -Y axis that it 00271 // is pointing. 00272 float LSM303DLH::heading() 00273 { 00274 return heading((vector){0,-1,0}); 00275 } 00276 00277 float LSM303DLH::heading(vector from) 00278 { 00279 vector a, m; 00280 00281 read(a, m); 00282 00283 //////////////////////////////////////////////// 00284 // compute heading 00285 //////////////////////////////////////////////// 00286 00287 vector temp_a = a; 00288 // normalize 00289 vector_normalize(&temp_a); 00290 //vector_normalize(&m); 00291 00292 // compute E and N 00293 vector E; 00294 vector N; 00295 vector_cross(&m,&temp_a,&E); 00296 vector_normalize(&E); 00297 vector_cross(&temp_a,&E,&N); 00298 00299 // compute heading 00300 float heading = atan2(vector_dot(&E,&from), vector_dot(&N,&from)) * 180/M_PI; 00301 if (heading < 0) heading += 360; 00302 00303 return heading; 00304 } 00305 00306 void LSM303DLH::frequency(int hz) 00307 { 00308 m_ptr_I2C->frequency(hz); 00309 } 00310 00311 int8_t LSM303DLH::get_FullScall_selection(void) 00312 { 00313 char data_read_acc =0; 00314 read_reg(addr_acc,CTRL_REG4_A,&data_read_acc); 00315 00316 return 2<<((((Ctrl_Reg4_A_t*)&data_read_acc)->FS)); 00317 } 00318 00319 float LSM303DLH::get_acc_value_in_g(OUT_XYZ_t* dataOut) 00320 { 00321 return (float) (dataOut->value / (float)(32768 /*half of the ADC resolution*/ / m_FS/*+- 4g*/)); 00322 } 00323 00324 bool LSM303DLH::read_acc_raw(vector *a) 00325 { 00326 bool result = true; 00327 char data_read_acc =0; 00328 OUT_XYZ_t dataOut; 00329 00330 read_reg(addr_acc,STATUS_REG_A,&data_read_acc); 00331 00332 if(((Status_Reg_A_t*)&data_read_acc)->ZYXDA)//new data 00333 { 00334 result &= read_reg_short(addr_acc,OUT_X_A,&dataOut); 00335 00336 if(result) 00337 { 00338 a->x = get_acc_value_in_g(&dataOut); 00339 } 00340 else 00341 { 00342 debug("error reading \n"); 00343 } 00344 00345 if(result) 00346 { 00347 result &= read_reg_short(addr_acc,OUT_Y_A,&dataOut); 00348 } 00349 if(result) 00350 { 00351 a->y = get_acc_value_in_g(&dataOut); 00352 } 00353 else 00354 { 00355 debug("error reading \n"); 00356 } 00357 00358 if(result) 00359 { 00360 result &= read_reg_short(addr_acc,OUT_Z_A,&dataOut); 00361 } 00362 if(result) 00363 { 00364 a->z = get_acc_value_in_g(&dataOut); 00365 } 00366 else 00367 { 00368 debug("error reading \n"); 00369 } 00370 } 00371 00372 return result; 00373 } 00374 bool LSM303DLH::read_mag_raw(vector *m) 00375 { 00376 bool result = true; 00377 char data_read_mag =0; 00378 OUT_XYZ_t dataOut; 00379 00380 read_reg(addr_mag,SR_REG_M,&data_read_mag); 00381 00382 00383 /**@todo not sure if the reading of magnetometer is Litle or big endian, I assume its change like the accelerometer. 00384 * You can try to find the answer if you care. 00385 */ 00386 00387 if(((SR_Reg_M_t*)&data_read_mag)->DRDY) 00388 { 00389 float gainxy[] = { 1100., 855., 670., 450., 400., 330., 230. }; 00390 float gainz[] = { 980., 760., 600., 400., 355., 295., 205. }; 00391 00392 result &= read_reg_short(addr_mag,OUT_X_M,&dataOut); 00393 if(result) 00394 { 00395 //dataOut.value = (dataOut.byte[0]<<8)+(dataOut.byte[1]);//only a test 00396 m->x = float(dataOut.value) / gainxy[m_GN]; 00397 } 00398 00399 result &= read_reg_short(addr_mag,OUT_Y_M,&dataOut); 00400 if(result) 00401 { 00402 //dataOut.value = (dataOut.byte[0]<<8)+(dataOut.byte[1]);//only a test 00403 m->y = float(dataOut.value) / gainxy[m_GN]; 00404 } 00405 00406 result &= read_reg_short(addr_mag,OUT_Z_M,&dataOut); 00407 if(result) 00408 { 00409 //dataOut.value = (dataOut.byte[0]<<8)+(dataOut.byte[1]);//only a test 00410 m->z = float(dataOut.value) / gainz[m_GN]; 00411 } 00412 } 00413 00414 return result; 00415 }
Generated on Fri Jul 15 2022 14:50:37 by 1.7.2