11"""
2- Python library for the TCS34725 Color Sensor
2+ Python library for the TCS3472x and TCS340x Color Sensors
33Documentation (including datasheet): https://ams.com/tcs34725#tab/documents
4+ https://ams.com/tcs3400#tab/documents
5+ The sense hat for AstroPi on the ISS uses the TCS34725.
6+ The sense hat v2 uses the TCS3400 the successor of the TCS34725.
7+ The TCS34725 is not available any more. It was discontinued by ams in 2021.
48"""
59
610from time import sleep
1115class HardwareInterface :
1216 """
1317 `HardwareInterface` is the abstract class that sits between the
14- `ColourSensor` class (providing the TCS34725 sensor API) and the
15- actual hardware. Using this intermediate layer of abstraction, a
16- `ColourSensor` object interacts with the hardware without being
18+ `ColourSensor` class (providing the TCS34725/TCS3400 sensor API)
19+ and the actual hardware. Using this intermediate layer of abstraction,
20+ a `ColourSensor` object interacts with the hardware without being
1721 aware of how this interaction is implemented.
1822 Different subclasses of the `HardwareInterface` class can provide
1923 access to the hardware through e.g. I2C, `libiio` and its system
2024 files or even a hardware emulator.
2125 """
2226
23- GAIN_VALUES = (1 , 4 , 16 , 60 )
24- CLOCK_STEP = 0.0024 # the clock step is 2.4ms
25-
2627 @staticmethod
2728 def max_value (integration_cycles ):
2829 """
2930 The maximum raw value for the RBGC channels depends on the number
3031 of integration cycles.
3132 """
32- return 2 ** 16 if integration_cycles >= 64 else 1024 * integration_cycles
33+ return 65535 if integration_cycles >= 64 else 1024 * integration_cycles
3334
3435 def get_enabled (self ):
3536 """
@@ -123,36 +124,34 @@ def _raw_wrapper(register):
123124 fashion. This is a factory function that implements this retrieval method.
124125 """
125126 def get_raw_register (self ):
126- return self ._read (register )
127+ block = self .bus .read_i2c_block_data (self .ADDR , register , 2 )
128+ return (block [0 ] + (block [1 ] << 8 ))
127129 return get_raw_register
128130
129131class I2C (HardwareInterface ):
130132 """
131- An implementation of the `HardwareInterface` for the TCS34725 sensor
132- that uses I2C to control the sensor and retrieve measurements.
133- Use the datasheet as a reference: https://ams.com/tcs34725#tab/documents
133+ An implementation of the `HardwareInterface` for the TCS34725/TCS3400
134+ sensor that uses I2C to control the sensor and retrieve measurements.
135+ Use the datasheets as a reference.
134136 """
135137
136138 # device-specific constants
137139 BUS = 1
138- ADDR = 0x29
139-
140- COMMAND_BIT = 0x80
141140
142141 # control registers
143- ENABLE = 0x00 | COMMAND_BIT
144- ATIME = 0x01 | COMMAND_BIT
145- CONTROL = 0x0F | COMMAND_BIT
146- ID = 0x12 | COMMAND_BIT
147- STATUS = 0x13 | COMMAND_BIT
142+ ENABLE = 0x80
143+ ATIME = 0x81
144+ CONTROL = 0x8F
145+ ID = 0x92
146+ STATUS = 0x93
148147 # (if a register is described in the datasheet but missing here
149148 # it means the corresponding functionality is not provided)
150149
151150 # data registers
152- CDATA = 0x14 | COMMAND_BIT
153- RDATA = 0x16 | COMMAND_BIT
154- GDATA = 0x18 | COMMAND_BIT
155- BDATA = 0x1A | COMMAND_BIT
151+ CDATA = 0x94
152+ RDATA = 0x96
153+ GDATA = 0x98
154+ BDATA = 0x9A
156155
157156 # bit positions
158157 OFF = 0x00
@@ -162,9 +161,13 @@ class I2C(HardwareInterface):
162161 AVALID = 0x01
163162
164163 GAIN_REG_VALUES = (0x00 , 0x01 , 0x02 , 0x03 )
165- # map gain values to register values and vice-versa
166- GAIN_TO_REG = dict (zip (HardwareInterface .GAIN_VALUES , GAIN_REG_VALUES ))
167- REG_TO_GAIN = dict (zip (GAIN_REG_VALUES , HardwareInterface .GAIN_VALUES ))
164+ # Assume TCS34725 as on the ISS AstroPi
165+ # Adjust for TCS3400 after the detection of the sensor type.
166+ ADDR = 0x29
167+ GAIN_VALUES = (1 , 4 , 16 , 60 )
168+ CLOCK_STEP = 0.0024 # 2.4ms
169+ GAIN_TO_REG = dict (zip (GAIN_VALUES , GAIN_REG_VALUES ))
170+ REG_TO_GAIN = dict (zip (GAIN_REG_VALUES , GAIN_VALUES ))
168171
169172 def __init__ (self ):
170173
@@ -176,14 +179,43 @@ def __init__(self):
176179 except Exception as e :
177180 explanation = "(I2C is not enabled)" if not self .i2c_enabled () else ""
178181 raise ColourSensorInitialisationError (explanation = explanation ) from e
182+
183+ # Test for sensor at I2C addresses 0x29 or 0x39
184+ # Both sensors have variants at 0x29 and 0x39 (See data sheets)
185+ addr1 = addr2 = False
179186 try :
187+ self .bus .write_quick (0x29 )
188+ addr1 = True
189+ except :
190+ pass
191+ try :
192+ self .bus .write_quick (0x39 )
193+ addr2 = True
194+ except :
195+ pass
196+
197+ if addr2 :
198+ self .ADDR = 0x39
199+ if addr1 or addr2 :
200+ # get sensor id
180201 id = self ._read (self .ID )
181- except Exception as e :
182- explanation = "(sensor not present)"
183- raise ColourSensorInitialisationError (explanation = explanation ) from e
184- if id != 0x44 :
185- explanation = f" (different device id detected: { id } )"
186- raise ColourSensorInitialisationError (explanation = explanation ) from e
202+ if (id & 0xf8 ) == 0x90 :
203+ sensor = 'TCS340x'
204+ elif (id & 0xf4 ) == 0x44 :
205+ sensor = 'TCS3472x'
206+ else :
207+ explanation = "(Sensor not present)"
208+ raise ColourSensorInitialisationError (explanation = explanation )
209+
210+ # Set type specific constants
211+ # Assume TCS3472x as in AstroPi
212+ sensor == 'TCS3472x'
213+ if sensor == 'TCS340x' :
214+ self .GAIN_VALUES = (1 , 4 , 16 , 64 )
215+ self .CLOCK_STEP = 0.00275 # 2.75ms
216+ self .GAIN_TO_REG = dict (zip (self .GAIN_VALUES , self .GAIN_REG_VALUES ))
217+ self .REG_TO_GAIN = dict (zip (self .GAIN_REG_VALUES , self .GAIN_VALUES ))
218+
187219 @staticmethod
188220 def i2c_enabled ():
189221 """Returns True if I2C is enabled or False otherwise."""
@@ -192,14 +224,14 @@ def i2c_enabled():
192224 def _read (self , attribute ):
193225 """
194226 Read and return the value of a specific register (`attribute`) of the
195- TCS34725 colour sensor.
227+ TCS34725/TCS3400 colour sensor.
196228 """
197229 return self .bus .read_byte_data (self .ADDR , attribute )
198230
199231 def _write (self , attribute , value ):
200232 """
201233 Write a value in a specific register (`attribute`) of the
202- TCS34725 colour sensor.
234+ TCS34725/TCS3400 colour sensor.
203235 """
204236 self .bus .write_byte_data (self .ADDR , attribute , value )
205237
0 commit comments