A Vishay library for devices VEML6040 R+G+B+W and VEML6075 UVA+UVB optical sensors. Data is stored in a dedicated data structure.

Dependents:   vmel60xx_hello_world

This device library is for use with the Vishay VEML6040 and VEML6075 optical sensors. Ambient light conditions are gathered and stored in a user accessible data structure veml60xx_struct. The library has enough intelligence to determine which device is connected and performs the appropriate functions.

The VEML6040 detects Red, Green, Blue and White light data, which is easily converted to relative Lux intensities.

The VEML6075 detects UVA and UVB light which is converted to a UV Index value.

Since both devices use the same I2C address, they cannot be on the same I2C bus at the same time.

Tested on a K64F

veml60xx.h

Committer:
loopsva
Date:
2016-04-29
Revision:
4:0ce65ee5697f
Parent:
3:dda770fa7228

File content as of revision 4:0ce65ee5697f:

#ifndef VEML60XX_H
#define VEML60XX_H

/**
* Library for Vishay VEML6040 R+G+B+W and VEML6075 UVA+UVB optical sensors that operate on the I2C bus.  There are 
* routines for detecting which VEML device is connected to the I2C bus and sets the appropriate resigter values
* in the data structure "veml60xx_struct". 
*
* The code has all of the hooks for gathering raw data from the VEML60xx chip and performs the necessary compensation 
* in order to get the corrected output readings.  There is also an optional automatic scaling routine that 
* modifies the integration time (IT bits in the CONF register), should the raw register reading saturate (65535) or
* are too small (< 255).  Adjustments are made + or - one IT count, each time the routine is called.  If the light
* striking the sensor changes dramatically, you may have to run the automatic scaling routine a few times.  After 
* each change in integration time (changing of IT bits), you must wait a maximum of 2 * 1280mSec before taking a new 
* reading in order to get accurate results.
*
* NOTE: Both the VEML6040 and the VEML6075 have the same I2C address.  You cannot have both devices on the same I2C 
*       bus at the same time!! Vishay does have an application note for using multiple devices in the same I2C bus.
*       However, it does require additional hardware to do so. 
*
* NOTE: Although no device ID is noted in the VEML6040 datasheet, it apprears to have an ID of 0x0123.  This code
*       does look at the 0x0123 ID signature to determine that a VEML6040 has been detected and sets 
*       the "is6040" flag in the "veml60xx_struct" data structure.
*
* NOTE: It is not yet known when using startAccess(), whether or not that TRIG bit clear immediately or after the
*       integration time has finished.  As a result, you should not depend on TRIG bit for polling.
*
**/

#include "mbed.h"

// I2C address
#define VEML60_WADDR                        0x20    //i2c address write mode
#define VEML60_RADDR                        0x21    //i2c address read mode


// VEML6040 and VEML6075 common register set
#define VEML60xx_CONF_REG                   0x00    //rw Config Register 

// VEML6075-only register set
#define VEML6075_UVA_DATA_REG               0x07    //ro 16 bit UVA data Register
#define VEML6075_DUMMY_REG                  0x08    //ro 16 bit dummy Register
#define VEML6075_UVB_DATA_REG               0x09    //ro 16 bit UVB data Register 
#define VEML6075_UV_COMP1_REG               0x0A    //ro 16 bit UV compensation Register 1
#define VEML6075_UV_COMP2_REG               0x0B    //ro 16 bit UV compensation Register 2
#define VEML6075_CHIP_ID_REG                0x0C    //ro 16 bit Chip ID Register 

// VEML6040-only register set
#define VEML6040_R_DATA_REG                 0x08    //ro 16 bit RED data
#define VEML6040_G_DATA_REG                 0x09    //ro 16 bit GREEN data
#define VEML6040_B_DATA_REG                 0x0A    //ro 16 bit BLUE data
#define VEML6040_W_DATA_REG                 0x0B    //ro 16 bit WHITE data 

// VEML6040 and VEML6075 common config register bits
#define VEML60xx_CONF_BITS_IT               0x70    //VEML6075 -> 0x00 = 50mS, 0x10 = 100mS, 0x20 = 200mS, 0x30 = 400mS, 0x40 = 800mS, 0x50-0x70 = reserved
                                                    //VEML6040 -> 0x00 = 40mS, 0x10 =  80mS, 0x20 = 160mS, 0x30 = 320mS, 0x40 = 640mS, 0x50 = 1280mS, 0x60-0x70 = reserved
#define VEML60xx_CONF_BITS_IT_50m40m        0x00
#define VEML60xx_CONF_BITS_IT_100m80m       0x10
#define VEML60xx_CONF_BITS_IT_200m160m      0x20
#define VEML60xx_CONF_BITS_IT_400m320m      0x30
#define VEML60xx_CONF_BITS_IT_800m640m      0x40
                                                    
#define VEML60xx_CONF_BITS_TRIG             0x04    //0x00 = idle, 0x04 = trigger (measurement), auto returns to 0x00 note: AF == 1
#define VEML60xx_CONF_BITS_AF               0x02    //0x00 = auto, 0x02 = force (mode)
#define VEML60xx_CONF_BITS_SD               0x01    //0x00 = run,  0x01 = shut down

// VEML6075-only config register bits
#define VEML6075_CONF_BITS_HD               0x08    //0x00 = normal, 0x08 = high (dynamic setting)

// VEML6040-only config register bits
#define VEML6040_CONF_BITS_IT_1280m         0x50

