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

Dependents:   SimpleSample combination combination

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ak8963.cpp Source File

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