Skip to content

Commit 116a9aa

Browse files
author
Kevin Townsend
committed
Implemented DN40 CCT algorithm for more accurate results
1 parent e5bdf0d commit 116a9aa

File tree

4 files changed

+150
-18
lines changed

4 files changed

+150
-18
lines changed

Adafruit_TCS34725.cpp

+137-7
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ void Adafruit_TCS34725::enable(void)
119119
{
120120
write8(TCS34725_ENABLE, TCS34725_ENABLE_PON);
121121
delay(3);
122-
write8(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
122+
write8(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
123123
/* Set a delay for the integration time.
124-
This is only necessary in the case where enabling and then
124+
This is only necessary in the case where enabling and then
125125
immediately trying to read values back. This is because setting
126126
AEN triggers an automatic integration, so if a read RGBC is
127127
performed too quickly, the data is not yet valid and all 0's are
@@ -171,7 +171,7 @@ void Adafruit_TCS34725::disable(void)
171171
Constructor
172172
*/
173173
/**************************************************************************/
174-
Adafruit_TCS34725::Adafruit_TCS34725(tcs34725IntegrationTime_t it, tcs34725Gain_t gain)
174+
Adafruit_TCS34725::Adafruit_TCS34725(tcs34725IntegrationTime_t it, tcs34725Gain_t gain)
175175
{
176176
_tcs34725Initialised = false;
177177
_tcs34725IntegrationTime = it;
@@ -188,10 +188,10 @@ Adafruit_TCS34725::Adafruit_TCS34725(tcs34725IntegrationTime_t it, tcs34725Gain_
188188
doing anything else)
189189
*/
190190
/**************************************************************************/
191-
boolean Adafruit_TCS34725::begin(void)
191+
boolean Adafruit_TCS34725::begin(void)
192192
{
193193
Wire.begin();
194-
194+
195195
/* Make sure we're actually connected */
196196
uint8_t x = read8(TCS34725_ID);
197197
if ((x != 0x44) && (x != 0x10))
@@ -209,7 +209,7 @@ boolean Adafruit_TCS34725::begin(void)
209209

210210
return true;
211211
}
212-
212+
213213
/**************************************************************************/
214214
/*!
215215
Sets the integration time for the TC34725
@@ -255,7 +255,7 @@ void Adafruit_TCS34725::getRawData (uint16_t *r, uint16_t *g, uint16_t *b, uint1
255255
*r = read16(TCS34725_RDATAL);
256256
*g = read16(TCS34725_GDATAL);
257257
*b = read16(TCS34725_BDATAL);
258-
258+
259259
/* Set a delay for the integration time */
260260
switch (_tcs34725IntegrationTime)
261261
{
@@ -330,6 +330,136 @@ uint16_t Adafruit_TCS34725::calculateColorTemperature(uint16_t r, uint16_t g, ui
330330
return (uint16_t)cct;
331331
}
332332

333+
/**************************************************************************/
334+
/*!
335+
@brief Converts the raw R/G/B values to color temperature in degrees
336+
Kelvin using the algorithm described in DN40 from Taos (now AMS).
337+
*/
338+
/**************************************************************************/
339+
uint16_t Adafruit_TCS34725::calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b, uint16_t c)
340+
{
341+
int rc; /* Error return code */
342+
uint16_t r2, g2, b2; /* RGB values minus IR component */
343+
int gl; /* Results of the initial lux conversion */
344+
uint8_t gain_int; /* Gain multiplier as a normal integer */
345+
uint16_t sat; /* Digital saturation level */
346+
uint16_t ir; /* Inferred IR content */
347+
348+
/* Analog/Digital saturation:
349+
*
350+
* (a) As light becomes brighter, the clear channel will tend to
351+
* saturate first since R+G+B is approximately equal to C.
352+
* (b) The TCS34725 accumulates 1024 counts per 2.4ms of integration
353+
* time, up to a maximum values of 65535. This means analog
354+
* saturation can occur up to an integration time of 153.6ms
355+
* (64*2.4ms=153.6ms).
356+
* (c) If the integration time is > 153.6ms, digital saturation will
357+
* occur before analog saturation. Digital saturation occurs when
358+
* the count reaches 65535.
359+
*/
360+
if ((256 - _tcs34725IntegrationTime) > 63) {
361+
/* Track digital saturation */
362+
sat = 65535;
363+
} else {
364+
/* Track analog saturation */
365+
sat = 1024 * (256 - _tcs34725IntegrationTime);
366+
}
367+
368+
/* Ripple rejection:
369+
*
370+
* (a) An integration time of 50ms or multiples of 50ms are required to
371+
* reject both 50Hz and 60Hz ripple.
372+
* (b) If an integration time faster than 50ms is required, you may need
373+
* to average a number of samples over a 50ms period to reject ripple
374+
* from fluorescent and incandescent light sources.
375+
*
376+
* Ripple saturation notes:
377+
*
378+
* (a) If there is ripple in the received signal, the value read from C
379+
* will be less than the max, but still have some effects of being
380+
* saturated. This means that you can be below the 'sat' value, but
381+
* still be saturating. At integration times >150ms this can be
382+
* ignored, but <= 150ms you should calculate the 75% saturation
383+
* level to avoid this problem.
384+
*/
385+
if ((256 - _tcs34725IntegrationTime) <= 63) {
386+
/* Adjust sat to 75% to avoid analog saturation if atime < 153.6ms */
387+
sat -= sat/4;
388+
}
389+
390+
/* Check for saturation and mark the sample as invalid if true */
391+
if (c >= sat) {
392+
return 0;
393+
}
394+
395+
/* AMS RGB sensors have no IR channel, so the IR content must be */
396+
/* calculated indirectly. */
397+
ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0;
398+
399+
/* Remove the IR component from the raw RGB values */
400+
r2 = r - ir;
401+
g2 = g - ir;
402+
b2 = b - ir;
403+
404+
/* Convert gain to a usable integer value */
405+
switch(_tcs34725Gain) {
406+
case TCS34725_GAIN_4X: /* GAIN 4X */
407+
gain_int = 4;
408+
break;
409+
case TCS34725_GAIN_16X: /* GAIN 16X */
410+
gain_int = 16;
411+
break;
412+
case TCS34725_GAIN_60X: /* GAIN 60X */
413+
gain_int = 60;
414+
break;
415+
case TCS34725_GAIN_1X: /* GAIN 1X */
416+
default:
417+
gain_int = 1;
418+
break;
419+
}
420+
421+
/* Calculate the counts per lux (CPL), taking into account the optional
422+
* arguments for Glass Attenuation (GA) and Device Factor (DF).
423+
*
424+
* GA = 1/T where T is glass transmissivity, meaning if glass is 50%
425+
* transmissive, the GA is 2 (1/0.5=2), and if the glass attenuates light
426+
* 95% the GA is 20 (1/0.05). A GA of 1.0 assumes perfect transmission.
427+
*
428+
* NOTE: It is recommended to have a CPL > 5 to have a lux accuracy
429+
* < +/- 0.5 lux, where the digitization error can be calculated via:
430+
* 'DER = (+/-2) / CPL'.
431+
*/
432+
float cpl = (((256-_tcs34725IntegrationTime)*2.4f) * gain_int) /
433+
(1.0f * 310.0f);
434+
435+
/* Determine lux accuracy (+/- lux) */
436+
float der = 2.0f / cpl;
437+
438+
/* Determine the maximum lux value */
439+
float max_lux = 65535.0 / (cpl * 3);
440+
441+
/* Lux is a function of the IR-compensated RGB channels and the associated
442+
* color coefficients, with G having a particularly heavy influence to
443+
* match the nature of the human eye.
444+
*
445+
* NOTE: The green value should be > 10 to ensure the accuracy of the lux
446+
* conversions. If it is below 10, the gain should be increased, but
447+
* the clear<100 check earlier should cover this edge case.
448+
*/
449+
gl = 0.136f * (float)r2 + /** Red coefficient. */
450+
1.000f * (float)g2 + /** Green coefficient. */
451+
-0.444f * (float)b2; /** Blue coefficient. */
452+
453+
float lux = gl / cpl;
454+
455+
/* A simple method of measuring color temp is to use the ratio of blue */
456+
/* to red light, taking IR cancellation into account. */
457+
uint16_t cct = (3810 * (uint32_t)b2) / /** Color temp coefficient. */
458+
(uint32_t)r2 + 1391; /** Color temp offset. */
459+
460+
return cct;
461+
}
462+
333463
/**************************************************************************/
334464
/*!
335465
@brief Converts the raw R/G/B values to lux

Adafruit_TCS34725.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**************************************************************************/
2-
/*!
2+
/*!
33
@file Adafruit_TCS34725.h
44
@author KTOWN (Adafruit Industries)
55
@@ -118,13 +118,14 @@ tcs34725Gain_t;
118118
class Adafruit_TCS34725 {
119119
public:
120120
Adafruit_TCS34725(tcs34725IntegrationTime_t = TCS34725_INTEGRATIONTIME_2_4MS, tcs34725Gain_t = TCS34725_GAIN_1X);
121-
121+
122122
boolean begin(void);
123123
void setIntegrationTime(tcs34725IntegrationTime_t it);
124124
void setGain(tcs34725Gain_t gain);
125125
void getRawData(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c);
126126
void getRawDataOneShot(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c);
127127
uint16_t calculateColorTemperature(uint16_t r, uint16_t g, uint16_t b);
128+
uint16_t calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b, uint16_t c);
128129
uint16_t calculateLux(uint16_t r, uint16_t g, uint16_t b);
129130
void write8 (uint8_t reg, uint32_t value);
130131
uint8_t read8 (uint8_t reg);
@@ -138,8 +139,8 @@ class Adafruit_TCS34725 {
138139
private:
139140
boolean _tcs34725Initialised;
140141
tcs34725Gain_t _tcs34725Gain;
141-
tcs34725IntegrationTime_t _tcs34725IntegrationTime;
142-
142+
tcs34725IntegrationTime_t _tcs34725IntegrationTime;
143+
143144
};
144145

145146
#endif

examples/tcs34725/tcs34725.pde

+7-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Connect SDA to analog 4
88
Connect VDD to 3.3V DC
99
Connect GROUND to common ground */
10-
10+
1111
/* Initialise with default values (int time = 2.4ms, gain = 1x) */
1212
// Adafruit_TCS34725 tcs = Adafruit_TCS34725();
1313

@@ -16,24 +16,25 @@ Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS347
1616

1717
void setup(void) {
1818
Serial.begin(9600);
19-
19+
2020
if (tcs.begin()) {
2121
Serial.println("Found sensor");
2222
} else {
2323
Serial.println("No TCS34725 found ... check your connections");
2424
while (1);
2525
}
26-
26+
2727
// Now we're ready to get readings!
2828
}
2929

3030
void loop(void) {
3131
uint16_t r, g, b, c, colorTemp, lux;
32-
32+
3333
tcs.getRawData(&r, &g, &b, &c);
34-
colorTemp = tcs.calculateColorTemperature(r, g, b);
34+
// colorTemp = tcs.calculateColorTemperature(r, g, b);
35+
colorTemp = tcs.calculateColorTemperature_dn40(r, g, b, c);
3536
lux = tcs.calculateLux(r, g, b);
36-
37+
3738
Serial.print("Color Temp: "); Serial.print(colorTemp, DEC); Serial.print(" K - ");
3839
Serial.print("Lux: "); Serial.print(lux, DEC); Serial.print(" - ");
3940
Serial.print("R: "); Serial.print(r, DEC); Serial.print(" ");

library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Adafruit TCS34725
2-
version=1.1.0
2+
version=1.2.0
33
author=Adafruit
44
maintainer=Adafruit <[email protected]>
55
sentence=Driver for Adafruit's TCS34725 RGB Color Sensor Breakout

0 commit comments

Comments
 (0)