1 /* 2 * Author: Nandkishor Sonar <Nandkishor.Sonar (at) intel.com> 3 * Copyright (c) 2014 Intel Corporation. 4 * 5 * LIGHT-TO-DIGITAL CONVERTER [TAOS-TSL2561] 6 * Inspiration and lux calculation formulas from data sheet 7 * URL: http://www.adafruit.com/datasheets/TSL2561.pdf 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining 10 * a copy of this software and associated documentation files (the 11 * "Software"), to deal in the Software without restriction, including 12 * without limitation the rights to use, copy, modify, merge, publish, 13 * distribute, sublicense, and/or sell copies of the Software, and to 14 * permit persons to whom the Software is furnished to do so, subject to 15 * the following conditions: 16 * 17 * The above copyright notice and this permission notice shall be 18 * included in all copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 */ 28 29 30 #include <string> 31 #include <stdexcept> 32 #include <unistd.h> 33 #include "tsl2561.h" 34 35 using namespace upm; 36 37 38 TSL2561::TSL2561(int bus, uint8_t devAddr, uint8_t gain, uint8_t integrationTime) 39 : m_i2ControlCtx(bus) 40 { 41 m_controlAddr = devAddr; 42 m_bus = bus; 43 m_gain = gain ; 44 m_integrationTime = integrationTime; 45 46 m_name = "TSL2561- Digital Light Sensor"; 47 48 mraa::Result error = m_i2ControlCtx.address(m_controlAddr); 49 if (error != mraa::SUCCESS) { 50 throw std::invalid_argument(std::string(__FUNCTION__) + 51 ": mraa_i2c_address() failed"); 52 return; 53 } 54 55 // POWER UP. 56 error = m_i2ControlCtx.writeReg(REGISTER_Control, CONTROL_POWERON); 57 if (error != mraa::SUCCESS) { 58 throw std::runtime_error(std::string(__FUNCTION__) + 59 ": Unable to power up TSL2561"); 60 return; 61 } 62 // Power on Settling time 63 usleep(1000); 64 65 // Gain & Integration time . 66 error = m_i2ControlCtx.writeReg(REGISTER_Timing, m_gain | m_integrationTime); 67 if (error != mraa::SUCCESS) { 68 throw std::runtime_error(std::string(__FUNCTION__) + 69 ": Unable to set gain/time"); 70 return; 71 } 72 73 // Set interrupt threshold to default. 74 error = m_i2ControlCtx.writeReg(REGISTER_Interrupt, 0x00); 75 if (error != mraa::SUCCESS) { 76 throw std::runtime_error(std::string(__FUNCTION__) + 77 ": Unable to set interrupt threshold"); 78 return; 79 } 80 } 81 82 TSL2561::~TSL2561() 83 { 84 // POWER DOWN 85 m_i2ControlCtx.writeReg(REGISTER_Control, CONTROL_POWEROFF); 86 } 87 88 int 89 TSL2561::getLux() 90 { 91 mraa::Result error = mraa::SUCCESS; 92 int lux; 93 uint16_t rawLuxCh0; 94 uint16_t rawLuxCh1; 95 uint8_t ch0_low, ch0_high, ch1_low, ch1_high; 96 97 error = i2cReadReg(REGISTER_Channal0L, ch0_low); 98 if (error != mraa::SUCCESS) { 99 fprintf(stderr, "Error: Unable to read channel0L in getRawLux()\n"); 100 return error; 101 } 102 103 error = i2cReadReg(REGISTER_Channal0H, ch0_high); 104 if (error != mraa::SUCCESS) { 105 fprintf(stderr, "Error: Unable to read channel0H in getRawLux()\n"); 106 return error; 107 } 108 109 rawLuxCh0 = ch0_high*256+ch0_low; 110 111 error= i2cReadReg(REGISTER_Channal1L, ch1_low); 112 if (error != mraa::SUCCESS) { 113 fprintf(stderr, "Error: Unable to read channel1L in getRawLux()\n"); 114 return error; 115 } 116 117 error = i2cReadReg(REGISTER_Channal1H, ch1_high); 118 if (error != mraa::SUCCESS) { 119 fprintf(stderr, "Error: Unable to read channel1H in getRawLux()\n"); 120 return error; 121 } 122 123 rawLuxCh1 = ch1_high*256+ch1_low; 124 125 uint64_t scale = 0; 126 127 switch (m_integrationTime) 128 { 129 case 0: // 13.7 msec 130 scale = LUX_CHSCALE_TINT0; 131 break; 132 case 1: // 101 msec 133 scale = LUX_CHSCALE_TINT1; 134 break; 135 default: // assume no scaling 136 scale = (1 << LUX_CHSCALE); 137 break; 138 } 139 140 // scale if gain is NOT 16X 141 if (!m_gain) scale = scale << 4; 142 143 uint64_t channel1 = 0; 144 uint64_t channel0 = 0; 145 // scale the channel values 146 channel0 = (rawLuxCh0 * scale) >> LUX_CHSCALE; 147 channel1 = (rawLuxCh1 * scale) >> LUX_CHSCALE; 148 149 // find the ratio of the channel values (Channel1/Channel0) 150 // protect against divide by zero 151 unsigned long ratio1 = 0; 152 if (channel0 != 0) ratio1 = (channel1 << (LUX_RATIOSCALE+1)) / channel0; 153 154 // round the ratio value 155 unsigned long ratio = (ratio1 + 1) >> 1; 156 157 unsigned int b, m; 158 159 // CS package 160 // Check if ratio <= eachBreak ? 161 if ((ratio >= 0) && (ratio <= LUX_K1C)) 162 {b=LUX_B1C; m=LUX_M1C;} 163 else if (ratio <= LUX_K2C) 164 {b=LUX_B2C; m=LUX_M2C;} 165 else if (ratio <= LUX_K3C) 166 {b=LUX_B3C; m=LUX_M3C;} 167 else if (ratio <= LUX_K4C) 168 {b=LUX_B4C; m=LUX_M4C;} 169 else if (ratio <= LUX_K5C) 170 {b=LUX_B5C; m=LUX_M5C;} 171 else if (ratio <= LUX_K6C) 172 {b=LUX_B6C; m=LUX_M6C;} 173 else if (ratio <= LUX_K7C) 174 {b=LUX_B7C; m=LUX_M7C;} 175 else if (ratio > LUX_K8C) 176 {b=LUX_B8C; m=LUX_M8C;} 177 178 uint64_t tempLux = 0; 179 tempLux = ((channel0 * b) - (channel1 * m)); 180 // do not allow negative lux value 181 if (tempLux < 0) tempLux = 0; 182 183 // round lsb (2^(LUX_SCALE-1)) 184 tempLux += (1 << (LUX_SCALE-1)); 185 186 // strip off fractional portion 187 lux = tempLux >> LUX_SCALE; 188 189 return lux; 190 } 191 192 193 mraa::Result 194 TSL2561::i2cWriteReg (uint8_t reg, uint8_t value) 195 { 196 mraa::Result error = mraa::SUCCESS; 197 198 // Start transmission to device 199 error = m_i2ControlCtx.address (m_controlAddr); 200 if (error != mraa::SUCCESS) { 201 fprintf(stderr, "Error: on i2c bus address setup in i2cWriteReg()\n"); 202 return error; 203 } 204 // Write register to I2C 205 error = m_i2ControlCtx.writeByte (reg); 206 if (error != mraa::SUCCESS) { 207 fprintf(stderr, "Error: on i2c bus write reg in i2cWriteReg()\n"); 208 return error; 209 } 210 211 // Write value to I2C 212 error = m_i2ControlCtx.writeByte (value); 213 if (error != mraa::SUCCESS) { 214 fprintf(stderr, "Error: on i2c bus write value in i2cWriteReg()\n"); 215 return error; 216 } 217 218 usleep(100000); 219 220 return error; 221 } 222 223 mraa::Result 224 TSL2561::i2cReadReg(uint8_t reg, uint8_t &data) 225 { 226 mraa::Result error = mraa::SUCCESS; 227 228 // Start transmission to device 229 error = m_i2ControlCtx.address(m_controlAddr); 230 if (error != mraa::SUCCESS) { 231 fprintf(stderr, "Error: on i2c bus address setup in i2cReadReg()\n"); 232 return error; 233 } 234 235 // Send address of register to be read. 236 error = m_i2ControlCtx.writeByte(reg); 237 if (error != mraa::SUCCESS) { 238 fprintf(stderr, "Error: on i2c bus write in i2cReadReg()\n"); 239 return error; 240 } 241 242 // Read byte. 243 data = m_i2ControlCtx.readByte(); 244 245 usleep(10000); 246 247 return error; 248 } 249