Skip to content
This repository has been archived by the owner on Jan 7, 2019. It is now read-only.

Commit

Permalink
[driver] Driver for TCS3472X color sensor (based on TCS34714 driver)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arjun Sarin authored and salkinium committed Apr 27, 2017
1 parent 7111cd3 commit 68b904e
Show file tree
Hide file tree
Showing 2 changed files with 373 additions and 0 deletions.
242 changes: 242 additions & 0 deletions src/xpcc/driver/color/tcs3472.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// coding: utf-8
/* Copyright (c) 2017, Arjun Sarin
* All Rights Reserved.
*
* The file is part of the xpcc library and is released under the 3-clause BSD
* license. See the file `LICENSE` for the full license governing this code.
*/
// ----------------------------------------------------------------------------

/**
* \file tcs3472.hpp
* \date 04 Feb 2017
* \author David Hebbeker, Arjun Sarin
*/

#ifndef XPCC_TCS3472_HPP
#define XPCC_TCS3472_HPP

#include <stdint.h>

#include <xpcc/ui/color.hpp>
#include <xpcc/processing/protothread.hpp>
#include <xpcc/processing/resumable.hpp>
#include <xpcc/architecture/interface/i2c_device.hpp>

namespace xpcc
{
/**
* \brief Settings to configure the ams digital color sensor family tcs34721, -13, -15, 17
* \see tcs3472
* \ingroup driver_other
*
* Device Address
* tcs34721 0x39 (with IR filter)
* 3 0x39 (without IR filter)
* 5 0x29 (with IR filter)
* 7 0x29 (without IR filter)
*
*/
struct tcs3472
{
/** @name Gain_Register
* @{
*/

//! \brief Analog rgbc gain control
enum class Gain : uint8_t
{
X1 = 0b00, //!< x1 gain
X4 = 0b01, //!< x4 gain
X16 = 0b10, //!< x16 gain
X64 = 0b11, //!< x60 gain
DEFAULT = 0 //!< default value on chip reset
};
//! @}


//! \brief Integration for a fixed time
enum class IntegrationTime : uint8_t
{
MSEC_2 = 0xFF, //!< integrate over 2.4 ms
MSEC_24 = 0xF6, //!< integrate over 100 ms
MSEC_101 = 0xD5, //!< integrate over 101 ms
MSEC_154 = 0xC0, //!< integrate over 154 ms
MSEC_700 = 0x00, //!< integrate over 700 ms
DEFAULT = 0xFF //!< default value on chip reset
};
//! @}


//! \brief Register addresses
enum class RegisterAddress : uint8_t
{
ENABLE = 0x00, //!< Primarily to power up the device
TIMING = 0x01, //!< Integration time control @see tcs3472::setIntegrationTime
//INTERRUPT = 0x02, //!< Interrupt settings
//INT_SOURCE = 0x03, //!< Interrupt source
ID = 0x12, //!< Part number
GAIN = 0x0F, //!< Sensitivity settings @see Tcs3414::setGain
// Interrupt threshold registers
LOW_THRESH_LOW_BYTE = 0x04, //!< Low byte of low interrupt threshold
LOW_THRESH_HIGH_BYTE = 0x05, //!< High byte of low interrupt threshold
HIGH_THRESH_LOW_BYTE = 0x06, //!< Low byte of high interrupt threshold
HIGH_THRESH_HIGH_BYTE = 0x07, //!< High byte of high interrupt threshold
// Data registers
CDATALOW = 0x14, //!< Low byte of ADC clear channel
CDATAHIGH = 0x15, //!< High byte of ADC clear channel
RDATALOW = 0x16, //!< Low byte of ADC red channel
RDATAHIGH = 0x17, //!< High byte of ADC red channel
GDATALOW = 0x18, //!< Low byte of ADC green channel
GDATAHIGH = 0x19, //!< High byte of ADC green channel
BDATALOW = 0x1A, //!< Low byte of ADC blue channel
BDATAHIGH = 0x1B //!< High byte of ADC blue channel
};

typedef uint16_t UnderlyingType; //!< datatype of color values
typedef color::RgbT<UnderlyingType> Rgb;

};

/**
* \brief Tcs3472X Digital Color Sensors
*
* \todo Not all features of the sensors are implemented in this driver
* yet.
*
* \tparam I2CMaster I2C interface which needs an \em initialized
* xpcc::i2c::Master
* \see tcs3472
* \author David Hebbeker, Arjun Sarin
* \ingroup driver_other
*/
template < typename I2cMaster >
class Tcs3472 : public tcs3472, public xpcc::I2cDevice< I2cMaster, 2 >
{
public:
Tcs3472(uint8_t address = 0x29);

//! \brief Power up sensor and start conversions
// Blocking
bool inline
initializeBlocking()
{
return RF_CALL_BLOCKING(initialize());
}

//! \brief The gain can be used to adjust the sensitivity of all ADC output channels.
xpcc::ResumableResult<bool>
setGain(
const Gain gain = Gain::DEFAULT)
{
return writeRegister(RegisterAddress::GAIN,
static_cast<uint8_t>(gain));
}

/**
* @name Return already sampled color
* @{
*/
inline static Tcs3472::Rgb
getOldColors()
{
return color;
};

//!@}

/**
* @name Sample and return fresh color values
* @{
*/
inline static Tcs3472::Rgb
getNewColors()
{
refreshAllColors();
return getOldColors();
};

//!@}

//! \brief Read current samples of ADC conversions for all channels.
// Non-blocking
xpcc::ResumableResult<bool>
refreshAllColors();

// MARK: - TASKS
xpcc::ResumableResult<bool>
initialize()
{
return writeRegister(RegisterAddress::ENABLE, 0b11); // control to power up and start conversion
// note: adafruits driver waits 3ms before writing AEN bit (0b10). we don't??
};

xpcc::ResumableResult<bool>
configure(
const Gain gain = Gain::DEFAULT,
const uint8_t int_time = IntegrationTime::DEFAULT);

private:
//! \brief Sets the integration time for the ADCs.
xpcc::ResumableResult<bool>
setIntegrationTime(const uint8_t int_time = 0)
{
return writeRegister(
RegisterAddress::TIMING,
static_cast<uint8_t>(int_time));
}

private:
uint8_t commandBuffer[4];
bool success;

private:
//! \brief Read value of specific register.
xpcc::ResumableResult<bool>
readRegisters(
const RegisterAddress address,
uint8_t * const values,
const uint8_t count = 1);

xpcc::ResumableResult<bool>
writeRegister(
const RegisterAddress address,
const uint8_t value);

private:
class uint16_t_LOW_HIGH
{
private:
uint8_t low;
uint8_t high;
public:
uint16_t
get() const
{
uint16_t value = low;
value |= high << 8;
return value;
}
inline uint8_t getLSB() const { return low; }
inline uint8_t getMSB() const { return high; }
} xpcc_packed;

static union Data
{
uint8_t dataBytes[2*4];
struct
{
uint16_t_LOW_HIGH clear;
uint16_t_LOW_HIGH red;
uint16_t_LOW_HIGH green;
uint16_t_LOW_HIGH blue;
} xpcc_packed;
} data;

static Rgb color;
};
}

