This is a device driver of AK8963, which is 3-axis magnetometer manufactured by AKM.
Dependents: SimpleSample combination combination
ak8963.cpp@2:9dff393e5e86, 2015-09-04 (annotated)
- Committer:
- coisme
- Date:
- Fri Sep 04 23:39:10 2015 +0000
- Revision:
- 2:9dff393e5e86
- Parent:
- 1:a362b9e3aac2
maintainance
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
coisme | 0:fc56973c077a | 1 | #include "ak8963.h" |
coisme | 0:fc56973c077a | 2 | |
coisme | 0:fc56973c077a | 3 | // REGISTER MAP |
coisme | 0:fc56973c077a | 4 | #define AK8963_REG_WIA 0x00 |
coisme | 0:fc56973c077a | 5 | #define AK8963_REG_INFO 0x01 |
coisme | 0:fc56973c077a | 6 | #define AK8963_REG_ST1 0x02 |
coisme | 0:fc56973c077a | 7 | #define AK8963_REG_HXL 0x03 |
coisme | 0:fc56973c077a | 8 | #define AK8963_REG_HXH 0x04 |
coisme | 0:fc56973c077a | 9 | #define AK8963_REG_HYL 0x05 |
coisme | 0:fc56973c077a | 10 | #define AK8963_REG_HYH 0x06 |
coisme | 0:fc56973c077a | 11 | #define AK8963_REG_HZL 0x07 |
coisme | 0:fc56973c077a | 12 | #define AK8963_REG_HZH 0x08 |
coisme | 0:fc56973c077a | 13 | #define AK8963_REG_ST2 0x09 |
coisme | 0:fc56973c077a | 14 | #define AK8963_REG_CNTL1 0x0A |
coisme | 0:fc56973c077a | 15 | #define AK8963_REG_CNTL2 0x0B |
coisme | 0:fc56973c077a | 16 | #define AK8963_REG_ASTC 0x0C |
coisme | 0:fc56973c077a | 17 | #define AK8963_REG_TS1 0x0D |
coisme | 0:fc56973c077a | 18 | #define AK8963_REG_TS2 0x0E |
coisme | 0:fc56973c077a | 19 | #define AK8963_REG_I2CDIS 0x0F |
coisme | 0:fc56973c077a | 20 | #define AK8963_REG_ASAX 0x10 |
coisme | 0:fc56973c077a | 21 | #define AK8963_REG_ASAY 0x11 |
coisme | 0:fc56973c077a | 22 | #define AK8963_REG_ASAZ 0x12 |
coisme | 0:fc56973c077a | 23 | #define AK8963_REG_RSV 0x13 |
coisme | 0:fc56973c077a | 24 | |
coisme | 0:fc56973c077a | 25 | // BITS in CNTL1 register |
coisme | 0:fc56973c077a | 26 | #define AK8963_CNTL1_MODE_PDN 0x00 // POWER DOWN MODE |
coisme | 0:fc56973c077a | 27 | #define AK8963_CNTL1_MODE_SNG 0x01 // SINGLE MEASUREMENT MODE |
coisme | 0:fc56973c077a | 28 | #define AK8963_CNTL1_MODE_CNT1 0x02 // CONTINUOUS MEASUREMENT MODE 1 |
coisme | 0:fc56973c077a | 29 | #define AK8963_CNTL1_MODE_CNT2 0x06 // CONTINUOUS MEASUREMENT MODE 2 |
coisme | 0:fc56973c077a | 30 | #define AK8963_CNTL1_MODE_EXT 0x04 // EXTERNAL TRIGGER MEASUREMENT MODE |
coisme | 0:fc56973c077a | 31 | #define AK8963_CNTL1_MODE_TEST 0x08 // SELF-TEST MODE |
coisme | 0:fc56973c077a | 32 | #define AK8963_CNTL1_MODE_FUSE_ROM 0x0F // FUSE ROM ACCESS MODE |
coisme | 0:fc56973c077a | 33 | #define AK8963_CNTL1_OUTPUT_14BIT 0x00 |
coisme | 0:fc56973c077a | 34 | #define AK8963_CNTL1_OUTPUT_16BIT 0x10 |
coisme | 0:fc56973c077a | 35 | |
coisme | 0:fc56973c077a | 36 | #define AK8963_BIT_MASK_DRDY 0x01 |
coisme | 0:fc56973c077a | 37 | |
coisme | 1:a362b9e3aac2 | 38 | #define AK8963_BIT_MASK_HOFL 0x08 |
coisme | 1:a362b9e3aac2 | 39 | |
coisme | 0:fc56973c077a | 40 | #define AK8963_REG_WIA_VAL 0x48 |
coisme | 0:fc56973c077a | 41 | |
coisme | 0:fc56973c077a | 42 | #define AK8963_BUF_LENGTH_ASA 3 |
coisme | 0:fc56973c077a | 43 | #define AK8963_BUF_LENGTH_BDATA 8 |
coisme | 0:fc56973c077a | 44 | #define AK8963_WAIT_MODE_TRANSITION 100 |
coisme | 0:fc56973c077a | 45 | #define AK8963_DEFAULT_OUTPUT_BIT AK8963_CNTL1_OUTPUT_16BIT |
coisme | 0:fc56973c077a | 46 | #define AK8963_SENSITIVITY (0.15) // uT/LSB |
coisme | 0:fc56973c077a | 47 | |
coisme | 1:a362b9e3aac2 | 48 | #define AK8963_WAIT_POWER_DOWN_US 100 |
coisme | 0:fc56973c077a | 49 | |
coisme | 0:fc56973c077a | 50 | #define LEN_ONE_BYTE 1 |
coisme | 0:fc56973c077a | 51 | |
coisme | 0:fc56973c077a | 52 | AK8963::AK8963(I2C *conn, SlaveAddress addr) { |
coisme | 0:fc56973c077a | 53 | slaveAddress = addr; |
coisme | 0:fc56973c077a | 54 | connection = conn; |
coisme | 0:fc56973c077a | 55 | getSensitivityAdjustment(&sensitivityAdjustment); |
coisme | 0:fc56973c077a | 56 | } |
coisme | 0:fc56973c077a | 57 | |
coisme | 0:fc56973c077a | 58 | AK8963::Status AK8963::checkConnection() { |
coisme | 0:fc56973c077a | 59 | AK8963::Status status = AK8963::SUCCESS; |
coisme | 0:fc56973c077a | 60 | |
coisme | 0:fc56973c077a | 61 | // Gets the WIA register value. |
coisme | 0:fc56973c077a | 62 | char wiaValue = 0; |
coisme | 0:fc56973c077a | 63 | if ((status=AK8963::read(AK8963_REG_WIA, &wiaValue, LEN_ONE_BYTE)) != SUCCESS) { |
coisme | 0:fc56973c077a | 64 | return status; |
coisme | 0:fc56973c077a | 65 | } |
coisme | 0:fc56973c077a | 66 | |
coisme | 0:fc56973c077a | 67 | // Checks the obtained value equals to the supposed value. |
coisme | 0:fc56973c077a | 68 | if (wiaValue != AK8963_REG_WIA_VAL) { |
coisme | 0:fc56973c077a | 69 | return AK8963::ERROR; |
coisme | 0:fc56973c077a | 70 | } |
coisme | 0:fc56973c077a | 71 | |
coisme | 0:fc56973c077a | 72 | return status; |
coisme | 0:fc56973c077a | 73 | } |
coisme | 0:fc56973c077a | 74 | |
coisme | 0:fc56973c077a | 75 | AK8963::Status AK8963::read(char registerAddress, char *buf, int length) { |
coisme | 0:fc56973c077a | 76 | // Writes a start address |
coisme | 0:fc56973c077a | 77 | if (connection->write((slaveAddress << 1), ®isterAddress, LEN_ONE_BYTE) != 0) { |
coisme | 0:fc56973c077a | 78 | // I2C write failed. |
coisme | 0:fc56973c077a | 79 | return AK8963::ERROR_I2C_WRITE; |
coisme | 0:fc56973c077a | 80 | } |
coisme | 0:fc56973c077a | 81 | |
coisme | 0:fc56973c077a | 82 | // Reads register data |
coisme | 0:fc56973c077a | 83 | if (connection->read((slaveAddress << 1), buf, length) != 0) { |
coisme | 0:fc56973c077a | 84 | // I2C read failed. |
coisme | 0:fc56973c077a | 85 | return AK8963::ERROR_I2C_READ; |
coisme | 0:fc56973c077a | 86 | } |
coisme | 0:fc56973c077a | 87 | |
coisme | 0:fc56973c077a | 88 | return AK8963::SUCCESS; |
coisme | 0:fc56973c077a | 89 | } |
coisme | 0:fc56973c077a | 90 | |
coisme | 0:fc56973c077a | 91 | AK8963::Status AK8963::write(char registerAddress, const char *buf, int length) { |
coisme | 0:fc56973c077a | 92 | int bufLength = length + 1; |
coisme | 0:fc56973c077a | 93 | char data[bufLength]; |
coisme | 0:fc56973c077a | 94 | |
coisme | 0:fc56973c077a | 95 | // Creates data to be sent. |
coisme | 0:fc56973c077a | 96 | data[0] = registerAddress; |
coisme | 0:fc56973c077a | 97 | for (int i=0; i < length; i++) { |
coisme | 0:fc56973c077a | 98 | data[1+i] = buf[i]; |
coisme | 0:fc56973c077a | 99 | } |
coisme | 0:fc56973c077a | 100 | |
coisme | 2:9dff393e5e86 | 101 | // Writes data |
coisme | 0:fc56973c077a | 102 | if (connection->write((slaveAddress << 1), data, bufLength) != 0) { |
coisme | 0:fc56973c077a | 103 | // I2C write failed. |
coisme | 0:fc56973c077a | 104 | return AK8963::ERROR_I2C_WRITE; |
coisme | 0:fc56973c077a | 105 | } |
coisme | 0:fc56973c077a | 106 | |
coisme | 0:fc56973c077a | 107 | return AK8963::SUCCESS; |
coisme | 0:fc56973c077a | 108 | } |
coisme | 0:fc56973c077a | 109 | |
coisme | 0:fc56973c077a | 110 | AK8963::Status AK8963::isDataReady() { |
coisme | 0:fc56973c077a | 111 | AK8963::Status status = AK8963::ERROR; |
coisme | 0:fc56973c077a | 112 | |
coisme | 0:fc56973c077a | 113 | // Gets the ST1 register value. |
coisme | 0:fc56973c077a | 114 | char st1Value = 0; |
coisme | 0:fc56973c077a | 115 | if ((status=AK8963::read(AK8963_REG_ST1, &st1Value, LEN_ONE_BYTE)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 116 | // I2C read failed. |
coisme | 0:fc56973c077a | 117 | return status; |
coisme | 0:fc56973c077a | 118 | } |
coisme | 0:fc56973c077a | 119 | |
coisme | 0:fc56973c077a | 120 | // Sets a return status corresponds to the obtained value. |
coisme | 0:fc56973c077a | 121 | if ((st1Value & AK8963_BIT_MASK_DRDY) > 0) { |
coisme | 0:fc56973c077a | 122 | status = AK8963::DATA_READY; |
coisme | 0:fc56973c077a | 123 | } else { |
coisme | 0:fc56973c077a | 124 | status = AK8963::NOT_DATA_READY; |
coisme | 0:fc56973c077a | 125 | } |
coisme | 0:fc56973c077a | 126 | |
coisme | 0:fc56973c077a | 127 | return status; |
coisme | 0:fc56973c077a | 128 | } |
coisme | 0:fc56973c077a | 129 | |
coisme | 0:fc56973c077a | 130 | AK8963::Status AK8963::getData(char *buf) { |
coisme | 0:fc56973c077a | 131 | AK8963::Status status = AK8963::ERROR; |
coisme | 0:fc56973c077a | 132 | |
coisme | 0:fc56973c077a | 133 | if ((status=AK8963::read(AK8963_REG_ST1, buf, AK8963_BUF_LENGTH_BDATA)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 134 | // I2C read failed. |
coisme | 0:fc56973c077a | 135 | return status; |
coisme | 0:fc56973c077a | 136 | } |
coisme | 0:fc56973c077a | 137 | |
coisme | 0:fc56973c077a | 138 | return status; |
coisme | 0:fc56973c077a | 139 | } |
coisme | 0:fc56973c077a | 140 | |
coisme | 0:fc56973c077a | 141 | AK8963::Status AK8963::setOperationMode(AK8963::OperationMode mode) { |
coisme | 0:fc56973c077a | 142 | AK8963::Status status = AK8963::ERROR; |
coisme | 0:fc56973c077a | 143 | |
coisme | 0:fc56973c077a | 144 | // The device has to be put into power-down mode first before switching mode. |
coisme | 1:a362b9e3aac2 | 145 | char buf = AK8963::MODE_POWER_DOWN; |
coisme | 0:fc56973c077a | 146 | if (mode != AK8963::MODE_POWER_DOWN) { |
coisme | 0:fc56973c077a | 147 | if ((status=AK8963::write(AK8963_REG_CNTL1, &buf, LEN_ONE_BYTE)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 148 | // I2C write failed. |
coisme | 0:fc56973c077a | 149 | return status; |
coisme | 0:fc56973c077a | 150 | } |
coisme | 0:fc56973c077a | 151 | wait_us(AK8963_WAIT_POWER_DOWN_US); |
coisme | 0:fc56973c077a | 152 | } |
coisme | 0:fc56973c077a | 153 | |
coisme | 0:fc56973c077a | 154 | |
coisme | 0:fc56973c077a | 155 | // Switch to the specified mode. |
coisme | 1:a362b9e3aac2 | 156 | buf = (mode | AK8963_CNTL1_OUTPUT_16BIT); |
coisme | 0:fc56973c077a | 157 | if ((status=AK8963::write(AK8963_REG_CNTL1, &buf, LEN_ONE_BYTE)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 158 | // I2C write failed. |
coisme | 0:fc56973c077a | 159 | return status; |
coisme | 0:fc56973c077a | 160 | } |
coisme | 0:fc56973c077a | 161 | |
coisme | 0:fc56973c077a | 162 | wait_us(AK8963_WAIT_POWER_DOWN_US); |
coisme | 0:fc56973c077a | 163 | |
coisme | 0:fc56973c077a | 164 | return AK8963::SUCCESS; |
coisme | 0:fc56973c077a | 165 | } |
coisme | 0:fc56973c077a | 166 | |
coisme | 0:fc56973c077a | 167 | AK8963::Status AK8963::getMagneticVector(MagneticVector *vec) { |
coisme | 0:fc56973c077a | 168 | AK8963::Status status = AK8963::ERROR; |
coisme | 0:fc56973c077a | 169 | char buf[AK8963_BUF_LENGTH_BDATA]; |
coisme | 0:fc56973c077a | 170 | |
coisme | 0:fc56973c077a | 171 | if ((status=AK8963::getData(buf)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 172 | // Failed to get data. |
coisme | 0:fc56973c077a | 173 | return status; |
coisme | 0:fc56973c077a | 174 | } |
coisme | 0:fc56973c077a | 175 | |
coisme | 1:a362b9e3aac2 | 176 | // Checks sensor overflow |
coisme | 1:a362b9e3aac2 | 177 | if ((buf[7] & AK8963_BIT_MASK_HOFL) > 0) { |
coisme | 1:a362b9e3aac2 | 178 | // Magnetic sensor overflow |
coisme | 1:a362b9e3aac2 | 179 | vec->isOverflow = true; |
coisme | 1:a362b9e3aac2 | 180 | } else { |
coisme | 1:a362b9e3aac2 | 181 | // Magnetic sensor didn't overflow. |
coisme | 1:a362b9e3aac2 | 182 | vec->isOverflow = false; |
coisme | 1:a362b9e3aac2 | 183 | // Calculates magnetic field value |
coisme | 1:a362b9e3aac2 | 184 | int16_t xi = (int16_t)((buf[2] << 8) | buf[1]); |
coisme | 1:a362b9e3aac2 | 185 | int16_t yi = (int16_t)((buf[4] << 8) | buf[3]); |
coisme | 1:a362b9e3aac2 | 186 | int16_t zi = (int16_t)((buf[6] << 8) | buf[5]); |
coisme | 1:a362b9e3aac2 | 187 | vec->mx = (float)(xi * ((sensitivityAdjustment.x + 128)/256.0) * AK8963_SENSITIVITY); |
coisme | 1:a362b9e3aac2 | 188 | vec->my = (float)(yi * ((sensitivityAdjustment.y + 128)/256.0) * AK8963_SENSITIVITY); |
coisme | 1:a362b9e3aac2 | 189 | vec->mz = (float)(zi * ((sensitivityAdjustment.z + 128)/256.0) * AK8963_SENSITIVITY); |
coisme | 1:a362b9e3aac2 | 190 | } |
coisme | 1:a362b9e3aac2 | 191 | |
coisme | 0:fc56973c077a | 192 | return AK8963::SUCCESS; |
coisme | 0:fc56973c077a | 193 | } |
coisme | 0:fc56973c077a | 194 | |
coisme | 0:fc56973c077a | 195 | |
coisme | 0:fc56973c077a | 196 | AK8963::Status AK8963::getSensitivityAdjustment(SensitivityAdjustment *sns) { |
coisme | 0:fc56973c077a | 197 | AK8963::Status status = AK8963::ERROR; |
coisme | 0:fc56973c077a | 198 | |
coisme | 0:fc56973c077a | 199 | // Set the device into the fuse ROM access mode. |
coisme | 0:fc56973c077a | 200 | char data = AK8963_CNTL1_MODE_FUSE_ROM; |
coisme | 0:fc56973c077a | 201 | if ((status=AK8963::write(AK8963_REG_CNTL1, &data, LEN_ONE_BYTE)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 202 | // I2C write failed. |
coisme | 0:fc56973c077a | 203 | return status; |
coisme | 0:fc56973c077a | 204 | } |
coisme | 0:fc56973c077a | 205 | |
coisme | 0:fc56973c077a | 206 | // Wait |
coisme | 0:fc56973c077a | 207 | wait_us(AK8963_WAIT_POWER_DOWN_US); |
coisme | 0:fc56973c077a | 208 | |
coisme | 0:fc56973c077a | 209 | // Read the fuse ROM |
coisme | 0:fc56973c077a | 210 | char buf[AK8963_BUF_LENGTH_ASA]; |
coisme | 0:fc56973c077a | 211 | if ((status=AK8963::read(AK8963_REG_ASAX, buf, AK8963_BUF_LENGTH_ASA)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 212 | // I2C read failed. |
coisme | 0:fc56973c077a | 213 | return status; |
coisme | 0:fc56973c077a | 214 | } |
coisme | 0:fc56973c077a | 215 | |
coisme | 0:fc56973c077a | 216 | sns->x = buf[0]; |
coisme | 0:fc56973c077a | 217 | sns->y = buf[1]; |
coisme | 0:fc56973c077a | 218 | sns->z = buf[2]; |
coisme | 0:fc56973c077a | 219 | |
coisme | 0:fc56973c077a | 220 | // Set the device into the power-down mode |
coisme | 0:fc56973c077a | 221 | data = AK8963_CNTL1_MODE_PDN; |
coisme | 0:fc56973c077a | 222 | if ((status=AK8963::write(AK8963_REG_CNTL1, &data, LEN_ONE_BYTE)) != AK8963::SUCCESS) { |
coisme | 0:fc56973c077a | 223 | // I2C write failed. |
coisme | 0:fc56973c077a | 224 | return status; |
coisme | 0:fc56973c077a | 225 | } |
coisme | 0:fc56973c077a | 226 | |
coisme | 0:fc56973c077a | 227 | // Wait |
coisme | 0:fc56973c077a | 228 | wait_us(AK8963_WAIT_POWER_DOWN_US); |
coisme | 0:fc56973c077a | 229 | |
coisme | 0:fc56973c077a | 230 | return AK8963::SUCCESS; |
coisme | 0:fc56973c077a | 231 | } |
coisme | 0:fc56973c077a | 232 |