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);
}