Adafruit VCNL4010 library

Hi,

I tried to port the Adafruit VCNL4010 library for the Photon and Core. My code compiles in the online IDE but does not seem to work. Maybe someone can have a look at it :smile:

VCNL4010.h


#include <stdlib.h>

#include "spark_wiring.h"
#include "spark_wiring_i2c.h"

#define VCNL4000_DEBUG 0

// the i2c address
#define VCNL4010_ADRESS 0x13

// commands and constants
#define VCNL4010_COMMAND 0x80
#define VCNL4010_PRODUCTID 0x81
#define VCNL4010_PROXRATE 0x82
#define VCNL4010_IRLED 0x83
#define VCNL4010_AMBIENTPARAMETER 0x84
#define VCNL4010_AMBIENTDATA 0x85
#define VCNL4010_PROXIMITYDATA 0x87
#define VCNL4010_INTCONTROL 0x89
#define VCNL4010_PROXINITYADJUST 0x8A
#define VCNL4010_INTSTAT 0x8E
#define VCNL4010_MODTIMING 0x8F

typedef enum
  {
    VCNL4010_3M125   = 3,
    VCNL4010_1M5625  = 2,
    VCNL4010_781K25  = 1,
    VCNL4010_390K625 = 0,
  } vcnl4010_freq;

#define VCNL4010_MEASUREAMBIENT 0x10
#define VCNL4010_MEASUREPROXIMITY 0x08
#define VCNL4010_AMBIENTREADY 0x40
#define VCNL4010_PROXIMITYREADY 0x20
  
class VCNL4010 {
 public:
  VCNL4010();
  boolean begin(uint8_t a = VCNL4010_ADRESS);  

  uint8_t getLEDcurrent(void);
  void setLEDcurrent(uint8_t c);

  void setFrequency(vcnl4010_freq f);
  uint16_t readProximity(void);
  uint16_t readAmbient(void);

 private:

  void write8(uint8_t address, uint8_t data);
  uint16_t read16(uint8_t address);
  uint8_t read8(uint8_t address);

  uint8_t _i2caddr;
};

VCNL4010.cpp


#include "VCNL4010.h"

/**************************************************************************/
/*! 
    @brief  Instantiates a new VCNL4010 class
*/
/**************************************************************************/
VCNL4010::VCNL4010() {
}

/**************************************************************************/
/*! 
    @brief  Setups the HW
*/
/**************************************************************************/
boolean VCNL4010::begin(uint8_t addr) {
  _i2caddr = addr;
  Wire.begin();

  uint8_t rev = read8(VCNL4010_PRODUCTID);
  //Serial.println(rev, HEX);
  if ((rev & 0xF0) != 0x20) {
    return false;
  }
  
  setLEDcurrent(20);
  setFrequency(VCNL4010_390K625);

  write8(VCNL4010_INTCONTROL, 0x08);
  return true;
}
 

/**************************************************************************/
/*! 
    @brief  Get and set the LED current draw
*/
/**************************************************************************/

void VCNL4010::setLEDcurrent(uint8_t c) {
  if (c > 20) c = 20;
  write8(VCNL4010_IRLED, c);
}

uint8_t VCNL4010::getLEDcurrent(void) {
  return read8(VCNL4010_IRLED);
}

/**************************************************************************/
/*! 
    @brief  Get and set the measurement signal frequency
*/
/**************************************************************************/

void VCNL4010::setFrequency(vcnl4010_freq f) {
  uint8_t r =  read8(VCNL4010_MODTIMING);
  r &= ~(0b00011000);
  r |= f << 3;
  write8(VCNL4010_MODTIMING, r);
}


/**************************************************************************/
/*! 
    @brief  Get proximity measurement
*/
/**************************************************************************/

uint16_t  VCNL4010::readProximity(void) {
  uint8_t i = read8(VCNL4010_INTSTAT);
  i &= ~0x80;
  write8(VCNL4010_INTSTAT, i);

  write8(VCNL4010_COMMAND, VCNL4010_MEASUREPROXIMITY);
  while (1) {
    //Serial.println(read8(VCNL4010_INTSTAT), HEX);
    uint8_t result = read8(VCNL4010_COMMAND);
    //Serial.print("Ready = 0x"); Serial.println(result, HEX);
    if (result & VCNL4010_PROXIMITYREADY) {
      return read16(VCNL4010_PROXIMITYDATA);
    }
    delay(1);
  }
}

