VCNL4020, Fully Integrated Proximity and Ambient Light Sensor with Infrared Emitter, I2C Interface, and Interrupt Function
Dependents: testVCNL4020 testSensor
VCNL4020.cpp
- Committer:
- Rhyme
- Date:
- 2017-04-29
- Revision:
- 1:4f4cdaf51fc2
- Parent:
- 0:95952f8fe2b4
File content as of revision 1:4f4cdaf51fc2:
#include "mbed.h" #include "VCNL4020.h" /* Register address definitions */ #define REG_COMMAND 0x80 #define REG_PRODUCT_ID_REV 0x81 #define REG_PROXIMITY_RATE 0x82 #define REG_IR_LED_CURRENT 0x83 #define REG_AMBIENT_LIGHT_PARAM 0x84 #define REG_AMBIENT_LIGHT_RESULT 0x85 #define REG_AMBIENT_LIGHT_MSB 0x85 #define REG_AMBIENT_LIGHT_LSB 0x86 #define REG_PROXIMITY_RESULT 0x87 #define REG_PROXIMITY_MSB 0x87 #define REG_PROXIMITY_LSB 0x88 #define REG_INTERRUPT_CONTROL 0x89 #define REG_LOW_THRESHOLD_MSB 0x8A #define REG_LOW_THRESHOLD_LSB 0x8B #define REG_HIGH_THRESHOLD_MSB 0x8C #define REG_HIGH_THRESHOLD_LSB 0x8D #define REG_INTERRUPT_STATUS 0x8E #define REG_PROXIMITY_MOD_TIMING 0x8F /* bit definitions */ /* Command Register (0x80) Register #0 */ /* bit[7] config_lock Read only bit. Value = 1 */ #define BIT_CONFIG_LOCK 0x80 /* bit[6] als_data_rdy Read only bit. * Value = 1 when ambient light measurement data is availabe in thre result registers. * This bit will be reset when one of the corresponding result registers (reg #5, reg #6) is read */ #define BIT_ALS_DATA_RDY 0x40 /* bit[5] prox_data_rdy Read only bit. * Value = 1 when proximity measurement data is available in the result registers. * This bit will be reset when one of the corresponding result registers (reg #7, reg #8) is read */ #define BIT_PROX_DATA_RDY 0x20 /* bit[4] als_od R/W bit. * Starts a single on-demand measurement for ambient light. * If averaging is enabled, starts a sequence of readings and stores the averaged result. * Result is available at the end of conversion for reading in the registers #5(HB) and #6(LB). */ #define BIT_ALS_OD 0x10 /* bit[3] prox_od R/W bit. * Starts a single on-demand measurement for proximity. * Result is available at the end of conversion for reading in the registers #7(HB) and #8(LB). */ #define BIT_PROX_OD 0x08 /* bit[2] als_en R/W bit. Enables periodic als measurement */ #define BIT_ALS_EN 0x04 /* bit[1] prox_en R/W bit. Enables periodic proximity measurement */ #define BIT_PROX_EN 0x02 /* bit[0] sleftimed_en R/W bit. * Enables state machine and LP oscillator for self timed measurements; * no measurement is performed until the correnponding bit is set */ #define BIT_SELFTIMED_EN 0x01 /* Note: With setting bit[3] and bit[4] at the same write command, * a simultaneously measurement of ambient light and proximity is done. * Beside als_en and/or prox_en first selftimed_en needs to be set. * On-demand measurement modes are disabled if setltimed_en bit is set. * For the selftimed_en mode changes in reading rates (reg #5 and reg #2) * can be made only when b[0] (seltfimed_en bit) = 0. * For the als_od mode changes to the reg #4 can be made only when b[4](als_od bit) = 0; * this is to avoid synchronization problems and undefined states between * the clock domains. In effect this means that it is only reasonable to change * rates while no selftimed conversion is ongoing. */ uint8_t VCNL4020::getCommandReg(void) { uint8_t cmd ; readRegs(REG_COMMAND, &cmd, 1) ; return(cmd) ; } void VCNL4020::setCommandReg(uint8_t cmd) { uint8_t data[2] ; data[0] = REG_COMMAND ; data[1] = cmd ; writeRegs(data, 2) ; } uint8_t VCNL4020::getConfigLock(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd = (cmd >> 7) & 0x01 ; return(cmd) ; } void VCNL4020::setConfigLock(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= BIT_CONFIG_LOCK ; setCommandReg(cmd) ; } void VCNL4020::clearConfigLock(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd ^= BIT_CONFIG_LOCK ; setCommandReg(cmd) ; } uint8_t VCNL4020::alsDataReady(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd = (cmd >> 6) & 0x01 ; return(cmd) ; } uint8_t VCNL4020::proxDataReady(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd = (cmd >> 5) & 0x01 ; return(cmd) ; } void VCNL4020::trigAlsOd(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= BIT_ALS_OD ; setCommandReg(cmd) ; } void VCNL4020::trigProxOd(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= BIT_PROX_OD ; setCommandReg(cmd) ; } void VCNL4020::trigBothOd(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= (BIT_ALS_OD | BIT_PROX_OD) ; setCommandReg(cmd) ; } uint8_t VCNL4020::getAlsPeriodicEnable(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd = (cmd >> 2) & 0x01 ; return(cmd) ; } void VCNL4020::enableAlsPeriodic(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= BIT_ALS_EN ; setCommandReg(cmd) ; } void VCNL4020::disableAlsPeriodic(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd ^= BIT_ALS_EN ; setCommandReg(cmd) ; } uint8_t VCNL4020::getProxPeriodicEnable(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd = (cmd >> 1) & 0x01 ; return(cmd) ; } void VCNL4020::enableProxPeriodic(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= BIT_PROX_EN ; setCommandReg(cmd) ; } void VCNL4020::disableProxPeriodic(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd ^= BIT_PROX_EN ; setCommandReg(cmd) ; } uint8_t VCNL4020::getSelfTimedEnable(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd = cmd & BIT_SELFTIMED_EN ; return(cmd) ; } void VCNL4020::enableSelfTimed(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd |= BIT_SELFTIMED_EN ; setCommandReg(cmd) ; } void VCNL4020::disableSelfTimed(void) { uint8_t cmd ; cmd = getCommandReg() ; cmd ^= BIT_SELFTIMED_EN ; setCommandReg(cmd) ; } /* Product ID Revision (0x81) Register #1 */ /* bit[7:4] Product ID Read Only bits. Value = 2 */ /* bit[3:0] Revision ID Read Only bits. Value = 1 */ uint8_t VCNL4020::getProdID(void) { uint8_t prod_id ; readRegs(REG_PRODUCT_ID_REV, &prod_id, 1) ; prod_id = (prod_id >> 4) & 0x0F ; return(prod_id) ; } /* Proximity Rate (0x82) Register #2 */ /* bit[7:3] (reserved) */ /* bit[2:1] Rate of Proximity Measurement (no. of measurements per second) */ /* R/W bits */ /* 000 - 1.95 measurements/s (DEFAULT) */ /* 001 - 3.90626 */ /* 010 - 7.8125 */ /* 011 - 16.625 */ /* 100 - 31.25 */ /* 101 - 62.5 */ /* 110 - 125 */ /* 111 - 250 */ uint8_t VCNL4020::getProxRate(void) { uint8_t rate ; readRegs(REG_PROXIMITY_RATE, &rate, 1) ; rate &= 0x07 ; return( rate ) ; } void VCNL4020::setProxRate(uint8_t rate) { uint8_t data[2] ; data[0] = REG_PROXIMITY_RATE ; data[1] = (rate & 0x07) ; writeRegs(data, 2) ; } /* IR LED Current (0x83) Register #3 */ /* bit[7:6] Fuse prog ID Read only bits */ /* Information about fuse program revision used for initial setup/calibration of the device. */ /* bit[5:0] IR LED current value R/W bits. */ /* IR LED current = Value(dec.) x 10mA */ /* Valid Rage = 0 to 20d. */ /* 0 = 0mA, 1 = 10mA, 2 = 20mA (DEFAULT) ... 20 = 200mA */ /* LED Current is limited to 200mA for values higher than 20d. */ uint8_t VCNL4020::getFuseProgID(void) { uint8_t data ; readRegs(REG_IR_LED_CURRENT, &data, 1) ; data = ((data >> 5) & 0x03) ; return(data) ; } uint8_t VCNL4020::getIrLedCurrent(void) { uint8_t data ; readRegs(REG_IR_LED_CURRENT, &data, 1) ; data = data & 0x3F ; return(data) ; } void VCNL4020::setIrLedCurrent(uint8_t value) { uint8_t data[2] ; data[0] = REG_IR_LED_CURRENT ; data[1] = value & 0x3F ; writeRegs(data, 2) ; } /* Ambient Light Parameter (0x84) Register #4 */ /* bit[7] Cont.Conv.mode R/W bit. Continuous conversion mode. */ /* Enable = 1; Disable = 0 = DEFAULT */ /* This funcion can be used for performing faster ambient light measurements. */ /* This mode should only be used with ambient light on-demand measurements. */ /* Do not use with self-fimed mode. */ /* Please refer to the application information chapter 3.3 for details about this function */ #define BIT_CONT_CONV_MODE 0x80 /* bit[6:4] als_rate R/W bits. Ambient light measurement rate */ /* 000 - 1 samples/s */ /* 001 - 2 */ /* 010 - 3 */ /* 011 - 4 */ /* 100 - 5 */ /* 101 - 6 */ /* 110 - 8 */ /* 111 - 10 */ /* bit[3] Auto offset compensation R/W bit. Automatic offset compensation */ /* Enable = 1 = DEFAULT; Disable = 0 */ /* In order to compensate a technology, package or temperature realted drift */ /* of the ambient light values there is a built in automatic offset compensation function */ /* With active auto offset compensation the offset value is measured before each */ /* ambient light measurement and subtracted automatically from actual reading. */ /* bit[2:0] Averaging function (number of measurements per fun) */ /* R/W bits. Averating function */ /* Bit values sets the number of single conversions done during one measurement cycle. */ /* Result is the average value of all conversions */ /* Number of conversions = 2^decimal_value */ /* 0 = 1 conv, 1 = 2 conv, 2 = 4 conv, ... 5 = 32 conv (DEFAULT), ... 7 = 128 conv. */ /* Ambient Light Result 0x85, 0x86, Read only bits Register #5, #6 */ uint16_t VCNL4020::getAls(void) { uint16_t result ; uint8_t data[2] ; readRegs(REG_AMBIENT_LIGHT_RESULT, data, 2) ; result = (data[0] << 8) | data[1] ; return( result ) ; } /* Proxymity Measurement Result 0x87, 0x88 Register #7, #8 */ uint16_t VCNL4020::getProx(void) { uint16_t result ; uint8_t data[2] ; readRegs(REG_PROXIMITY_RESULT, data, 2) ; result = (data[0] << 8) | data[1] ; return( result ) ; } /* Interrupt Control 0x89, Register #9 */ /* bit[7:5] Int count exceed R/W bits */ /* These bits contains number of consecutive measurements needed above/below the threshold */ /* 000 - 1 count = DEFAULT */ /* 001 - 2 */ /* 010 - 4 */ /* 011 - 8 */ /* 100 - 16 */ /* 101 - 32 */ /* 110 - 64 */ /* 111 - 128 */ /* bit[4] (reserved) */ /* bit[3] INT_PROX_ready_EN R/W bit */ /* Enables interrupt generation at proximity data ready */ /* bit[2] INT_ALS_ready_EN R/W bit */ /* Enables interrupt generation at ambient data ready */ /* bit[1] INT_THRES_EN R/W bit */ /* Enables interrupt generation when high or low threshol is exceeded */ /* bit[0] INT_THRES_SEL R/W bit */ /* if 0: thresholds are applied to proximity measurements */ /* if 1: thresholds are applied to als measurements */ uint8_t VCNL4020::getIntControl(void) { uint8_t data ; readRegs(REG_INTERRUPT_CONTROL, &data, 1) ; return(data) ; } void VCNL4020::setIntControl(uint8_t ctrl) { uint8_t data[2] ; data[0] = REG_INTERRUPT_CONTROL ; data[1] = ctrl ; writeRegs(data, 2) ; } /* Low Threshold 0x8A, 0x8B Register #10, #11 */ uint16_t VCNL4020::getLowThreshold(void) { uint32_t threshold ; uint8_t data[2] ; readRegs(REG_LOW_THRESHOLD_MSB, data, 2) ; threshold = (data[0] << 8) | data[1] ; return(threshold) ; } void VCNL4020::setLowThreshold(uint16_t threshold) { uint8_t data[5] ; data[0] = REG_LOW_THRESHOLD_MSB ; data[1] = (threshold >> 8) & 0xFF ; data[2] = threshold & 0xFF ; writeRegs(data, 3) ; } /* High Threshold 0x8C, 0x8D Register #12, #13 */ uint16_t VCNL4020::getHighThreshold(void) { uint32_t threshold ; uint8_t data[2] ; readRegs(REG_HIGH_THRESHOLD_MSB, data, 2) ; threshold = (data[0] << 8) | data[1] ; return(threshold) ; } void VCNL4020::setHighThreshold(uint16_t threshold) { uint8_t data[5] ; data[0] = REG_HIGH_THRESHOLD_MSB ; data[1] = (threshold >> 8) & 0xFF ; data[2] = threshold & 0xFF ; writeRegs(data, 3) ; } /* Interrupt Status 0x8E Register #14 */ /* bit[7:4] (reserved) */ /* bit[3] int_prox_ready */ /* bit[2] int_als_ready */ /* bit[1] int_th_low */ /* bit[0] int_th_hi */ uint8_t VCNL4020::getIntStatus(void) { uint8_t status ; readRegs(REG_INTERRUPT_STATUS, &status, 1) ; status &= 0x0F ; return(status) ; } /* Proximity Modulator Timing Adjustment 0x8F Register #15 */ /* bit[7:5] Modulation delay time */ /* bit[4:3] Proximity frequency */ /* bit[2:0] Modulation dead time */ uint8_t VCNL4020::getProxModTiming(void) { uint8_t pmta ; /* Proximity Modulator Timing Adjustment */ readRegs(REG_PROXIMITY_MOD_TIMING, &pmta, 1) ; return(pmta) ; } void VCNL4020::setProxModTiming(uint8_t pmta) { uint8_t data[2] ; data[0] = REG_PROXIMITY_MOD_TIMING ; data[1] = pmta ; writeRegs(data, 2) ; } uint8_t VCNL4020::getRevID(void) { uint8_t rev_id ; readRegs(REG_PRODUCT_ID_REV, &rev_id, 1) ; rev_id = (rev_id & 0x0F) ; return(rev_id) ; } VCNL4020::VCNL4020(PinName sda, PinName scl, int addr) : m_i2c(sda, scl), m_addr(addr<<1) { // activate the peripheral } VCNL4020::~VCNL4020() { } void VCNL4020::readRegs(int addr, uint8_t * data, int len) { char t[1] = {addr}; m_i2c.write(m_addr, t, 1, true); m_i2c.read(m_addr, (char *)data, len); } void VCNL4020::writeRegs(uint8_t * data, int len) { m_i2c.write(m_addr, (char *)data, len); }