Driver for the HSCDTD008A Geomagnetic Sensor.
Embed:
(wiki syntax)
Show/hide line numbers
HSCDTD008A.cpp
00001 /* 00002 * Copyright (c) 2020 Zoltan Hudak <hudakz@outlook.com> 00003 * All rights reserved. 00004 * 00005 * This program is free software: you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation, either version 3 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include "mbed.h" 00020 #include "HSCDTD008A.h" 00021 00022 /*$off*/ 00023 const char STB = 0x0C; // Self test response 00024 const char INFO1 = 0x0D; // More info version 00025 const char INFO2 = 0x0E; // More info ALPS 00026 const char WIA = 0x0F; // Who I am 00027 const char OUTX_LSB = 0x10; // Output X LSB 00028 const char OUTX_MSB = 0x11; // Output X MSB 00029 const char OUTY_LSB = 0x12; // Output Y LSB 00030 const char OUTY_MSB = 0x13; // Output Y MSB 00031 const char OUTZ_LSB = 0x14; // Output Z LSB 00032 const char OUTZ_MSB = 0x15; // Output Z MSB 00033 const char STAT = 0x18; // Status 00034 const char FFPT = 0x19; // FIFO Pointer Status 00035 const char CTRL1 = 0x1B; // Control1 00036 const char CTRL2 = 0x1C; // Control2 00037 const char CTRL3 = 0x1D; // Control3 00038 const char CTRL4 = 0x1E; // Control4 00039 const char OFFX_LSB = 0x20; // Offset X LSB 00040 const char OFFX_MSB = 0x21; // Offset X MSB 00041 const char OFFY_LSB = 0x22; // Offset Y LSB 00042 const char OFFY_MSB = 0x23; // Offset Y MSB 00043 const char OFFZ_LSB = 0x24; // Offset Z LSB 00044 const char OFFZ_MSB = 0x25; // Offset Z MSB 00045 const char ITHR_LSB = 0x26; // Interrupt Threshold LSB. Comparison value.Note: Enabled if CTRL2.FCO 00046 const char ITHR_MSB = 0x27; // Interrupt Threshold MSB. Not Used (Read Only) 00047 const char TEMP = 0x31; // Temperature Data, Signed Integer. LSB = 1°C, 1000 0000 = -128°C, 0000 0000 = 0°C, 0111 1111 = 127°C 00048 // 00049 /** 00050 * @brief 00051 * @note 00052 * @param 00053 * @retval 00054 */ 00055 void printBinary(uint8_t val) 00056 { 00057 for (int i = 7; i >= 0; i--) { 00058 if (val & (1<< i)) 00059 putc('1', stdout); 00060 else 00061 putc('0', stdout); 00062 } 00063 } 00064 /*$on*/ 00065 00066 /** 00067 * @brief Constructor 00068 * @note 00069 * @param 00070 * @retval 00071 */ 00072 HSCDTD008A::HSCDTD008A(PinName sda, PinName scl, uint8_t addr /*= 0x0C*/ ) : 00073 _i2c(new I2C(sda, scl)), 00074 _addr(addr << 1), // convert to 8bit address 00075 _x(0), 00076 _y(0), 00077 _z(0) 00078 { 00079 _i2c->frequency(400000); // select 400kHz clock 00080 } 00081 00082 /** 00083 * @brief 00084 * @note 00085 * @param 00086 * @retval 00087 */ 00088 int16_t HSCDTD008A::toInt16(uint16_t word) 00089 { 00090 if (word & (1 << 7)) 00091 return(-(uint16_t(~word + 1))); 00092 else 00093 return(word); 00094 } 00095 00096 /** 00097 * @brief 00098 * @note 00099 * @param 00100 * @retval 00101 */ 00102 void HSCDTD008A::softReset() 00103 { 00104 const char soft_reset[] = { CTRL3, (1 << SRST) }; 00105 char ret; 00106 00107 _i2c->write(_addr, soft_reset, 2); 00108 00109 while (true) { 00110 ThisThread::sleep_for(1ms); 00111 00112 // read CTRL3 register 00113 _i2c->write(_addr, &CTRL3, 1); 00114 _i2c->read(_addr, &ret, 1); 00115 00116 if (ret & (1 << SRST) == 0) { 00117 break; // done 00118 } 00119 } 00120 } 00121 00122 /** 00123 * @brief 00124 * @note 00125 * @param 00126 * @retval 00127 */ 00128 uint8_t HSCDTD008A::selfTest() 00129 { 00130 const char start_selftest[] = { CTRL3, (1 << STC) }; 00131 char ret; 00132 00133 _i2c->write(_addr, start_selftest, 2); 00134 00135 // read Status register 00136 _i2c->write(_addr, &STB, 1); 00137 _i2c->read(_addr, &ret, 1); 00138 00139 if (ret == 0xAA) { 00140 ThisThread::sleep_for(1ms); 00141 00142 // read Status register 00143 _i2c->write(_addr, &STB, 1); 00144 _i2c->read(_addr, &ret, 1); 00145 if (ret == 0x55) { 00146 return OK; 00147 } 00148 } 00149 00150 return ERROR; 00151 } 00152 00153 /** 00154 * @brief 00155 * @note 00156 * @param 00157 * @retval 00158 */ 00159 void HSCDTD008A::calibrateOffsets() 00160 { 00161 const char start_calibration[] = { CTRL3, (1 << OCL) }; 00162 char ret; 00163 00164 _i2c->write(_addr, start_calibration, 2); 00165 00166 while (true) { 00167 ThisThread::sleep_for(1ms); 00168 00169 // read Control3 register 00170 _i2c->write(_addr, &CTRL3, 1); 00171 _i2c->read(_addr, &ret, 1); 00172 00173 if ((ret & (1 << OCL)) == 0) { 00174 break; // done 00175 } 00176 } 00177 } 00178 00179 /** 00180 * @brief 00181 * @note 00182 * @param 00183 * @retval 00184 */ 00185 void HSCDTD008A::setDriftOffsetX(uint16_t val) 00186 { 00187 const char set_offx_lsb[] = { OFFX_LSB, (char)(val & 0xFF) }; 00188 const char set_offx_msb[] = { OFFX_MSB, (char)((val >> 8) & 0xFF) }; 00189 00190 _i2c->write(_addr, set_offx_lsb, 2); 00191 _i2c->write(_addr, set_offx_msb, 2); 00192 } 00193 00194 /** 00195 * @brief 00196 * @note 00197 * @param 00198 * @retval 00199 */ 00200 void HSCDTD008A::setDriftOffsetY(uint16_t val) 00201 { 00202 const char set_offy_lsb[] = { OFFY_LSB, (char)(val & 0xFF) }; 00203 const char set_offy_msb[] = { OFFY_MSB, (char)((val >> 8) & 0xFF) }; 00204 00205 _i2c->write(_addr, set_offy_lsb, 2); 00206 _i2c->write(_addr, set_offy_msb, 2); 00207 } 00208 00209 /** 00210 * @brief 00211 * @note 00212 * @param 00213 * @retval 00214 */ 00215 void HSCDTD008A::setDriftOffsetZ(uint16_t val) 00216 { 00217 const char set_offz_lsb[] = { OFFZ_LSB, (char)(val & 0xFF) }; 00218 const char set_offz_msb[] = { OFFZ_MSB, (char)((val >> 8) & 0xFF) }; 00219 00220 _i2c->write(_addr, set_offz_lsb, 2); 00221 _i2c->write(_addr, set_offz_msb, 2); 00222 } 00223 00224 /** 00225 * @brief 00226 * @note 00227 * @param 00228 * @retval 00229 */ 00230 void HSCDTD008A::compensateTemp() 00231 { 00232 const char measure_temperature[] = { CTRL3, (1 << TCS) }; 00233 char ret; 00234 00235 forcedMode(); 00236 _i2c->write(_addr, measure_temperature, 2); 00237 00238 while (true) { 00239 ThisThread::sleep_for(1ms); 00240 00241 // read Status register 00242 _i2c->write(_addr, &STAT, 1); 00243 _i2c->read(_addr, &ret, 1); 00244 00245 if (ret & (1 << TRDY)) { 00246 break; // done 00247 } 00248 } 00249 00250 standbyMode(); 00251 } 00252 00253 /** 00254 * @brief 00255 * @note 00256 * @param 00257 * @retval 00258 */ 00259 void HSCDTD008A::enableFifo() 00260 { 00261 const char enable_fifo[] = { CTRL2, (1 << FF) }; 00262 00263 _i2c->write(_addr, enable_fifo, 2); 00264 } 00265 00266 /** 00267 * @brief 00268 * @note 00269 * @param 00270 * @retval 00271 */ 00272 void HSCDTD008A::disableFifo() 00273 { 00274 const char enable_fifo[] = { CTRL2, (0 << FF) }; 00275 00276 _i2c->write(_addr, enable_fifo, 2); 00277 } 00278 00279 /** 00280 * @brief 00281 * @note 00282 * @param 00283 * @retval 00284 */ 00285 uint8_t HSCDTD008A::getFifoPointer() 00286 { 00287 char ret; 00288 00289 // read FIFO pointer register 00290 _i2c->write(_addr, &FFPT, 1); 00291 _i2c->read(_addr, &ret, 1); 00292 00293 return(ret & FP); 00294 } 00295 00296 /** 00297 * @brief 00298 * @note 00299 * @param 00300 * @retval 00301 */ 00302 bool HSCDTD008A::isFifoFull() 00303 { 00304 char ret; 00305 00306 // read Status register 00307 _i2c->write(_addr, &STAT, 1); 00308 _i2c->read(_addr, &ret, 1); 00309 00310 if (ret & (1 << FFU)) 00311 return true; 00312 else 00313 return false; 00314 } 00315 00316 /** 00317 * @brief 00318 * @note 00319 * @param 00320 * @retval 00321 */ 00322 bool HSCDTD008A::isFifoOverrun() 00323 { 00324 char ret; 00325 00326 // read Status register 00327 _i2c->write(_addr, &STAT, 1); 00328 _i2c->read(_addr, &ret, 1); 00329 00330 if (ret & ((1 << FFU) | (1 << DOR))) 00331 return true; 00332 else 00333 return false; 00334 } 00335 00336 /** 00337 * @brief 00338 * @note 00339 * @param 00340 * @retval 00341 */ 00342 bool HSCDTD008A::isDataReady() 00343 { 00344 char ret; 00345 00346 // read Status register 00347 _i2c->write(_addr, &STAT, 1); 00348 _i2c->read(_addr, &ret, 1); 00349 00350 if (ret & (1 << DRDY) == 0) 00351 return true; 00352 else 00353 return false; 00354 } 00355 00356 /** 00357 * @brief 00358 * @note 00359 * @param 00360 * @retval 00361 */ 00362 void HSCDTD008A::standbyMode() 00363 { 00364 const char select_standby_mode[] = { CTRL1, (0 << PC) }; 00365 00366 _i2c->write(_addr, select_standby_mode, 2); 00367 } 00368 00369 /** 00370 * @brief 00371 * @note 00372 * @param 00373 * @retval 00374 */ 00375 void HSCDTD008A::normalMode(uint8_t odr /*= 0b01*/, bool enableDataReady /*= false*/ ) 00376 { 00377 const char enable_data_ready[] = { CTRL2, (1 << DEN) | (0 << DRP) }; // enable Data Ready with ACTIVE LOW control 00378 const char select_normal_mode[] = { CTRL1, (1 << PC) | (0b11 << ODR) | (0 << FS) }; // set active mode to normal 00379 00380 if (enableDataReady) 00381 _i2c->write(_addr, enable_data_ready, 2); 00382 00383 _i2c->write(_addr, select_normal_mode, 2); 00384 } 00385 00386 /** 00387 * @brief 00388 * @note 00389 * @param 00390 * @retval 00391 */ 00392 void HSCDTD008A::forcedMode() 00393 { 00394 const char select_forced_mode[] = { CTRL1, (1 << PC) | (1 << FS) }; 00395 00396 _i2c->write(_addr, select_forced_mode, 2); 00397 } 00398 00399 /** 00400 * @brief 00401 * @note 00402 * @param 00403 * @retval 00404 */ 00405 bool HSCDTD008A::getResolution() 00406 { 00407 char ret; 00408 00409 // read CTRL4 register 00410 _i2c->write(_addr, &CTRL4, 1); 00411 _i2c->read(_addr, &ret, 1); 00412 00413 // check RS bit 00414 if (ret & (1 << RS)) 00415 return true; // 15bit output resolution 00416 else 00417 return false; // 14bit output resolution 00418 } 00419 00420 /** 00421 * @brief 00422 * @note 00423 * @param 00424 * @retval 00425 */ 00426 void HSCDTD008A::setResolution(bool fifteen_bits) 00427 { 00428 char ret; 00429 char cmd[2] = { CTRL4, 0 }; 00430 00431 // read CTRL4 register 00432 _i2c->write(_addr, &CTRL4, 1); 00433 _i2c->read(_addr, &ret, 1); 00434 00435 if (fifteen_bits) 00436 ret |= (1 << RS); // set RS bit 00437 else 00438 ret &= ~(0 << RS); // clear RS bit 00439 cmd[1] = RS; // set output resolution 00440 _i2c->write(_addr, cmd, 2); 00441 } 00442 00443 /** 00444 * @brief 00445 * @note Shall be called in forced mode 00446 * @param 00447 * @retval 00448 */ 00449 uint8_t HSCDTD008A::measure() 00450 { 00451 const char start_measurement[] = { CTRL3, (1 << FRC) }; // Start measurement in force mode (returns to 0 when finished) 00452 char ret; 00453 char data[6]; 00454 00455 // Start measurement in forced mode 00456 _i2c->write(_addr, &STAT, 1); 00457 _i2c->read(_addr, &ret, 1); 00458 if (!(ret & (1 << DRDY))) { 00459 _i2c->write(_addr, start_measurement, 2); 00460 } 00461 00462 // Read Status register 00463 _i2c->write(_addr, &STAT, 1); 00464 _i2c->read(_addr, &ret, 1); 00465 00466 // Is data ready? 00467 if (ret & (1 << DRDY)) { 00468 readData(); 00469 00470 return OK; 00471 } 00472 00473 return ERROR; 00474 } 00475 00476 /** 00477 * @brief 00478 * @note 00479 * @param 00480 * @retval 00481 */ 00482 void HSCDTD008A::readData() 00483 { 00484 char data[6]; 00485 00486 _i2c->write(_addr, &OUTX_LSB, 1); 00487 _i2c->read(_addr, data, 6); 00488 00489 _x = *((uint16_t*) &data[0]); // two bytes, LSB first 00490 _y = *((uint16_t*) &data[2]); // two bytes, LSB first 00491 _z = *((uint16_t*) &data[4]); // two bytes, LSB first 00492 00493 // Debug print 00494 //printf("x = "); 00495 //printBinary(data[1]); 00496 //putc(' ', stdout); 00497 //printBinary(data[0]); 00498 //printf(" = %d \t= %f mT\r\n", _x, x()); 00499 //printf("y = "); 00500 //printBinary(data[3]); 00501 //putc(' ', stdout); 00502 //printBinary(data[2]); 00503 //printf(" = %d \t= %f mT\r\n", _y, y()); 00504 //printf("z = "); 00505 //printBinary(data[5]); 00506 //putc(' ', stdout); 00507 //printBinary(data[4]); 00508 //printf(" = %d \t= %f mT\r\n", _z, z()); 00509 } 00510 00511 /** 00512 * @brief 00513 * @note 00514 * @param 00515 * @retval 00516 */ 00517 float HSCDTD008A::x() 00518 { 00519 return toInt16(_x) * RANGE / RESOL; // mT 00520 } 00521 00522 /** 00523 * @brief 00524 * @note 00525 * @param 00526 * @retval 00527 */ 00528 float HSCDTD008A::y() 00529 { 00530 return toInt16(_y) * RANGE / RESOL; // mT 00531 } 00532 00533 /** 00534 * @brief 00535 * @note 00536 * @param 00537 * @retval 00538 */ 00539 float HSCDTD008A::z() 00540 { 00541 return toInt16(_z) * RANGE / RESOL; // mT 00542 }
Generated on Fri Jul 15 2022 14:06:39 by 1.7.2