uint16_t  VCNL4010::readAmbient(void) {
  uint8_t i = read8(VCNL4010_INTSTAT);
  i &= ~0x40;
  write8(VCNL4010_INTSTAT, i);


  write8(VCNL4010_COMMAND, VCNL4010_MEASUREAMBIENT);
  while (1) {
    //Serial.println(read8(VCNL4010_INTSTAT), HEX);
    uint8_t result = read8(VCNL4010_COMMAND);
    //Serial.print("Ready = 0x"); Serial.println(result, HEX);
    if (result & VCNL4010_AMBIENTREADY) {
      return read16(VCNL4010_AMBIENTDATA);
    }
    delay(1);
  }
}

/**************************************************************************/
/*! 
    @brief  I2C low level interfacing
*/
/**************************************************************************/


// Read 1 byte from the VCNL4000 at 'address'
uint8_t VCNL4010::read8(uint8_t address)
{
  uint8_t data;

  Wire.beginTransmission(_i2caddr);
  Wire.write(address);
  Wire.endTransmission();

  delayMicroseconds(170);  // delay required

  Wire.requestFrom(_i2caddr, (uint8_t)1);
  while(!Wire.available());

  return Wire.read();
}


// Read 2 byte from the VCNL4000 at 'address'
uint16_t VCNL4010::read16(uint8_t address)
{
  uint16_t data;

  Wire.beginTransmission(_i2caddr);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(_i2caddr, (uint8_t)2);
  while(!Wire.available());
  data = Wire.read();
  data <<= 8;
  while(!Wire.available());
  data |= Wire.read();

  return data;
}

// write 1 byte
void VCNL4010::write8(uint8_t address, uint8_t data)
{
  Wire.beginTransmission(_i2caddr);
  Wire.write(address);
  Wire.write(data);  
  Wire.endTransmission();
}

VCNL4010.ino

// This #include statement was automatically added by the Particle IDE.
#include "VCNL4010.h"

VCNL4010 vcnl;

void setup() {
  Serial.begin(9600);
  Serial.println("VCNL4010 test");

  if (! vcnl.begin()){
    Serial.println("Sensor not found :(");
    while (1);
  }
  Serial.println("Found VCNL4010");
}


void loop() {
   Serial.print("Ambient: "); Serial.println(vcnl.readAmbient());
   Serial.print("Proimity: "); Serial.println(vcnl.readProximity());
   delay(100);
}

I tried to do my best but I think I have to learn a lot more!

PS: The original library can be found here

What are the symptoms?
Can you try the library in SYSTEM_MODE(MANUAL)?

If you could put in some Serial.print() statements to see where your code starts misbehaving.

You might also alter your header like this

#ifndef _VCNL410_H_
#define _VCNL410_H_

#include "application.h"
#include "stdlib.h"

... // rest of the code

#endif 

This avoids multiple inclusion and application.h includes all the important spark_ libraries.

1 Like

Hi @ScruffR,

thank you very much! Changing the header was the key to success :smile:
I have published the library already for the web IDE :wink:

I have tested the sensor with my Photon and an Arduino and got equal results.

Github link

2 Likes

The sensor is at https://www.adafruit.com/products/466

And @hl68fx library (VCNL4010) loads and compiles, but I am confused by the connections and can’t figure it out from the .h or .cpp files.

I normally connect:

Sensor to Photon

Vin to VIN (Should I use V30 to 3V3 I read the board works better with the 5V power)
GND to GND
SCL to D1
SDA to D0
INT ???

Not sure about the INT connector . My student says it should be D3.

Quick update:

It is now working. The INT connection does not seem to be relevant.

That INT pin can be connected to any other pin, since it’s completely up to you which pin you want to use for attachInterrupt() to react on any interrupt triggered by the sensor.
But that lib doesn’t give you any clue how to set up the interrupt - and the Adafruit docs seem to do neither.
So you’d need to go through the datasheet to do it yourself


just saw you found that out already :wink:

1 Like

How did you manage to publish in the dashboard? Mine is not working :confused: . What am I doing wrong?
//publish events in particle dashboard
Particle.publish(“Ambient:”, String(Ambient));
Particle.publish(“Proimity:”, String(Proximity));

Are you publishing at a rate higher than 1/s?

// This #include statement was automatically added by the Particle IDE.
#include <VCNL4010.h>

// EXAMPLE - an AT&T APN with no username or password in AUTOMATIC mode
#include "cellular_hal.h"
STARTUP(cellular_credentials_set("internet", "", "", NULL));

//////////////////////code for particle
VCNL4010 vcnl;