// VEML6075-only ID contents
#define VEML6075_DEVICE_ID                  0x0026  //expected device ID

// VEML6040-only ID contents
#define VEML6040_DEVICE_ID                  0x0023  //expected device ID

// VEML6075-only conversion coefficients
#define VEML6075_UVA_RESP                   0.0011
#define VEML6075_UVB_RESP                   0.00125

#define VEML6075_UVA_COEF_A                 3.33
#define VEML6075_UVA_COEF_B                 2.50
#define VEML6075_UVB_COEF_C                 3.67
#define VEML6075_UVB_COEF_D                 2.75

// VEML6040-only conversion coefficients
#define VEML6040_LUX_STEP                   0.007865

    /** 
     * Create VEML60 controller class
     *
     * @param VEML class
     *
     */
class veml60xx {

public:

    /** 
     * Public data structure for VEML60xx data values.
     * 
    **/
    typedef struct {
        uint16_t id;        /*!< VEML60xx Device ID*/
        uint16_t conf_reg;  /*!< VEML60xx config register mirror */ 
        int      trig_dly;  /*!< VEML60xx FORCE mode min trigger delay (mS) before resding data registers */ 
              
        bool     is6075;    /*!< connected device is a VEML6075 */ 
        bool     is6040;    /*!< connected device is a VEML6040 */ 
        
        uint16_t uva_d;     /*!< VEML6075 UVA data */   
        uint16_t uvb_d;     /*!< VEML6075 UVB data */
        uint16_t dummy_d;   /*!< VEML6075 Dummy data */ 
        uint16_t uv_c1;     /*!< VEML6075 UV comp1 data */
        uint16_t uv_c2;     /*!< VEML6075 UV comp2 data */
        double   uva_step;  /*!< VEML6075 UVA value per step */
        double   uvb_step;  /*!< VEML6075 UVB value per step */
        double   uva_comp;  /*!< VEML6075 UVA compensated data */
        double   uvb_comp;  /*!< VEML6075 UVB compensated data */
        double   uv_index;  /*!< VEML6075 UV Index */
                
        double   lux_step;  /*!< VEML6040 Lux value per step */
        uint16_t r_d;       /*!< VEML6040 RED data */ 
        uint16_t g_d;       /*!< VEML6040 GREEN data */ 
        uint16_t b_d;       /*!< VEML6040 BLUE data */ 
        uint16_t w_d;       /*!< VEML6040 WHITE data */
        double   r_lux;     /*!< VEML6040 RED Lux value */
        double   g_lux;     /*!< VEML6040 GREEN Lux value */
        double   b_lux;     /*!< VEML6040 BLUE Lux value */
        double   w_lux;     /*!< VEML6040 WHITE Lux value */

    } veml60xx_struct;
         
    /** 
     * Create a VME60xx object using the specified I2C object
     *
     * @param sda - mbed I2C interface pin
     *
     * @param scl - mbed I2C interface pin
     *
     * @param set_I2C_frequency
     */
    veml60xx(PinName sda, PinName scl,  int i2cFrequency);

    /**
     * Destructor
     *
     * @param --none--
     */
    ~veml60xx();

    /** 
     * Get VEML60xx ID Register
     *
     * Note: the VEML6040 seems to have an ID register. However, it's not published by Vishay
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @return ID Register value
    */ 
    uint16_t getID(veml60xx_struct& Pntr);
    
    /** 
     * Get VEMLxx Config Register
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @return Config Register value
    */ 
    uint16_t getConfig(veml60xx_struct& Pntr);

    /** 
     * Get VEML60xx Raw Data
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @return raw data put into struct VEML60xx_struct
    */ 
    uint16_t getRawData(veml60xx_struct& Pntr);

    /** 
     * Convert the VEML6075 Raw Data
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @return converted data put into struct VEML60xx_struct
    */ 
    void convertRawData(veml60xx_struct& Pntr);

    /** 
     * Initialize the VEML60xx
     *
     * Sets up the command register to proper operating mode
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @param val any value to be or'd into the config register
     *
     * Typical val variable settings:
     * - veml.setConfig(vemlSTR, 0);
     * - veml.setConfig(vemlSTR, VEML60xx_CONF_BITS_IT_100m80m);
     * - veml.setConfig(vemlSTR, VEML60xx_CONF_BITS_IT_400m320m);
     * - veml.setConfig(vemlSTR, VEML60xx_CONF_BITS_IT_800m640m | VEML6075_CONF_BITS_HD | VEML60xx_CONF_BITS_AF);
     *
     * @return nothing
    */  
    void setConfig(veml60xx_struct& Pntr, uint16_t val);

    /** 
     * Trigger a VEML60xx conversion cycle
     *
     * Must be in manual trigger mode (AF == 1)
     *
     * Example: veml.setConfig(vemlSTR, VEML60xx_CONF_BITS_AF);
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @return 0 TRIG properly set
     * @return 1 TRIG has been previously set
     * @return 2 AF bit not set (in AUTO mode)
    */     
    uint16_t startAccess(veml60xx_struct& Pntr);

    /** 
     * Automatically adjust Lux scaling level
     *
     * Change CONF_BITS_IT by +-1 if count bits saturated or too low
     * 
     * @param pointer to struct veml60xx_struct
     *
     * @return true = IT scale value has changed
     * @return false = IT scale value not changed, could be at its limit
    */  
    bool autoAdjustLux(veml60xx_struct& Pntr);
        
private:
    char vemlBuffer[4];
  
protected:
    I2C*    _i2c_;

}; 
#endif