#include "TCS34725.h" typedef enum { TCS34725_INTEGRATIONTIME_2_4MS = 0xFF, /**< 2.4ms - 1 cycle - Max Count: 1024 */ TCS34725_INTEGRATIONTIME_24MS = 0xF6, /**< 24ms - 10 cycles - Max Count: 10240 */ TCS34725_INTEGRATIONTIME_50MS = 0xEB, /**< 50ms - 20 cycles - Max Count: 20480 */ TCS34725_INTEGRATIONTIME_101MS = 0xD5, /**< 101ms - 42 cycles - Max Count: 43008 */ TCS34725_INTEGRATIONTIME_154MS = 0xC0, /**< 154ms - 64 cycles - Max Count: 65535 */ TCS34725_INTEGRATIONTIME_700MS = 0x00 /**< 700ms - 256 cycles - Max Count: 65535 */ } tcs34725IntegrationTime_t; typedef enum { TCS34725_GAIN_1X = 0x00, /**< No gain */ TCS34725_GAIN_4X = 0x01, /**< 4x gain */ TCS34725_GAIN_16X = 0x02, /**< 16x gain */ TCS34725_GAIN_60X = 0x03 /**< 60x gain */ } tcs34725Gain_t; tcs34725IntegrationTime_t _tcs34725IntegrationTime; tcs34725Gain_t _tcs34725Gain; uint8_t TCS34725_I2C_Read(uint8_t addr, uint8_t reg) { uint8_t TCS34725_I2C[3]={0,}; uint16_t value = 0; uint8_t data = 0; data=HAL_I2C_Mem_Read(&hi2c1, addr, reg, 1, TCS34725_I2C, 1, 10); value = TCS34725_I2C[0]; return value; } void TCS34725_I2C_Write(uint8_t addr, uint8_t reg, uint8_t data) { uint8_t tmp_afe; tmp_afe = data; HAL_I2C_Mem_Write(&hi2c1, addr, reg, 1, &tmp_afe, 1, 10); } /**************************************************************************/ /*! Adjusts the gain on the TCS34725 (adjusts the sensitivity to light) */ /**************************************************************************/ void TCS34725_getrawdata(void) { uint8_t data_ret_R =0; uint8_t data_ret_G =0; uint8_t data_ret_B =0; uint8_t data_ret_C =0; uint8_t DEV_DATA = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_ID); uint8_t C_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_CDATAL); uint8_t C_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_CDATAH); uint8_t R_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_RDATAL); uint8_t R_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_RDATAH); uint8_t G_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_GDATAL); uint8_t G_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_GDATAH); uint8_t B_DATA_L = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_BDATAL); uint8_t B_DATA_H = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_BDATAH); #if 0 double CLEAR = 0; double RED = 0; double GREEN = 0; double BLUE = 0; printf("************************************\r\n"); printf("1. DEV ID\t:\t%x\r\n", DEV_DATA); CLEAR = (C_DATA_H << 8) | C_DATA_L; data_ret_C = (CLEAR / 65535)*255; printf("CLEAR : %d\r\n",data_ret_C); RED = (R_DATA_H << 8) | R_DATA_L; data_ret_R = (RED / 65535)*255; printf("RED : %d\r\n",data_ret_R); GREEN = (G_DATA_H << 8) | G_DATA_L; data_ret_G = (GREEN / 65535)*255; printf("GREEN : %d\r\n",data_ret_G); BLUE = (B_DATA_H << 8) | B_DATA_L; data_ret_B = (BLUE / 65535)*255; printf("BLUE : %d\r\n",data_ret_B); #else double CLEAR = 0; double RED = 0; double GREEN = 0; double BLUE = 0; CLEAR = (C_DATA_H << 8) | C_DATA_L; data_ret_C = (CLEAR / 65535)*255; RED = (R_DATA_H << 8) | R_DATA_L; data_ret_R = (RED / 65535)*255; GREEN = (G_DATA_H << 8) | G_DATA_L; data_ret_G = (GREEN / 65535)*255; BLUE = (B_DATA_H << 8) | B_DATA_L; data_ret_B = (BLUE / 65535)*255; #if 0 printf("02%04x%05d%04x%05d%04x%05d%04x%05d03\r\n",data_ret_C,data_ret_C,data_ret_R,data_ret_R,data_ret_G,data_ret_G,data_ret_B,data_ret_B); #else // printf("%04x,%05d,%04x,%05d,%04x,%05d,%04x,%05d,\r\n",data_ret_C,data_ret_C,data_ret_R,data_ret_R,data_ret_G,data_ret_G,data_ret_B,data_ret_B); printf("%x %d %d %d %d %d %d %d %d\r\n",DEV_DATA,(uint16_t)CLEAR,data_ret_C,(uint16_t)RED,data_ret_R,(uint16_t)GREEN,data_ret_G,(uint16_t)BLUE,data_ret_B); #endif #endif #if 0 uint16_t CLEAR = 0; uint16_t RED = 0; uint16_t GREEN = 0; uint16_t BLUE = 0; CLEAR = (C_DATA_H << 8) | C_DATA_L; RED = (R_DATA_H << 8) | R_DATA_L; GREEN = (G_DATA_H << 8) | G_DATA_L; BLUE = (B_DATA_H << 8) | B_DATA_L; printf("1. DEV ID\t:\t%x\r\n", DEV_DATA); printf("3. C\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", CLEAR,CLEAR); printf("4. R\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", RED,RED); printf("5. G\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", GREEN,GREEN); printf("6. B\t:\tHEX : [%04x]\tDEC : [%05d]\r\n", BLUE,BLUE); #else // printf("02%04x%05d%04x%05d%04x%05d%04x%05d03\r\n",CLEAR,CLEAR,RED,RED,GREEN,GREEN,BLUE,BLUE); #endif } void TCS34725_disable(void){ /* Turn the device off to save power */ uint8_t reg = 0; reg = TCS34725_I2C_Read(TCS34725_ADDRESS,TCS34725_ENABLE); TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN)); } void TCS34725_enable(void) { TCS34725_I2C_Write(TCS34725_ADDRESS, TCS34725_ENABLE, TCS34725_ENABLE_PON); HAL_Delay(3); TCS34725_I2C_Write(TCS34725_ADDRESS, TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN); switch (_tcs34725IntegrationTime) { case TCS34725_INTEGRATIONTIME_2_4MS: HAL_Delay(3); break; case TCS34725_INTEGRATIONTIME_24MS: HAL_Delay(24); break; case TCS34725_INTEGRATIONTIME_50MS: HAL_Delay(50); break; case TCS34725_INTEGRATIONTIME_101MS: HAL_Delay(101); break; case TCS34725_INTEGRATIONTIME_154MS: HAL_Delay(154); break; case TCS34725_INTEGRATIONTIME_700MS: HAL_Delay(700); break; } } void tcs34725SetIntegrationTime(tcs34725IntegrationTime_t it) { TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_ATIME, it); _tcs34725IntegrationTime = it; } void getRawDataOneShot (void) { // TCS34725_enable(); TCS34725_getrawdata(); // TCS34725_disable(); } /**************************************************************************/ /*! @brief Converts the raw R/G/B values to color temperature in degrees Kelvin */ /**************************************************************************/ uint16_t calculateColorTemperature(uint16_t r, uint16_t g, uint16_t b) { float X, Y, Z; /* RGB to XYZ correlation */ float xc, yc; /* Chromaticity co-ordinates */ float n; /* McCamy's formula */ float cct; /* 1. Map RGB values to their XYZ counterparts. */ /* Based on 6500K fluorescent, 3000K fluorescent */ /* and 60W incandescent values for a wide range. */ /* Note: Y = Illuminance or lux */ X = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b); Y = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); Z = (-0.68202F * r) + (0.77073F * g) + ( 0.56332F * b); /* 2. Calculate the chromaticity co-ordinates */ xc = (X) / (X + Y + Z); yc = (Y) / (X + Y + Z); /* 3. Use McCamy's formula to determine the CCT */ n = (xc - 0.3320F) / (0.1858F - yc); /* Calculate the final CCT */ cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F; /* Return the results in degrees Kelvin */ return (uint16_t)cct; } /**************************************************************************/ /*! @brief Converts the raw R/G/B values to lux */ /**************************************************************************/ uint16_t calculateLux(uint16_t r, uint16_t g, uint16_t b) { float illuminance; /* This only uses RGB ... how can we integrate clear or calculate lux */ /* based exclusively on clear since this might be more reliable? */ illuminance = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); return (uint16_t)illuminance; } /**************************************************************************/ /*! @brief Sets gain to the specified value */ /**************************************************************************/ void tcs34725SetGain(tcs34725Gain_t gain) { TCS34725_I2C_Write(TCS34725_ADDRESS,TCS34725_CONTROL, gain); _tcs34725Gain = gain; } /**************************************************************************/ /*! @brief Converts the raw R/G/B values to color temperature in degrees Kelvin using the algorithm described in DN40 from Taos (now AMS). */ /**************************************************************************/ uint16_t calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b, uint16_t c) { int rc; /* Error return code */ uint16_t r2, g2, b2; /* RGB values minus IR component */ int gl; /* Results of the initial lux conversion */ uint8_t gain_int; /* Gain multiplier as a normal integer */ uint16_t sat; /* Digital saturation level */ uint16_t ir; /* Inferred IR content */ /* Analog/Digital saturation: * * (a) As light becomes brighter, the clear channel will tend to * saturate first since R+G+B is approximately equal to C. * (b) The TCS34725 accumulates 1024 counts per 2.4ms of integration * time, up to a maximum values of 65535. This means analog * saturation can occur up to an integration time of 153.6ms * (64*2.4ms=153.6ms). * (c) If the integration time is > 153.6ms, digital saturation will * occur before analog saturation. Digital saturation occurs when * the count reaches 65535. */ if ((256 - _tcs34725IntegrationTime) > 63) { /* Track digital saturation */ sat = 65535; } else { /* Track analog saturation */ sat = 1024 * (256 - _tcs34725IntegrationTime); } /* Ripple rejection: * * (a) An integration time of 50ms or multiples of 50ms are required to * reject both 50Hz and 60Hz ripple. * (b) If an integration time faster than 50ms is required, you may need * to average a number of samples over a 50ms period to reject ripple * from fluorescent and incandescent light sources. * * Ripple saturation notes: * * (a) If there is ripple in the received signal, the value read from C * will be less than the max, but still have some effects of being * saturated. This means that you can be below the 'sat' value, but * still be saturating. At integration times >150ms this can be * ignored, but <= 150ms you should calculate the 75% saturation * level to avoid this problem. */ if ((256 - _tcs34725IntegrationTime) <= 63) { /* Adjust sat to 75% to avoid analog saturation if atime < 153.6ms */ sat -= sat/4; } /* Check for saturation and mark the sample as invalid if true */ if (c >= sat) { return 0; } /* AMS RGB sensors have no IR channel, so the IR content must be */ /* calculated indirectly. */ ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0; /* Remove the IR component from the raw RGB values */ r2 = r - ir; g2 = g - ir; b2 = b - ir; /* Convert gain to a usable integer value */ switch(_tcs34725Gain) { case TCS34725_GAIN_4X: /* GAIN 4X */ gain_int = 4; break; case TCS34725_GAIN_16X: /* GAIN 16X */ gain_int = 16; break; case TCS34725_GAIN_60X: /* GAIN 60X */ gain_int = 60; break; case TCS34725_GAIN_1X: /* GAIN 1X */ default: gain_int = 1; break; } /* Calculate the counts per lux (CPL), taking into account the optional * arguments for Glass Attenuation (GA) and Device Factor (DF). * * GA = 1/T where T is glass transmissivity, meaning if glass is 50% * transmissive, the GA is 2 (1/0.5=2), and if the glass attenuates light * 95% the GA is 20 (1/0.05). A GA of 1.0 assumes perfect transmission. * * NOTE: It is recommended to have a CPL > 5 to have a lux accuracy * < +/- 0.5 lux, where the digitization error can be calculated via: * 'DER = (+/-2) / CPL'. */ float cpl = (((256-_tcs34725IntegrationTime)*2.4f) * gain_int) / (1.0f * 310.0f); /* Determine lux accuracy (+/- lux) */ float der = 2.0f / cpl; /* Determine the maximum lux value */ float max_lux = 65535.0 / (cpl * 3); /* Lux is a function of the IR-compensated RGB channels and the associated * color coefficients, with G having a particularly heavy influence to * match the nature of the human eye. * * NOTE: The green value should be > 10 to ensure the accuracy of the lux * conversions. If it is below 10, the gain should be increased, but * the clear<100 check earlier should cover this edge case. */ gl = 0.136f * (float)r2 + /** Red coefficient. */ 1.000f * (float)g2 + /** Green coefficient. */ -0.444f * (float)b2; /** Blue coefficient. */ float lux = gl / cpl; /* A simple method of measuring color temp is to use the ratio of blue */ /* to red light, taking IR cancellation into account. */ uint16_t cct = (3810 * (uint32_t)b2) / /** Color temp coefficient. */ (uint32_t)r2 + 1391; /** Color temp offset. */ return cct; } void i2c_status(HAL_StatusTypeDef data){ switch(data){ case HAL_OK :printf("HAL_OK \r\n");break; case HAL_ERROR :printf("HAL_ERROR \r\n");break; case HAL_BUSY :printf("HAL_BUSY \r\n");break; case HAL_TIMEOUT :printf("HAL_TIMEOUT\r\n");break; } } void TCS34725_init(void){ uint8_t DEV_DATA = TCS34725_I2C_Read(TCS34725_ADDRESS, TCS34725_COMMAND_BIT | TCS34725_ID); // tcs34725SetIntegrationTime(TCS34725_INTEGRATIONTIME_700MS); // tcs34725SetGain(TCS34725_GAIN_60X); TCS34725_enable(); if(DEV_DATA == 0x44){ printf("TCS34725_Success\r\n"); }else{ printf("TCS34725_Failed\r\n"); } }