A library for the Avago ADJD-S311-CR999 Color Light Sensor

Dependents:   ADJD-S311_HelloWorld

ADJDs311.cpp

Committer:
CheeseW
Date:
2014-03-24
Revision:
2:5d0bc4df0701
Parent:
0:d5bb69f92ea3

File content as of revision 2:5d0bc4df0701:

#include "ADJDs311.h"
#include "mbed.h"
#include <algorithm>

ADJDs311::ADJDs311(PinName sda, PinName scl, PinName led):
        _i2c(sda, scl), _led(led) {
    // hard coded value for number of capacitors
    colorCap.red = 12;
    colorCap.green = 9;
    colorCap.blue = 2;
    colorCap.clear = 9;
    
    // hard coded value for number of integration time slot
    colorInt.red = 16;
    colorInt.green = 16;
    colorInt.blue = 16;
    colorInt.clear = 16; 
    
    colorOffset.red = readRegister(OFFSET_RED);
    colorOffset.green = readRegister(OFFSET_GREEN);
    colorOffset.blue = readRegister(OFFSET_BLUE);
    colorOffset.clear = readRegister(OFFSET_CLEAR);
    
    // write number of capacitors to registers
    writeRegister(colorCap.red & 0xF, CAP_RED);    
    writeRegister(colorCap.green & 0xF, CAP_GREEN); 
    writeRegister(colorCap.blue & 0xF, CAP_BLUE); 
    writeRegister(colorCap.clear & 0xF, CAP_CLEAR);
    
    // write number of integration time slot to registers
    writeInt(colorInt.red & 0xFFF, INT_RED_LO);
    writeInt(colorInt.green & 0xFFF, INT_GREEN_LO); 
    writeInt(colorInt.blue & 0xFFF, INT_BLUE_LO); 
    writeInt(colorInt.clear & 0xFFF, INT_CLEAR_LO);     
}

// Read data regeisters and return a RGBC var
RGBC ADJDs311::read(){
    RGBC color = RGBC();
    
    performMeasurement();
    
    color.red = readInt(DATA_RED_LO);
    color.green = readInt(DATA_GREEN_LO);
    color.blue = readInt(DATA_BLUE_LO);
    color.clear = readInt(DATA_CLEAR_LO);
    
    return color;        
}

// get number of capacitor
RGBC ADJDs311::getColorCap()
{
    return colorCap;   
}

// get number of intetgration time slot
RGBC ADJDs311::getColorInt()
{
    return colorInt;   
}

// set number of capacitor
void ADJDs311::setColorCap(int red, int green, int blue, int clear) {
    colorCap.red = red;
    colorCap.green = green;
    colorCap.blue = blue;
    colorCap.clear = clear;
    
    // write number of capacitors to registers
    writeRegister(colorCap.red & 0xF, CAP_RED);    
    writeRegister(colorCap.green & 0xF, CAP_GREEN); 
    writeRegister(colorCap.blue & 0xF, CAP_BLUE); 
    writeRegister(colorCap.clear & 0xF, CAP_CLEAR);
}

// set number of integration time slot
void ADJDs311::setColorInt(int red, int green, int blue, int clear) { 
    colorInt.red = red;
    colorInt.green = green;
    colorInt.blue = blue;
    colorInt.clear = clear; 
    
    // write number of integration time slot to registers
    writeInt(colorInt.red & 0xFFF, INT_RED_LO);
    writeInt(colorInt.green & 0xFFF, INT_GREEN_LO); 
    writeInt(colorInt.blue & 0xFFF, INT_BLUE_LO); 
    writeInt(colorInt.clear & 0xFFF, INT_CLEAR_LO); 
}

// Perform measurement and save the result to registers
void ADJDs311::performMeasurement(){ 
 writeRegister(0x01, 0x00); // start sensing
 while(readRegister(0x00) != 0)
  ; // waiting for a result
}

// Write a byte of data to a specific ADJD-S311 address
void ADJDs311::writeRegister(char data, char regAddr){
    char temp[2];
    temp[0] = regAddr;  // register addresss
    temp[1] = data;
    
    _i2c.write(WRITE_ADDRESS, temp, 2, false);
}

// Read a byte of data from ADJD-S311 address
char ADJDs311::readRegister(char regAddr){
    char data;
    
    _i2c.write(WRITE_ADDRESS, &regAddr, 1, true);
    _i2c.read(READ_ADDRESS, &data, 1, false);
    return data;
}

// Read two bytes of data from ADJD-S311 address and addres+1
int ADJDs311::readInt(char loRegAddr)
{
    return (unsigned char)readRegister(loRegAddr) + (((unsigned char)readRegister(loRegAddr+1))<<8);
}

// Write two bytes of data to ADJD-S311 address and addres+1
void ADJDs311::writeInt(int data, char loRegAddr)
{
    char lobyte = data;
    char hibyte = data >> 8;
    
    writeRegister(lobyte, loRegAddr);
    writeRegister(hibyte, loRegAddr+1);   
}