void setup() {
  Serial.begin(9600);
  Serial.println("VCNL4010 test");

  if (! vcnl.begin()){
    Serial.println("Sensor not found :(");
    while (1);
  }
  Serial.println("Found VCNL4010");
}


void loop() {
   Serial.print("Ambient: "); Serial.println(vcnl.readAmbient());
   Serial.print("Proimity: "); Serial.println(vcnl.readProximity());
   
   //publish events in particle dashboard
   //Particle.publish("Ambient:", String(Ambient));
   //Particle.publish("Proximity", String(Proximity));
   
   delay(1000);
}

Thanks for your prompt reply.
Below is my serial output :smiley:
Humidity: 23.8 %
Temp (F): 78.8 deg F
Temp ©: 26.0 deg C
Ambient: 332
Proimity: 2244

Ok, first of all, what does that mean? The statement, "not working" is the bane of forum helpers everywhere because it doesn't help to diagnose the problem. What specifically is you problem? Do you get nothing in the dashboard? Some show up, and some don't? Be specific, the more information you give us, the easier it is to help you fix the problem. @ScruffR asked you whether you are publishing more than once per second which is the limit allowed, and you are exceeding that, with 2/second. Either make your delay longer, or combine your two pieces of data into one publish event, and see if that fixes the problem.

1 Like

Hi Ric! Thank you for your prompt reply. I am new to this community and promise to follow your advice regarding the post structure. :joy:

I am flashing the same code posted by @hl68fx, VCNL4010.ino

Could you please take a look at my code ? I have serial output and I have added delay(2000); now. However, there is nothing on the the dashboard. :cry: Is it something related to declaration of particle variable? Million thanks in advance.

//publish events in particle dashboard
Particle.publish(“Ambient:”, String(Ambient));
Particle.publish(“Proximity”, String(Proximity));

I don't see any Particle variable in that code, though you don't need one to publish. What I don't see anywhere are the variables, Ambient or Proximity. Do you have those in your code? When you say, there's nothing in the dashboard, do you mean you don't see the data you're sending, or that you don't see anything at all (no indication that the Publish occurred)? If it's the latter, then maybe there's something wrong with your dashboard. Do you see your devices listed there? Have you ever gotten anything to show up on your dashboard before?

Hi Eric! I have output of the others sensors in the dashboard. I am new in coding. I guess I am missing some important codes. Please take a look at the below code and errors:

// This #include statement was automatically added by the Particle IDE.
#include <VCNL4010.h>
//////////////////////code for particle
VCNL4010 vcnl;

void setup() {
  Serial.begin(9600);
  Serial.println("VCNL4010 test");

  if (! vcnl.begin()){
    Serial.println("Sensor not found :(");
    while (1);
  }
  Serial.println("Found VCNL4010");
}
void loop() {

   Serial.print("Ambient: "); Serial.println(vcnl.readAmbient());
   Serial.print("Proimity: "); Serial.println(vcnl.readProximity());
   
   //publish events in particle dashboard
   Particle.publish("Ambient:", String(Ambient));
   Particle.publish("Proximity", String(Proximity));
   
   delay(1000);
}

Errors:

/src/app3_light.cpp: In function 'void loop()':
/src/app3_light.cpp:29:40: error: 'Ambient' was not declared in this scope
 
                                        ^

/src/app3_light.cpp:30:41: error: 'Proximity' was not declared in this scope
    Serial.print("Ambient: "); Serial.println(vcnl.readAmbient());
                                         ^

make[1]: *** [../build/target/user/platform-10src/app3_light.o] Error 1
make: *** [user] Error 2

You don’t have any variables named Ambient or Proximity (you really should use lowercase names for variables). You need to add them and set them equal to vcml.readAmbient and vcml.readProximity respectively.

VCNL4010 vcnl;
uint16_t ambient;
uint16_t proximity;

void setup() {
  Serial.begin(9600);
  Serial.println("VCNL4010 test");

  if (! vcnl.begin()){
    Serial.println("Sensor not found :(");
    while (1) Particle.process();
  }
  Serial.println("Found VCNL4010");
}
void loop() {
  ambient = vcnl.readAmbient();
  proximity = vcnl.readProximity();
  Serial.print("Ambient: "); Serial.println(ambient);
  Serial.print("Proimity: "); Serial.println(proximity);

  //publish events in particle dashboard
  Particle.publish("Ambient:", String(ambient));
  delay(1000);
  Particle.publish("Proximity", String(proximity));
  delay(1000);
}
1 Like

Hi Ric! It works flawlessly! I have modified my others codes too.Thank you so much. I am glad to be the part of the community. Hope to contribute soon. :grinning: