This is a device driver of AK8963, which is 3-axis magnetometer manufactured by AKM.

Dependents:   SimpleSample combination combination

Committer:
coisme
Date:
Fri Sep 04 23:39:10 2015 +0000
Revision:
2:9dff393e5e86
Parent:
1:a362b9e3aac2
maintainance

Who changed what in which revision?

UserRevisionLine numberNew 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), &registerAddress, 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