/* calibrateClear() - This function calibrates the clear integration registers
of the ADJD-S311.
*/
void ADJDs311::calibrateClearInt(){
    bool gainFound = false;
    int upperBox=4096;
    int lowerBox = 0;
    int half;
    
    while (!gainFound){
        half = ((upperBox-lowerBox)/2)+lowerBox;
        //no further halfing possbile
        
        if (half==lowerBox){
            gainFound=true;
        }else{
            colorInt.clear = half;
            writeInt(colorInt.clear & 0xFFF, INT_CLEAR_LO);
            performMeasurement();
            int halfValue = readInt(DATA_CLEAR_LO);
        
            if (halfValue>800){
                upperBox=half;
            }else if (halfValue<800){
                lowerBox=half;
            }else{
                gainFound=true;
            } 
        }
    }
}

/* calibrateColor() - This function clalibrates the RG and B 
integration registers.
*/
void ADJDs311::calibrateColorInt(){
 bool gainFound = false;
 int upperBox=4096;
 int lowerBox = 0;
 int half;
 int halfValue;
 
 while (!gainFound)
 {
  half = ((upperBox-lowerBox)/2)+lowerBox;
  //no further halfing possbile
  if (half==lowerBox)
  {
   gainFound=true;
  }
  else {
    colorInt.red = half;
    colorInt.green = half;
    colorInt.blue = half;
    
    // write number of integration time slot to registers
    writeInt(colorInt.red & 0xFFF, INT_RED_LO);
    writeInt(colorInt.green & 0xFFF, INT_GREEN_LO); 
    writeInt(colorInt.blue & 0xFFF, INT_BLUE_LO); 

   performMeasurement();
   halfValue = 0;

   halfValue=std::max(halfValue, readInt(DATA_RED_LO));
   halfValue=std::max(halfValue, readInt(DATA_GREEN_LO));
   halfValue=std::max(halfValue, readInt(DATA_BLUE_LO));

   if (halfValue>800) {
    upperBox=half;
   }
   else if (halfValue<800) {
    lowerBox=half;
   }
   else {
    gainFound=true;
   }
  }
 }
}


/* calibrateCapacitors() - This function calibrates each of the RGB and C
capacitor registers.
*/
void ADJDs311::calibrateCapacitors(){

 bool calibrated = false;

 //need to store detect better calibration
 int diff;
 int oldDiff = 1024;

 while (!calibrated){
  // sensor gain setting (Avago app note 5330)
  // CAPs are 4bit (higher value will result in lower output)
    writeRegister(colorCap.red & 0xF, CAP_RED);    
    writeRegister(colorCap.green & 0xF, CAP_GREEN); 
    writeRegister(colorCap.blue & 0xF, CAP_BLUE); 

  int maxRead = 0;
  int minRead = 1024;
  int red  = 0;
  int green = 0;
  int blue = 0;
  
  for (int i=0; i<4 ;i ++)
  {
   performMeasurement();
   red  += readInt(DATA_RED_LO);
   green += readInt(DATA_GREEN_LO);
   blue += readInt(DATA_BLUE_LO);
  }
  red  /= 4;
  green /= 4;
  blue /= 4;

  maxRead = std::max(maxRead, red);
  maxRead = std::max(maxRead, green);
  maxRead = std::max(maxRead, blue);

  minRead = std::min(minRead, red);
  minRead = std::min(minRead, green);
  minRead = std::min(minRead, blue);

  diff = maxRead - minRead;

  if (oldDiff != diff)
  {
   if ((maxRead==red) && (colorCap.red<15))
    colorCap.red++;
   else if ((maxRead == green) && (colorCap.green<15))
    colorCap.green++;
   else if ((maxRead == blue) && (colorCap.blue<15))
    colorCap.blue++;
  }
  else
   calibrated = true;
   
  oldDiff=diff;

 }
 
}

void ADJDs311::calibrate(){
    setColorCap(0, 0, 0, 8);
    calibrateColorInt(); // This calibrates R, G, and B int registers
    calibrateClearInt(); // This calibrates the C int registers
    calibrateCapacitors(); // This calibrates the RGB, and C cap registers
    calibrateColorInt();
}


void ADJDs311::ledMode(bool ledOn)
{
    _led = ledOn;
}

void ADJDs311::offsetMode(bool useOffset)
{
    if (useOffset)
    {
        writeRegister(0x01, CONFIG);   
    } else
    {
        writeRegister(0x00, CONFIG); 
    }
}

RGBC ADJDs311::getOffset()
{
    return colorOffset;   
}

RGBC ADJDs311::setOffset(bool useOffset)
{
    _led = 0;
    
    writeRegister(0x02, CTRL);
    while(readRegister(CTRL));
    colorOffset.red = readRegister(OFFSET_RED);
    colorOffset.green = readRegister(OFFSET_GREEN);
    colorOffset.blue = readRegister(OFFSET_BLUE);
    colorOffset.clear = readRegister(OFFSET_CLEAR);
    
    offsetMode(useOffset);
    
    return colorOffset;
}