class to readout the VEML7700 light sensor via i2c
veml7700.cpp
- Committer:
- wbeaumont
- Date:
- 2019-09-10
- Revision:
- 1:d6eb62dc0a1e
- Parent:
- 0:e71d3ecdd257
File content as of revision 1:d6eb62dc0a1e:
#include "veml7700.h" //nclude <stdio.h> /** * veml7700.cpp * implementation of the veml7700 class , see veml7700.h * * version history * version 0.20 : initial value not tested with the sensor * version 0.21 : just change the name from VEML770 VEML7700 corrected address * version 0.30 : start with error reporting * version 0.34 : correction * version 0.46 : corrections for correct working , more methods added * version 0.50 : added readout in lux * This file make part of the PeriperalDevice package see repository * https://github.com/wimbeaumont/PeripheralDevices * * (C) Wim Beaumont Universiteit Antwerpen 2015 2019 * License see * https://github.com/wimbeaumont/PeripheralDevices/blob/master/LICENSE * **/ #define VERSION_VEML7700_SRC "0.52" namespace VEML7700_CONST { // the VEML7700 support only 1 I2C address const int i2caddr = 0x20; // registers const u8 ALS_CONF_0 =0x0 ; const u8 ALS_WH =0x1 ; const u8 ALS_WL =0x2 ; const u8 POW_SET =0x3 ; const u8 ALS =0x4 ; const u8 WHITE =0x5 ; const u8 ALS_INT =0x6 ; // bit masks R0 and values const u16 ALS_SD_SIZE =0x1 ; //shutdown =1 const u16 ALS_SD_LSB =0x0 ; const u16 ALS_INT_EN_SIZE =0x1 ; //enable =1 const u16 ALS_INT_EN_LSB =0x1 ; const u16 ALS_PERS_SIZE =0x2 ; const u16 ALS_PERS_LSB =4 ; const u16 ALS_GAIN_SIZE =0x2 ; const u16 ALS_GAIN_LSB = 11; const u16 ALS_IT_SIZE =0x4; const u16 ALS_IT_LSB =6; const u16 RESERVED_BIT_MSK_ALS_CONF_0 = 0xE40C; // these bits should be 0 so use inverse with AND const int NrGains =4; // make array of struct for the next 2 ? u16 GainSets[NrGains] = { 0x2, 0x3 , 0x0 , 0x1 }; float gains[NrGains] = {.125, .25 , 1, 2 }; const int NrIntT =6; u16 IntTSets[NrIntT]={ 0b1100,0b1000,0b0000,0b0001,0b0010,0b0011 }; int IntTs[NrIntT] = { 25 ,50,100,200,400, 800 }; const float luxref=.0576 ; // lux per bit for gain = 1 and IT =100 ms const int RefIntT= 100; // min resolution gain =2 IT =800 , 0.0036 (als ch) // R1 and R2 are 16 words value // bit mask R3 and values const u16 RESERVED_BIT_MSK_POW_SET = 0xFFF8; // these bits should be 0 so use inverse with AND const u16 PSM_EN_SIZE =0x1 ; const u16 PSM_EN_LSB =0x0 ; const u16 PSM_SIZE =0x6 ; const u16 PSM_LSB =0x1 ; // R4 and R5 are 16 words value // bit mask R6 and values status const u16 INT_TH_HIGH_MSK =0x4000 ; const u16 INT_TH_LOW_MSK =0x8000 ; } using namespace VEML7700_CONST; VEML7700::VEML7700(I2CInterface* i2c , bool init ) :getVersion( VERSION_VEML7700_HDR,VERSION_VEML7700_SRC, __TIME__, __DATE__), i2cdev(i2c) { i2cdev=i2c; gain_nr=0; IntTnr =0; if( init) { set_default_als_config(); set_default_powermode(); // don't care about the threshold settings are interrupt not used by default } } int VEML7700::get_status(void) { return i2cdev-> getLastComError() ; } void VEML7700::setHighWarningLevel( int lvl){ u16 llvl=(u16) lvl & 0xFF; write_cmd(ALS_WH, llvl); } void VEML7700::setLowWarningLevel( int lvl){ u16 llvl=(u16) lvl & 0xFF; write_cmd(ALS_WL, llvl); } bool VEML7700::HighThresoldExeed(void) { return (INT_TH_HIGH_MSK & read_cmd(ALS_INT )) ? true:false; } bool VEML7700::LowThresoldExeed(void){ return (INT_TH_LOW_MSK & read_cmd(ALS_INT )) ? true:false; } void VEML7700::set_bits_reg ( u8 reg , u16 value, u16 lsb ,u16 bsize ) { u16 regvalue =read_cmd(reg ); regvalue = set_bits(regvalue, value, lsb, bsize) ; if (reg == ALS_CONF_0) {regvalue &= ~RESERVED_BIT_MSK_ALS_CONF_0; } if (reg == POW_SET) {regvalue &= ~RESERVED_BIT_MSK_POW_SET; } write_cmd( reg, regvalue ) ; } u16 VEML7700::set_bits(u16 regvalue, u16 value, u16 lsb ,u16 bsize ) { u16 mask = 1; mask = mask << bsize ; mask = mask -1; // so bsize=3 give now mask 0 0111 mask = mask << lsb; // put the bits in the correct place regvalue &= ~mask; // set bits to 0 value = value << lsb; // set the value bits in the correct place. value &= mask ; //only set these bits return value | regvalue; } void VEML7700::shutdown( bool enable) { u16 ie= enable ? 0 :1 ; set_bits_reg( ALS_CONF_0,ie, ALS_SD_LSB,ALS_SD_SIZE ); } void VEML7700::set_int_enable( bool int_enable) { u16 ie= int_enable ? 0 :1 ; set_bits_reg( ALS_CONF_0,ie, ALS_INT_EN_LSB,ALS_INT_EN_SIZE ); } void VEML7700::set_gain_bits( u16 gbits ) { set_bits_reg ( ALS_CONF_0 , gbits , ALS_GAIN_LSB,ALS_GAIN_SIZE ); } void VEML7700::set_IntT_bits( u16 InTgbits ) { set_bits_reg ( ALS_CONF_0 , InTgbits , ALS_IT_LSB,ALS_IT_SIZE ); } void VEML7700::set_default_als_config ( bool shutdown , bool int_enable ,u16 pres, u16 integrationtime, u16 gain ) { u16 setvalue = shutdown? 1:0; //set shutdown u16 uinterrupt= int_enable ?1:0; setvalue=set_bits( setvalue , uinterrupt , ALS_INT_EN_LSB,ALS_INT_EN_SIZE); setvalue=set_bits( setvalue , pres , ALS_PERS_LSB,ALS_PERS_SIZE); setvalue=set_bits( setvalue , integrationtime , ALS_IT_LSB,ALS_IT_SIZE); setvalue=set_bits( setvalue , gain , ALS_GAIN_LSB,ALS_GAIN_SIZE); setvalue &= ~RESERVED_BIT_MSK_ALS_CONF_0; write_cmd( ALS_CONF_0, setvalue ) ;// it will et all the bits so no need to read first } void VEML7700::set_power_saving_enable( bool ps_enable) { u16 pse=ps_enable ? 0 :1 ; set_bits_reg( POW_SET ,pse, PSM_EN_LSB, PSM_EN_SIZE ); } void VEML7700::set_power_saving_mode( u16 psmode) { set_bits_reg( POW_SET ,psmode, PSM_LSB, PSM_SIZE ); } void VEML7700::set_default_powermode ( bool ps_enable , u16 psmode) { u16 setvalue = ps_enable ? 0:1; setvalue = set_bits( setvalue, psmode,PSM_LSB, PSM_SIZE ); setvalue &= ~ ~RESERVED_BIT_MSK_POW_SET; write_cmd( POW_SET , setvalue ) ; } // error handling via DevErrorReporter u16 VEML7700::read_cmd ( u8 reg) { /* seems this doesn work returns always zero printf("call read_cmd "); char readvalue[2]; // max 2 values read // first set the reg pointer . not sure if this works readvalue[0] = (char) reg; int err= i2cdev->write (i2caddr,readvalue, 1,false) ; // Write reg to an I2C slave. 3 words with stop if (err) { printf("VELM7700 %d i2c err %d in %d \n\r",err, __LINE__); } //now read err = i2cdev->read( i2caddr, readvalue , 2, false) ;// read from the i2c dev with stop if (err) {printf("VELM7700 %d i2c err %d in %d \n\r",err, __LINE__); } printf(" %x %x \n\r", (int) readvalue[0], (int) readvalue[1]); u16 rv= readvalue[1]; rv=rv<<8; rv|= readvalue[0]; return rv; */ char readvalue[2]; i2cdev-> read_reg( i2caddr , readvalue , 2, (int) reg, 1); u16 rv= readvalue[1]; rv=rv<<8; rv|= readvalue[0]; return rv; } // error handling via DevErrorReporter void VEML7700::write_cmd( u8 reg , u16 value ){ char writevalue[3]; // max 3 values to write writevalue[0] = (char) reg; writevalue[1] = (char)( value & 0xFF); //Write LSByte first see data I2C interface value =value >>8; writevalue[2] = (char)( value & 0xFF); //MSByte i2cdev->write(i2caddr,writevalue, 3,false) ; // Write to an I2C slave. 3 words with stop } u16 VEML7700::get_IntT_in_set_bit( int time_ms) { for ( IntTnr= 0;IntTnr <NrIntT ;IntTnr++){ if( time_ms < IntTs[IntTnr] ) break; } if( IntTnr == NrIntT ) { IntTnr--;} return IntTSets[IntTnr]; } void VEML7700::set_integrationtime( int time_ms ) { u16 gb=get_IntT_in_set_bit( time_ms); set_IntT_bits( gb); } void VEML7700::set_gain( float gain ) { u16 gb= get_gain_in_set_bit ( gain ); set_gain_bits( gb); } u16 VEML7700::get_gain_in_set_bit (float gainsel ) { for ( gain_nr = 0; gain_nr < NrGains; gain_nr++ ){ if ( gainsel <= gains[gain_nr] ) { break;} } if( gain_nr == NrGains) { gain_nr--;}; return GainSets[gain_nr]; } u16 VEML7700::get_als_bits(void){ return read_cmd(ALS ); } u16 VEML7700::get_white_ch_bits(void){ return read_cmd(WHITE ); } float VEML7700::get_lux(bool ALSreg , bool verify_reg ) { u16 reg= ALSreg ? ALS: WHITE; u16 res = read_cmd(reg); if ( verify_reg ) { reg= ALS_CONF_0; reg =read_cmd(reg); (void) decodeIntTbits( reg,IntTnr ); // just set this correct (void) decodeIntTbits( reg,gain_nr ); // just set gain_nr correct } return (float)res *luxref / gains[gain_nr]*RefIntT /(float) IntTs[IntTnr] ; } // below are not necessay but useful fpr debugging u16 VEML7700::get_bits(u16 regvalue, u16 lsb ,u16 bsize ) { u16 mask = 1; mask = mask << bsize ; mask = mask -1; // so bsize=3 give now mask 0 0111 mask = mask << lsb; // put the bits in the correct place regvalue &= mask ; //truncate if to big mask = 1; mask = mask << bsize ; mask = mask -1; // so bsize=3 give now mask 0 0111 regvalue = regvalue >> lsb; // set the value bits in the correct place. return regvalue & mask; } float VEML7700::decodeGainBits( u16 gb) { int dummy; return decodeGainBits( gb, dummy ) ; } float VEML7700::decodeGainBits( u16 gb, int& g_nr) { // this function doesn't set the gain_nr as it can be used for checking only for ( g_nr = 0; g_nr < NrGains; g_nr++ ){ if ( gb == GainSets[g_nr] ) { break;} } if( g_nr >= NrGains) { g_nr = NrGains-1;}; return gains[g_nr]; } int VEML7700::decodeIntTbits( u16 ib) { int dummy; return decodeIntTbits( ib,dummy ); } int VEML7700::decodeIntTbits( u16 ib, int &In_nr ) { // this function doesn't set the IntTnr as it can be used for checking only for ( In_nr= 0;In_nr < NrIntT ;In_nr++){ if( ib == IntTSets[In_nr] ){ break;} } if ( In_nr >= NrIntT) { In_nr= NrIntT-1; }; return IntTs[In_nr]; } u16 VEML7700::decode_Reg0( bool& sd ,bool& ie, u16& pers_protect,int& IntT, float& gain ) { u16 reg= read_cmd(ALS_CONF_0); u16 res= get_bits(reg, ALS_SD_LSB , ALS_SD_SIZE ) ; sd = res ? false : true; res= get_bits(reg,ALS_INT_EN_LSB , ALS_INT_EN_SIZE ) ; ie = res ? false : true; pers_protect= get_bits(reg,ALS_PERS_LSB , ALS_PERS_SIZE ) ; res= get_bits(reg,ALS_IT_LSB , ALS_IT_SIZE ) ; IntT=decodeIntTbits(res); res= get_bits(reg,ALS_GAIN_LSB , ALS_GAIN_SIZE ) ; gain=decodeGainBits(res); return reg; }