Subversion Repositories Code-Repo

Rev

Rev 154 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "lux_TSL2561.h"
#include "defines.h"
#include "i2c.h"
#include <delays.h>

static TSL2561_DATA tsl2561_data;
static TSL2561_DATA *tsl2561_data_p = &tsl2561_data;

void LUX_Init(unsigned char address) {
    tsl2561_data_p->address = address;
    tsl2561_data_p->integration = TSL2561_INTEGRATIONTIME_13MS;
    tsl2561_data_p->gain = TSL2561_GAIN_16X;
}

void LUX_Begin(void) {
    unsigned char i, result, length, buffer[10];
    unsigned char toSend = TSL2561_REGISTER_ID;
    DBG_PRINT_LUX("Sending %X to address %X\r\n", toSend, tsl2561_data_p->address);
    I2C_Master_Send(tsl2561_data_p->address, 1, &toSend);
    do {
        result = I2C_Get_Status();
    } while (!result);

    I2C_Master_Recv(tsl2561_data_p->address, 1);
    do {
        result = I2C_Get_Status();
    } while (!result);
    length = I2C_Read_Buffer((char *)buffer);
    DBG_PRINT_LUX("Received %d bytes: ", length);
    for (i = 0; i < length; i++) {
        DBG_PRINT_LUX("%c ", buffer[i]);
    }
    DBG_PRINT_LUX("\r\n");

    // Set default integration time and gain
    LUX_Set_Timing(tsl2561_data_p->integration);
    LUX_Set_Gain(tsl2561_data_p->gain);

    // Start the chip in power-down mode
    LUX_Disable();
}

void LUX_Enable()  {
    LUX_Write_2_Bytes(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON);
}

void LUX_Disable() {
    LUX_Write_2_Bytes(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF);
}

void LUX_Set_Gain(tsl2561Gain_t gain) {
    LUX_Enable();
    tsl2561_data_p->gain = gain;
    LUX_Write_2_Bytes(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING,
            tsl2561_data_p->integration | tsl2561_data_p->gain);
    LUX_Disable();
}

void LUX_Set_Timing(tsl2561IntegrationTime_t integration) {
    LUX_Enable();
    tsl2561_data_p->integration = integration;
    LUX_Write_2_Bytes(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING,
            tsl2561_data_p->integration | tsl2561_data_p->gain);
    LUX_Disable();
}

unsigned long LUX_Calculate_Lux(unsigned int ch0, unsigned int ch1) {
    unsigned long chScale, channel0, channel1, ratio1, ratio, temp, lux;
    unsigned int b, m;

    switch (tsl2561_data_p->integration) {
        case TSL2561_INTEGRATIONTIME_13MS:
            chScale = TSL2561_LUX_CHSCALE_TINT0;
            break;
        case TSL2561_INTEGRATIONTIME_101MS:
            chScale = TSL2561_LUX_CHSCALE_TINT1;
            break;
        default: // No scaling ... integration time = 402ms
            chScale = (1 << TSL2561_LUX_CHSCALE);
            break;
    }

    // Scale for gain (1x or 16x)
    if (!tsl2561_data_p->gain)
        chScale = chScale << 4;

    // scale the channel values
    channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE;
    channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE;

    // find the ratio of the channel values (Channel1/Channel0)
    ratio1 = 0;
    if (channel0 != 0)
        ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE+1)) / channel0;

    // round the ratio value
    ratio = (ratio1 + 1) >> 1;

#ifdef TSL2561_PACKAGE_CS
    if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) {
        b = TSL2561_LUX_B1C; m = TSL2561_LUX_M1C;
    } else if (ratio <= TSL2561_LUX_K2C) {
        b = TSL2561_LUX_B2C; m = TSL2561_LUX_M2C;
    } else if (ratio <= TSL2561_LUX_K3C) {
        b = TSL2561_LUX_B3C; m = TSL2561_LUX_M3C;
    } else if (ratio <= TSL2561_LUX_K4C) {
        b = TSL2561_LUX_B4C; m = TSL2561_LUX_M4C;
    } else if (ratio <= TSL2561_LUX_K5C) {
        b = TSL2561_LUX_B5C; m = TSL2561_LUX_M5C;
    } else if (ratio <= TSL2561_LUX_K6C) {
        b = TSL2561_LUX_B6C; m = TSL2561_LUX_M6C;
    } else if (ratio <= TSL2561_LUX_K7C) {
        b = TSL2561_LUX_B7C; m = TSL2561_LUX_M7C;
    } else if (ratio > TSL2561_LUX_K8C) {
        b = TSL2561_LUX_B8C; m = TSL2561_LUX_M8C;
    }