#include "tcs3472_impl.hpp"

#endif // XPCC_tcs3472_HPP
131 changes: 131 additions & 0 deletions src/xpcc/driver/color/tcs3472_impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// coding: utf-8
/* Copyright (c) 2017, Arjun Sarin
* All Rights Reserved.
*
* The file is part of the xpcc library and is released under the 3-clause BSD
* license. See the file `LICENSE` for the full license governing this code.
*/
// ----------------------------------------------------------------------------

#ifndef XPCC_TCS3472_HPP
# error "Don't include this file directly, use 'tcs3471.hpp' instead!"
#endif

template<typename I2cMaster>
typename xpcc::Tcs3472<I2cMaster>::Data xpcc::Tcs3472<I2cMaster>::data;

template<typename I2cMaster>
typename xpcc::tcs3472::Rgb xpcc::Tcs3472<I2cMaster>::color;

template < typename I2cMaster >
xpcc::Tcs3472<I2cMaster>::Tcs3472(uint8_t address)
: I2cDevice<I2cMaster,2>(address),
commandBuffer{0,0,0,0}
{
}

// ----------------------------------------------------------------------------
template<typename I2cMaster>
xpcc::ResumableResult<bool>
xpcc::Tcs3472<I2cMaster>::configure(
const Gain gain,
const uint8_t int_time)
{
RF_BEGIN();

if ( RF_CALL(setGain(gain) ) )
{
if ( RF_CALL(setIntegrationTime(int_time)) )
{
RF_RETURN(true);
}
}

RF_END_RETURN(false);
}

// ----------------------------------------------------------------------------
// MARK: - Tasks
template < class I2cMaster >
xpcc::ResumableResult<bool>
xpcc::Tcs3472<I2cMaster>::refreshAllColors()
{
RF_BEGIN();

// start reading in CDATALOW, continue reading in following registers
// with the auto-increment mode of the i2c protocoll @see Tcs3472::readRegisters
if ( RF_CALL(readRegisters(
RegisterAddress::CDATALOW,
data.dataBytes,
sizeof(data.dataBytes)
) ) )
{
// adapt the values to the overall light intensity
// so that R + G + B = C
color.red = data.red.get();
color.green = data.green.get();
color.blue = data.blue.get();

{
// START --> This part is not really necessary
// Rationale:
// Imagine a low band light. For example a green laser. In case the filters
// of this sensors do not transfer this wavelength well, it might
// result in all colors being very low. The clear value will not
// filter colors and thus it will see a bright light (intensity).
// In order to still have some signal the very low green value can be
// amplified with the clear value.
const float c = static_cast<float>(color.red) +
static_cast<float>(color.green) +
static_cast<float>(color.blue);
const float f = data.clear.get() / c;
color.red *= f;
color.green *= f;
color.blue *= f;
}

// <-- END
RF_RETURN(true);
}

RF_END_RETURN(false);
}

// ----------------------------------------------------------------------------
template<typename I2cMaster>
xpcc::ResumableResult<bool>
xpcc::Tcs3472<I2cMaster>::writeRegister(
const RegisterAddress address,
const uint8_t value)
{
RF_BEGIN();

commandBuffer[0] =
0x80 // write command
| 0x40 // with SMB read/write protocol
| static_cast<uint8_t>(address); // at this address
commandBuffer[2] = value;

this->transaction.configureWrite(commandBuffer, 3);

RF_END_RETURN_CALL( this->runTransaction() );
}

template<typename I2cMaster>
xpcc::ResumableResult<bool>
xpcc::Tcs3472<I2cMaster>::readRegisters(
const RegisterAddress address,
uint8_t* const values,
const uint8_t count)
{
RF_BEGIN();

commandBuffer[0] =
static_cast<uint8_t>(0x80) // write command
| static_cast<uint8_t>(0x40) // with SMB read/write protocol
| static_cast<uint8_t>(address); // at this address

this->transaction.configureWriteRead(commandBuffer, 1, values, count);

RF_END_RETURN_CALL( this->runTransaction() );
}

0 comments on commit 68b904e

Please sign in to comment.