This is a device driver of AK8963, which is 3-axis magnetometer manufactured by AKM.
Dependents: SimpleSample combination combination
ak8963.cpp
00001 #include "ak8963.h" 00002 00003 // REGISTER MAP 00004 #define AK8963_REG_WIA 0x00 00005 #define AK8963_REG_INFO 0x01 00006 #define AK8963_REG_ST1 0x02 00007 #define AK8963_REG_HXL 0x03 00008 #define AK8963_REG_HXH 0x04 00009 #define AK8963_REG_HYL 0x05 00010 #define AK8963_REG_HYH 0x06 00011 #define AK8963_REG_HZL 0x07 00012 #define AK8963_REG_HZH 0x08 00013 #define AK8963_REG_ST2 0x09 00014 #define AK8963_REG_CNTL1 0x0A 00015 #define AK8963_REG_CNTL2 0x0B 00016 #define AK8963_REG_ASTC 0x0C 00017 #define AK8963_REG_TS1 0x0D 00018 #define AK8963_REG_TS2 0x0E 00019 #define AK8963_REG_I2CDIS 0x0F 00020 #define AK8963_REG_ASAX 0x10 00021 #define AK8963_REG_ASAY 0x11 00022 #define AK8963_REG_ASAZ 0x12 00023 #define AK8963_REG_RSV 0x13 00024 00025 // BITS in CNTL1 register 00026 #define AK8963_CNTL1_MODE_PDN 0x00 // POWER DOWN MODE 00027 #define AK8963_CNTL1_MODE_SNG 0x01 // SINGLE MEASUREMENT MODE 00028 #define AK8963_CNTL1_MODE_CNT1 0x02 // CONTINUOUS MEASUREMENT MODE 1 00029 #define AK8963_CNTL1_MODE_CNT2 0x06 // CONTINUOUS MEASUREMENT MODE 2 00030 #define AK8963_CNTL1_MODE_EXT 0x04 // EXTERNAL TRIGGER MEASUREMENT MODE 00031 #define AK8963_CNTL1_MODE_TEST 0x08 // SELF-TEST MODE 00032 #define AK8963_CNTL1_MODE_FUSE_ROM 0x0F // FUSE ROM ACCESS MODE 00033 #define AK8963_CNTL1_OUTPUT_14BIT 0x00 00034 #define AK8963_CNTL1_OUTPUT_16BIT 0x10 00035 00036 #define AK8963_BIT_MASK_DRDY 0x01 00037 00038 #define AK8963_BIT_MASK_HOFL 0x08 00039 00040 #define AK8963_REG_WIA_VAL 0x48 00041 00042 #define AK8963_BUF_LENGTH_ASA 3 00043 #define AK8963_BUF_LENGTH_BDATA 8 00044 #define AK8963_WAIT_MODE_TRANSITION 100 00045 #define AK8963_DEFAULT_OUTPUT_BIT AK8963_CNTL1_OUTPUT_16BIT 00046 #define AK8963_SENSITIVITY (0.15) // uT/LSB 00047 00048 #define AK8963_WAIT_POWER_DOWN_US 100 00049 00050 #define LEN_ONE_BYTE 1 00051 00052 AK8963::AK8963(I2C *conn, SlaveAddress addr) { 00053 slaveAddress = addr; 00054 connection = conn; 00055 getSensitivityAdjustment(&sensitivityAdjustment); 00056 } 00057 00058 AK8963::Status AK8963::checkConnection() { 00059 AK8963::Status status = AK8963::SUCCESS; 00060 00061 // Gets the WIA register value. 00062 char wiaValue = 0; 00063 if ((status=AK8963::read(AK8963_REG_WIA, &wiaValue, LEN_ONE_BYTE)) != SUCCESS) { 00064 return status; 00065 } 00066 00067 // Checks the obtained value equals to the supposed value. 00068 if (wiaValue != AK8963_REG_WIA_VAL) { 00069 return AK8963::ERROR; 00070 } 00071 00072 return status; 00073 } 00074 00075 AK8963::Status AK8963::read(char registerAddress, char *buf, int length) { 00076 // Writes a start address 00077 if (connection->write((slaveAddress << 1), ®isterAddress, LEN_ONE_BYTE) != 0) { 00078 // I2C write failed. 00079 return AK8963::ERROR_I2C_WRITE; 00080 } 00081 00082 // Reads register data 00083 if (connection->read((slaveAddress << 1), buf, length) != 0) { 00084 // I2C read failed. 00085 return AK8963::ERROR_I2C_READ; 00086 } 00087 00088 return AK8963::SUCCESS; 00089 } 00090 00091 AK8963::Status AK8963::write(char registerAddress, const char *buf, int length) { 00092 int bufLength = length + 1; 00093 char data[bufLength]; 00094 00095 // Creates data to be sent. 00096 data[0] = registerAddress; 00097 for (int i=0; i < length; i++) { 00098 data[1+i] = buf[i]; 00099 } 00100 00101 // Writes data 00102 if (connection->write((slaveAddress << 1), data, bufLength) != 0) { 00103 // I2C write failed. 00104 return AK8963::ERROR_I2C_WRITE; 00105 } 00106 00107 return AK8963::SUCCESS; 00108 } 00109 00110 AK8963::Status AK8963::isDataReady() { 00111 AK8963::Status status = AK8963::ERROR; 00112 00113 // Gets the ST1 register value. 00114 char st1Value = 0; 00115 if ((status=AK8963::read(AK8963_REG_ST1, &st1Value, LEN_ONE_BYTE)) != AK8963::SUCCESS) { 00116 // I2C read failed. 00117 return status; 00118 } 00119 00120 // Sets a return status corresponds to the obtained value. 00121 if ((st1Value & AK8963_BIT_MASK_DRDY) > 0) { 00122 status = AK8963::DATA_READY; 00123 } else { 00124 status = AK8963::NOT_DATA_READY; 00125 } 00126 00127 return status; 00128 } 00129 00130 AK8963::Status AK8963::getData(char *buf) { 00131 AK8963::Status status = AK8963::ERROR; 00132 00133 if ((status=AK8963::read(AK8963_REG_ST1, buf, AK8963_BUF_LENGTH_BDATA)) != AK8963::SUCCESS) { 00134 // I2C read failed. 00135 return status; 00136 } 00137 00138 return status; 00139 } 00140 00141 AK8963::Status AK8963::setOperationMode(AK8963::OperationMode mode) { 00142 AK8963::Status status = AK8963::ERROR; 00143 00144 // The device has to be put into power-down mode first before switching mode. 00145 char buf = AK8963::MODE_POWER_DOWN; 00146 if (mode != AK8963::MODE_POWER_DOWN) { 00147 if ((status=AK8963::write(AK8963_REG_CNTL1, &buf, LEN_ONE_BYTE)) != AK8963::SUCCESS) { 00148 // I2C write failed. 00149 return status; 00150 } 00151 wait_us(AK8963_WAIT_POWER_DOWN_US); 00152 } 00153 00154 00155 // Switch to the specified mode. 00156 buf = (mode | AK8963_CNTL1_OUTPUT_16BIT); 00157 if ((status=AK8963::write(AK8963_REG_CNTL1, &buf, LEN_ONE_BYTE)) != AK8963::SUCCESS) { 00158 // I2C write failed. 00159 return status; 00160 } 00161 00162 wait_us(AK8963_WAIT_POWER_DOWN_US); 00163 00164 return AK8963::SUCCESS; 00165 } 00166 00167 AK8963::Status AK8963::getMagneticVector(MagneticVector *vec) { 00168 AK8963::Status status = AK8963::ERROR; 00169 char buf[AK8963_BUF_LENGTH_BDATA]; 00170 00171 if ((status=AK8963::getData(buf)) != AK8963::SUCCESS) { 00172 // Failed to get data. 00173 return status; 00174 } 00175 00176 // Checks sensor overflow 00177 if ((buf[7] & AK8963_BIT_MASK_HOFL) > 0) { 00178 // Magnetic sensor overflow 00179 vec->isOverflow = true; 00180 } else { 00181 // Magnetic sensor didn't overflow. 00182 vec->isOverflow = false; 00183 // Calculates magnetic field value 00184 int16_t xi = (int16_t)((buf[2] << 8) | buf[1]); 00185 int16_t yi = (int16_t)((buf[4] << 8) | buf[3]); 00186 int16_t zi = (int16_t)((buf[6] << 8) | buf[5]); 00187 vec->mx = (float)(xi * ((sensitivityAdjustment.x + 128)/256.0) * AK8963_SENSITIVITY); 00188 vec->my = (float)(yi * ((sensitivityAdjustment.y + 128)/256.0) * AK8963_SENSITIVITY); 00189 vec->mz = (float)(zi * ((sensitivityAdjustment.z + 128)/256.0) * AK8963_SENSITIVITY); 00190 } 00191 00192 return AK8963::SUCCESS; 00193 } 00194 00195 00196 AK8963::Status AK8963::getSensitivityAdjustment(SensitivityAdjustment *sns) { 00197 AK8963::Status status = AK8963::ERROR; 00198 00199 // Set the device into the fuse ROM access mode. 00200 char data = AK8963_CNTL1_MODE_FUSE_ROM; 00201 if ((status=AK8963::write(AK8963_REG_CNTL1, &data, LEN_ONE_BYTE)) != AK8963::SUCCESS) { 00202 // I2C write failed. 00203 return status; 00204 } 00205 00206 // Wait 00207 wait_us(AK8963_WAIT_POWER_DOWN_US); 00208 00209 // Read the fuse ROM 00210 char buf[AK8963_BUF_LENGTH_ASA]; 00211 if ((status=AK8963::read(AK8963_REG_ASAX, buf, AK8963_BUF_LENGTH_ASA)) != AK8963::SUCCESS) { 00212 // I2C read failed. 00213 return status; 00214 } 00215 00216 sns->x = buf[0]; 00217 sns->y = buf[1]; 00218 sns->z = buf[2]; 00219 00220 // Set the device into the power-down mode 00221 data = AK8963_CNTL1_MODE_PDN; 00222 if ((status=AK8963::write(AK8963_REG_CNTL1, &data, LEN_ONE_BYTE)) != AK8963::SUCCESS) { 00223 // I2C write failed. 00224 return status; 00225 } 00226 00227 // Wait 00228 wait_us(AK8963_WAIT_POWER_DOWN_US); 00229 00230 return AK8963::SUCCESS; 00231 } 00232
Generated on Wed Jul 13 2022 16:32:57 by 1.7.2