#else
    if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) {
        b = TSL2561_LUX_B1T; m = TSL2561_LUX_M1T;
    } else if (ratio <= TSL2561_LUX_K2T) {
        b = TSL2561_LUX_B2T; m = TSL2561_LUX_M2T;
    } else if (ratio <= TSL2561_LUX_K3T) {
        b = TSL2561_LUX_B3T; m = TSL2561_LUX_M3T;
    } else if (ratio <= TSL2561_LUX_K4T) {
        b = TSL2561_LUX_B4T; m = TSL2561_LUX_M4T;
    } else if (ratio <= TSL2561_LUX_K5T) {
        b = TSL2561_LUX_B5T; m = TSL2561_LUX_M5T;
    } else if (ratio <= TSL2561_LUX_K6T) {
        b = TSL2561_LUX_B6T; m = TSL2561_LUX_M6T;
    } else if (ratio <= TSL2561_LUX_K7T) {
        b = TSL2561_LUX_B7T; m = TSL2561_LUX_M7T;
    } else if (ratio > TSL2561_LUX_K8T) {
        b = TSL2561_LUX_B8T; m = TSL2561_LUX_M8T;
    }
#endif
    
    temp = ((channel0 * b) - (channel1 * m));

    // do not allow negative lux value
    if (temp < 0)
        temp = 0;

    // round lsb (2^(LUX_SCALE-1))
    temp += (1 << (TSL2561_LUX_LUXSCALE-1));

    // strip off fractional portion
    lux = temp >> TSL2561_LUX_LUXSCALE;

    return lux;
}

unsigned long LUX_Get_Full_Luminosity() {
    unsigned long x;

    // Enable the device by setting the control bit to 0x03
    LUX_Enable();

    // Wait x ms for ADC to complete
    switch (tsl2561_data_p->integration) {
        case TSL2561_INTEGRATIONTIME_13MS:
            Delay10KTCYx(67);
            break;
        case TSL2561_INTEGRATIONTIME_101MS:
            Delay10KTCYx(255);
            Delay10KTCYx(230);
            break;
        default:
            Delay10KTCYx(255);
            Delay10KTCYx(255);
            Delay10KTCYx(255);
            Delay10KTCYx(255);
            Delay10KTCYx(255);
            Delay10KTCYx(255);
            Delay10KTCYx(255);
            Delay10KTCYx(145);
            break;
    }

    x = LUX_Read_2_Bytes(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW);
    x <<= 16;
    x |= LUX_Read_2_Bytes(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW);

    LUX_Disable();

    return x;
}

unsigned int LUX_Get_Luminosity(unsigned char channel) {
    unsigned long x = LUX_Get_Full_Luminosity();

    if (channel == 0) {
        // Reads two byte value from channel 0 (visible + infrared)
        return (x & 0xFFFF);
    } else if (channel == 1) {
        // Reads two byte value from channel 1 (infrared)
        return (x >> 16);
    } else if (channel == 2) {
        // Reads all and subtracts out just the visible!
        return ( (x & 0xFFFF) - (x >> 16));
    }

    // Unknown channel!
    return 0;
}

void LUX_Write_2_Bytes(unsigned char reg, unsigned char value) {
    unsigned char buffer[2], result;
    buffer[0] = reg;
    buffer[1] = value;
    I2C_Master_Send(tsl2561_data_p->address, 2, buffer);
    do {
        result = I2C_Get_Status();
    } while (!result);
}

unsigned int LUX_Read_2_Bytes(unsigned char reg) {
    unsigned char result, length, buffer[2];
    unsigned int ret;

    I2C_Master_Restart(tsl2561_data_p->address, reg, 2);
    do {
        result = I2C_Get_Status();
    } while (!result);
    length = I2C_Read_Buffer((char *)buffer);
    ret = buffer[1] << 8;
    ret |= buffer[0];

    return ret;
}