Driver for the AKM AK9752 IR sensor device.
Library for the AK9752 Ultra-Small IR Sensor with I2C Interface. Includes integrated temperature sensor (0 - 50C) and 16-bit ADC.
Diff: AK9752.cpp
- Revision:
- 3:2035a4a54d3f
- Parent:
- 0:51fa46d39a3e
- Child:
- 6:254b7e5820e7
--- a/AK9752.cpp Fri Jul 08 22:27:55 2016 +0000 +++ b/AK9752.cpp Tue Nov 01 17:03:31 2016 +0000 @@ -1,20 +1,23 @@ #include "AK9752.h" #include "AK9752_reg.h" +/** + * Combine low and high int8_t bytes of Temp/IR data and store in int16_t variable + */ #define CONV16I(high,low) ((int16_t)(((high) << 8) | (low))) #define LEN_ONE_BYTE 1 /**<! Data length of 1 byte data. */ #define LEN_BUF_THRESHOLD 8 /**<! Data length of Threshold settings. From THIRH to THTMPL */ -#define LEN_BUF_IR_DATA 7 /**<! Data length of IR sensor data. From ST1 to ST2. */ -#define VAL_SOFTWARE_RESET 0x01 -#define ST1_STATUS_FLAG_DRDY 0x01 -#define INT_STATUS_FLAG_DR 0x01 -#define INT_STATUS_FLAG_TMPL 0x02 -#define INT_STATUS_FLAG_TMPH 0x04 -#define INT_STATUS_FLAG_IRL 0x08 -#define INT_STATUS_FLAG_IRH 0x10 -#define INT_STATUS_MASK 0x1F -#define ST2_STATUS_FLAG_DOR 0x01 +#define LEN_BUF_IR_DATA 7 /**<! Data length of IR sensor data: ST1,INTCAUSE,IR(16),TMP(16),ST2. */ +#define VAL_SOFTWARE_RESET 0x01 /**<! Software reset value. */ +#define ST1_STATUS_FLAG_DRDY 0x01 /**<! Data Ready*/ +#define INT_STATUS_FLAG_DR 0x01 /**<! Data Read */ +#define INT_STATUS_FLAG_TMPL 0x02 /**<! Temp low threshold reached */ +#define INT_STATUS_FLAG_TMPH 0x04 /**<! Temp high threshold reached */ +#define INT_STATUS_FLAG_IRL 0x08 /**<! IR low threshold reached */ +#define INT_STATUS_FLAG_IRH 0x10 /**<! IR high threshold reached */ +#define INT_STATUS_MASK 0x1F /**<! Mask highest 3 bits of status */ +#define ST2_STATUS_FLAG_DOR 0x01 /**<! Data overrun (data read is required) */ AK9752::AK9752() { @@ -43,13 +46,13 @@ } AK9752::Status AK9752::read(char registerAddress, char *buf, int length) { - // Writes a start address + // Tell slave address of where to read data if (connection->write((slaveAddress << 1), ®isterAddress, LEN_ONE_BYTE) != 0) { // I2C write failed. return AK9752::ERROR_I2C_WRITE; } - // Reads register data + // Read register data (converts 7-bit address to 8-bit) if (connection->read((slaveAddress << 1), buf, length) != 0) { // I2C read failed. return AK9752::ERROR_I2C_READ; @@ -59,16 +62,16 @@ } AK9752::Status AK9752::write(char registerAddress, const char *buf, int length) { - int bufLength = length + 1; + int bufLength = length + 1; // Increase size to account for address byte char data[bufLength]; // Creates data to be sent. - data[0] = registerAddress; + data[0] = registerAddress; // Place register address in first byte for (int i=0; i < length; i++) { - data[1+i] = buf[i]; + data[1+i] = buf[i]; // Load write data starting at second byte (i.e. data[1]) } - // Writes a start address. + // Initiate I2C write command if (connection->write((slaveAddress << 1), data, bufLength) != 0) { // I2C write failed. return AK9752::ERROR_I2C_WRITE; @@ -82,48 +85,45 @@ char buf = 0; if((status=read(AK9752_REG_ADDR_INTEN, &buf, LEN_ONE_BYTE)) != SUCCESS) { - return status; + return status; // Read failed } + // Set interrupt status flags individually intStatus->irh = ((buf & INT_STATUS_FLAG_IRH) > 0) ? true : false; intStatus->irl = ((buf & INT_STATUS_FLAG_IRL) > 0) ? true : false; intStatus->tmph = ((buf & INT_STATUS_FLAG_TMPH) > 0) ? true : false; intStatus->tmpl = ((buf & INT_STATUS_FLAG_TMPL) > 0) ? true : false; intStatus->dr = ((buf & INT_STATUS_FLAG_DR) > 0) ? true : false; - return SUCCESS; + return SUCCESS; // Read succeeded } -AK9752::Status AK9752::setInterruptEnable(const AK9752::InterruptStatus *intStatus) { +AK9752::Status AK9752::setInterruptEnable(const InterruptStatus *intStatus) { char buf = 0; + // If interrupt bit is 1, set corresponding buf bit to 1, otherwise set to 0 buf += intStatus->irh ? INT_STATUS_FLAG_IRH : 0; buf += intStatus->irl ? INT_STATUS_FLAG_IRL : 0; buf += intStatus->tmph ? INT_STATUS_FLAG_TMPH : 0; buf += intStatus->tmpl ? INT_STATUS_FLAG_TMPL : 0; buf += intStatus->dr ? INT_STATUS_FLAG_DR : 0; + // Perform interrupt status write operation Status status; if ((status=write(AK9752_REG_ADDR_INTEN, &buf, LEN_ONE_BYTE)) != SUCCESS) { return status; } + // Read back the interrupt status char readback = 0; if ((status=read(AK9752_REG_ADDR_INTEN, &readback, LEN_ONE_BYTE)) != SUCCESS) { - return status; - } - if ((readback & INT_STATUS_MASK) != buf) { - return ERROR; + return status; // Read back operation failed } - return SUCCESS; -} - -AK9752::Status AK9752::getData(char *buf) { - Status status; - if ((status=read(AK9752_REG_ADDR_ST1, buf, LEN_BUF_IR_DATA)) != SUCCESS) { - return status; + if ((readback & INT_STATUS_MASK) != buf) { + return ERROR; // Read back succeeded, but values incorrect } + return SUCCESS; } @@ -131,101 +131,110 @@ Status status; char buf[LEN_BUF_THRESHOLD]; - buf[0] = (char)(((uint16_t)th->thirh & 0x00FF)); // THIRHL - buf[1] = (char)(((uint16_t)th->thirh & 0xFF00) >> 8); // THIRHH - buf[2] = (char)(((uint16_t)th->thirl & 0x00FF)); // THIRLL - buf[3] = (char)(((uint16_t)th->thirl & 0xFF00) >> 8); // THIRLH - buf[4] = (char)(((uint16_t)th->thtmph & 0x00FF)); // THTMPHL - buf[5] = (char)(((uint16_t)th->thtmph & 0xFF00) >> 8); // THTMPHH - buf[6] = (char)(((uint16_t)th->thtmpl & 0x00FF)); // THTMPLL - buf[7] = (char)(((uint16_t)th->thtmpl & 0xFF00) >> 8); // THTMPLH + // Mask off irrelevant byte, cast 8-bit values to 16-bit + // + buf[0] = (char)(((uint16_t)th->thirh & 0x00FF)); // THIRHL Register + buf[1] = (char)(((uint16_t)th->thirh & 0xFF00) >> 8); // THIRHH Register + buf[2] = (char)(((uint16_t)th->thirl & 0x00FF)); // THIRLL Register + buf[3] = (char)(((uint16_t)th->thirl & 0xFF00) >> 8); // THIRLH Register + buf[4] = (char)(((uint16_t)th->thtmph & 0x00FF)); // THTMPHL Register + buf[5] = (char)(((uint16_t)th->thtmph & 0xFF00) >> 8); // THTMPHH Register + buf[6] = (char)(((uint16_t)th->thtmpl & 0x00FF)); // THTMPLL Register + buf[7] = (char)(((uint16_t)th->thtmpl & 0xFF00) >> 8); // THTMPLH Register + // Perform threshold register write operaton if ((status=write(AK9752_REG_ADDR_THIRHL, buf, LEN_BUF_THRESHOLD)) != SUCCESS) { - return status; + return status; // Write operation failed } - return SUCCESS; + return SUCCESS; // Write operation succeeded } AK9752::Status AK9752::getThreshold(Threshold *th) { Status status; char buf[LEN_BUF_THRESHOLD]; + // Perform threshold register read operation if ((status=read(AK9752_REG_ADDR_THIRHL, buf, LEN_BUF_THRESHOLD)) != SUCCESS) { - return status; + return status; // Read operation failed } + // Combine low and high bytes of data th->thirh = CONV16I(buf[1], buf[0]); th->thirl = CONV16I(buf[3], buf[2]); th->thtmph = CONV16I(buf[5], buf[4]); th->thtmpl = CONV16I(buf[7], buf[6]); - return SUCCESS; + return SUCCESS; // Read operation succeeded } AK9752::Status AK9752::getOperationMode(OperationMode *mode, FcTmp *fc_tmp, FcIr *fc_ir){ - Status status; + Status status; char buf[2]; if ((status=read(AK9752_REG_ADDR_CNTL1, buf, 2)) != SUCCESS) { - return status; + return status; // Read operation failed } - *fc_tmp = AK9752::FcTmp((buf[0] & 0x1C)>>2); - *fc_ir = AK9752::FcIr(buf[0] & 0x03); - *mode = AK9752::OperationMode(buf[1] & 0x03); - return SUCCESS; + *fc_tmp = AK9752::FcTmp((buf[0] & 0x1C)>>2); // Read CNTL1[2]-CNTL1[4] + *fc_ir = AK9752::FcIr(buf[0] & 0x03); // Read CNTL1[0]-CNTL1[1] + *mode = AK9752::OperationMode(buf[1] & 0x03); // Read CNTL2[0]-CNTL2[1] + + return SUCCESS; // Read operation succeeded } AK9752::Status AK9752::setOperationMode(OperationMode mode, FcTmp fc_tmp, FcIr fc_ir){ Status status; char buf[2]; - buf[0] = (fc_tmp<<2 | fc_ir&0x03); + buf[0] = (fc_tmp<<2 | fc_ir&0x03); // Combine FCTMP & FCIR in 1 byte buf[1] = mode; + + // Write 2 bytes starting from CNTL1 -> write CNTL1 and CNTL2 if ((status=write(AK9752_REG_ADDR_CNTL1, buf, 2)) != SUCCESS) { - return status; + return status; // Write operation failed } - return SUCCESS; + return SUCCESS; // Write operation succeeded } AK9752::Status AK9752::reset() { Status status; - char val = VAL_SOFTWARE_RESET; + + char val = VAL_SOFTWARE_RESET; // char instance required for write() if ((status=write(AK9752_REG_ADDR_CNTL3, &val, LEN_ONE_BYTE)) != SUCCESS) { - return status; + return status; // Write operation failed } - return SUCCESS; + return SUCCESS; // Write operation succeeded } -AK9752::Status AK9752::getSensorData(AK9752::SensorData *data) { - Status status; +AK9752::Status AK9752::getSensorData(SensorData *data) { + char buf[LEN_BUF_IR_DATA]; - if ((status=getData(buf)) != SUCCESS) { - return status; + // Read 7 bytes starting at ST1: reads ST1, INTCAUSE, data and ST2 at once + if ((read(AK9752_REG_ADDR_ST1, buf, LEN_BUF_IR_DATA)) != SUCCESS) { + return ERROR; // Read operation failed } - // check DRDY - if( (buf[0] & ST1_STATUS_FLAG_DRDY) == 0 ){ - // DRDY=0, data not ready + // Check Data ReaDY + if( (buf[0] & ST1_STATUS_FLAG_DRDY) == 0 ){ // DRDY=0, data not ready return ERROR; } - // Interrupt Status + // Read IR threshold, temp threshold and data ready flags data->intStatus.irh = ((buf[1] & INT_STATUS_FLAG_IRH) > 0) ? true : false; data->intStatus.irl = ((buf[1] & INT_STATUS_FLAG_IRL) > 0) ? true : false; data->intStatus.tmph = ((buf[1] & INT_STATUS_FLAG_TMPH) > 0) ? true : false; data->intStatus.tmpl = ((buf[1] & INT_STATUS_FLAG_TMPL) > 0) ? true : false; data->intStatus.dr = ((buf[1] & INT_STATUS_FLAG_DR) > 0) ? true : false; - // IR sensor data - data->ir = (int16_t)((buf[3] << 8) | buf[2]); + // Extract IR sensor data + data->ir = (int16_t)((buf[3] << 8) | buf[2]); // Combine IRL & IRH - // Temperature sensor data - data->temperature = (int16_t)((buf[5] << 8) | buf[4]); + // Extract Temperature sensor data + data->temperature = (int16_t)((buf[5] << 8) | buf[4]); // Combine TMPL & TMPH - // DOR Status + // Extract Data Overrun status data->dor = ((buf[1] & ST2_STATUS_FLAG_DOR) > 0) ? true : false; return SUCCESS;