adafruit-circuitpython-tcs3430 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adafruit_circuitpython_tcs3430-1.0.0.dist-info/METADATA +162 -0
- adafruit_circuitpython_tcs3430-1.0.0.dist-info/RECORD +6 -0
- adafruit_circuitpython_tcs3430-1.0.0.dist-info/WHEEL +5 -0
- adafruit_circuitpython_tcs3430-1.0.0.dist-info/licenses/LICENSE +21 -0
- adafruit_circuitpython_tcs3430-1.0.0.dist-info/top_level.txt +1 -0
- adafruit_tcs3430.py +441 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: adafruit-circuitpython-tcs3430
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: CircuitPython driver library for AMS TCS3430 / TCS34303 XYZ tri-stimulus color sensor.
|
|
5
|
+
Author-email: Adafruit Industries <circuitpython@adafruit.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/adafruit/Adafruit_CircuitPython_TCS3430
|
|
8
|
+
Keywords: adafruit,blinka,circuitpython,micropython,tcs3430,rgb,light,sensor,tri-stimulus,xyz,tcs32303,light-sensor
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
11
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
12
|
+
Classifier: Topic :: System :: Hardware
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Description-Content-Type: text/x-rst
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: Adafruit-Blinka
|
|
17
|
+
Requires-Dist: adafruit-circuitpython-busdevice
|
|
18
|
+
Requires-Dist: adafruit-circuitpython-register
|
|
19
|
+
Provides-Extra: optional
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
Introduction
|
|
23
|
+
============
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
.. image:: https://readthedocs.org/projects/adafruit-circuitpython-tcs3430/badge/?version=latest
|
|
27
|
+
:target: https://docs.circuitpython.org/projects/tcs3430/en/latest/
|
|
28
|
+
:alt: Documentation Status
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
.. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg
|
|
32
|
+
:target: https://adafru.it/discord
|
|
33
|
+
:alt: Discord
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_TCS3430/workflows/Build%20CI/badge.svg
|
|
37
|
+
:target: https://github.com/adafruit/Adafruit_CircuitPython_TCS3430/actions
|
|
38
|
+
:alt: Build Status
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
42
|
+
:target: https://github.com/astral-sh/ruff
|
|
43
|
+
:alt: Code Style: Ruff
|
|
44
|
+
|
|
45
|
+
CircuitPython driver library for AMS TCS3430 / TCS34303 XYZ tri-stimulus color sensor.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Dependencies
|
|
49
|
+
=============
|
|
50
|
+
This driver depends on:
|
|
51
|
+
|
|
52
|
+
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
|
|
53
|
+
* `Bus Device <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice>`_
|
|
54
|
+
* `Register <https://github.com/adafruit/Adafruit_CircuitPython_Register>`_
|
|
55
|
+
|
|
56
|
+
Please ensure all dependencies are available on the CircuitPython filesystem.
|
|
57
|
+
This is easily achieved by downloading
|
|
58
|
+
`the Adafruit library and driver bundle <https://circuitpython.org/libraries>`_
|
|
59
|
+
or individual libraries can be installed using
|
|
60
|
+
`circup <https://github.com/adafruit/circup>`_.
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
`Purchase one from the Adafruit shop <http://www.adafruit.com/products/6479>`_
|
|
64
|
+
|
|
65
|
+
Installing from PyPI
|
|
66
|
+
=====================
|
|
67
|
+
|
|
68
|
+
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
|
|
69
|
+
PyPI <https://pypi.org/project/adafruit-circuitpython-tcs3430/>`_.
|
|
70
|
+
To install for current user:
|
|
71
|
+
|
|
72
|
+
.. code-block:: shell
|
|
73
|
+
|
|
74
|
+
pip3 install adafruit-circuitpython-tcs3430
|
|
75
|
+
|
|
76
|
+
To install system-wide (this may be required in some cases):
|
|
77
|
+
|
|
78
|
+
.. code-block:: shell
|
|
79
|
+
|
|
80
|
+
sudo pip3 install adafruit-circuitpython-tcs3430
|
|
81
|
+
|
|
82
|
+
To install in a virtual environment in your current project:
|
|
83
|
+
|
|
84
|
+
.. code-block:: shell
|
|
85
|
+
|
|
86
|
+
mkdir project-name && cd project-name
|
|
87
|
+
python3 -m venv .venv
|
|
88
|
+
source .env/bin/activate
|
|
89
|
+
pip3 install adafruit-circuitpython-tcs3430
|
|
90
|
+
|
|
91
|
+
Installing to a Connected CircuitPython Device with Circup
|
|
92
|
+
==========================================================
|
|
93
|
+
|
|
94
|
+
Make sure that you have ``circup`` installed in your Python environment.
|
|
95
|
+
Install it with the following command if necessary:
|
|
96
|
+
|
|
97
|
+
.. code-block:: shell
|
|
98
|
+
|
|
99
|
+
pip3 install circup
|
|
100
|
+
|
|
101
|
+
With ``circup`` installed and your CircuitPython device connected use the
|
|
102
|
+
following command to install:
|
|
103
|
+
|
|
104
|
+
.. code-block:: shell
|
|
105
|
+
|
|
106
|
+
circup install adafruit_tcs3430
|
|
107
|
+
|
|
108
|
+
Or the following command to update an existing version:
|
|
109
|
+
|
|
110
|
+
.. code-block:: shell
|
|
111
|
+
|
|
112
|
+
circup update
|
|
113
|
+
|
|
114
|
+
Usage Example
|
|
115
|
+
=============
|
|
116
|
+
|
|
117
|
+
.. code-block:: python
|
|
118
|
+
|
|
119
|
+
import time
|
|
120
|
+
|
|
121
|
+
import board
|
|
122
|
+
|
|
123
|
+
from adafruit_tcs3430 import TCS3430, ALSGain, InterruptPersistence
|
|
124
|
+
|
|
125
|
+
i2c = board.I2C()
|
|
126
|
+
tcs = TCS3430(i2c)
|
|
127
|
+
|
|
128
|
+
print("TCS3430 Basic Test")
|
|
129
|
+
print("TCS3430 found!")
|
|
130
|
+
|
|
131
|
+
# --- Tweak these settings for your environment ---
|
|
132
|
+
tcs.als_gain = ALSGain.GAIN_64X # 1X, 4X, 16X, 64X, or 128X
|
|
133
|
+
tcs.integration_time = 100.0 # 2.78ms to 711ms
|
|
134
|
+
|
|
135
|
+
# Enable ALS interrupt so we can poll AINT for data ready
|
|
136
|
+
tcs.als_interrupt_enabled = True
|
|
137
|
+
tcs.interrupt_persistence = InterruptPersistence.EVERY
|
|
138
|
+
tcs.clear_als_interrupt()
|
|
139
|
+
|
|
140
|
+
while True:
|
|
141
|
+
# Wait for new data
|
|
142
|
+
if tcs.als_interrupt:
|
|
143
|
+
x, y, z, ir1 = tcs.channels
|
|
144
|
+
print(f"X: {x} Y: {y} Z: {z} IR1: {ir1}")
|
|
145
|
+
tcs.clear_als_interrupt()
|
|
146
|
+
|
|
147
|
+
time.sleep(1.0)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
Documentation
|
|
151
|
+
=============
|
|
152
|
+
API documentation for this library can be found on `Read the Docs <https://docs.circuitpython.org/projects/tcs3430/en/latest/>`_.
|
|
153
|
+
|
|
154
|
+
For information on building library documentation, please check out
|
|
155
|
+
`this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.
|
|
156
|
+
|
|
157
|
+
Contributing
|
|
158
|
+
============
|
|
159
|
+
|
|
160
|
+
Contributions are welcome! Please read our `Code of Conduct
|
|
161
|
+
<https://github.com/adafruit/Adafruit_CircuitPython_TCS3430/blob/HEAD/CODE_OF_CONDUCT.md>`_
|
|
162
|
+
before contributing to help this project stay welcoming.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
adafruit_tcs3430.py,sha256=wSjjIIEMNyB54zt8sZ3dcFWo8O-8Tar3iQs4W8ka2R0,17563
|
|
2
|
+
adafruit_circuitpython_tcs3430-1.0.0.dist-info/licenses/LICENSE,sha256=IrDmGxfX4xdm-jZka6acotFMss63SMR3pHWyFp7jA3o,1100
|
|
3
|
+
adafruit_circuitpython_tcs3430-1.0.0.dist-info/METADATA,sha256=cZ9BAd4apvIpVcUEIrn19I6vIO9kbtAbIa0j4OWbasE,5187
|
|
4
|
+
adafruit_circuitpython_tcs3430-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
5
|
+
adafruit_circuitpython_tcs3430-1.0.0.dist-info/top_level.txt,sha256=dSUdVgXVIT64zVqg98R2PUSuZe4isQOAyd4LCJbLLlk,17
|
|
6
|
+
adafruit_circuitpython_tcs3430-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tim Cocks for Adafruit Industries
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
adafruit_tcs3430
|
adafruit_tcs3430.py
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
"""
|
|
5
|
+
`adafruit_tcs3430`
|
|
6
|
+
================================================================================
|
|
7
|
+
|
|
8
|
+
CircuitPython driver library for AMS TCS3430 / TCS34303 XYZ tri-stimulus color sensor.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
* Author(s): Tim Cocks
|
|
12
|
+
|
|
13
|
+
Implementation Notes
|
|
14
|
+
--------------------
|
|
15
|
+
|
|
16
|
+
**Hardware:**
|
|
17
|
+
|
|
18
|
+
* `Adafruit TCS3430 / TCS34303 Ambient Tri-Stimulus Color Sensor <https://www.adafruit.com/product/6479>`_
|
|
19
|
+
|
|
20
|
+
**Software and Dependencies:**
|
|
21
|
+
|
|
22
|
+
* Adafruit CircuitPython firmware for the supported boards:
|
|
23
|
+
https://circuitpython.org/downloads
|
|
24
|
+
|
|
25
|
+
# * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
|
|
26
|
+
# * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
__version__ = "1.0.0"
|
|
30
|
+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_TCS3430.git"
|
|
31
|
+
|
|
32
|
+
# imports
|
|
33
|
+
import time
|
|
34
|
+
|
|
35
|
+
from adafruit_bus_device import i2c_device
|
|
36
|
+
from adafruit_register.i2c_bit import RWBit
|
|
37
|
+
from adafruit_register.i2c_bits import ROBits, RWBits
|
|
38
|
+
from adafruit_register.i2c_struct import UnaryStruct
|
|
39
|
+
from micropython import const
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
from typing import Tuple
|
|
43
|
+
|
|
44
|
+
import busio
|
|
45
|
+
except ImportError:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
# -----------------------------------------------------------------------
|
|
49
|
+
# I2C address
|
|
50
|
+
# -----------------------------------------------------------------------
|
|
51
|
+
_TCS3430_DEFAULT_ADDR = const(0x39)
|
|
52
|
+
|
|
53
|
+
# -----------------------------------------------------------------------
|
|
54
|
+
# Register addresses
|
|
55
|
+
# -----------------------------------------------------------------------
|
|
56
|
+
_TCS3430_REG_ENABLE = const(0x80) # Enable states and interrupts
|
|
57
|
+
_TCS3430_REG_ATIME = const(0x81) # ADC integration time
|
|
58
|
+
_TCS3430_REG_WTIME = const(0x83) # ALS wait time
|
|
59
|
+
_TCS3430_REG_AILTL = const(0x84) # ALS interrupt low threshold (16-bit LE)
|
|
60
|
+
_TCS3430_REG_AIHTL = const(0x86) # ALS interrupt high threshold (16-bit LE)
|
|
61
|
+
_TCS3430_REG_PERS = const(0x8C) # ALS interrupt persistence filters
|
|
62
|
+
_TCS3430_REG_CFG0 = const(0x8D) # Configuration register 0
|
|
63
|
+
_TCS3430_REG_CFG1 = const(0x90) # Configuration register 1
|
|
64
|
+
_TCS3430_REG_REVID = const(0x91) # Revision ID
|
|
65
|
+
_TCS3430_REG_ID = const(0x92) # Device ID
|
|
66
|
+
_TCS3430_REG_STATUS = const(0x93) # Device status
|
|
67
|
+
_TCS3430_REG_CH0DATAL = const(0x94) # Z channel data (16-bit LE)
|
|
68
|
+
_TCS3430_REG_CH1DATAL = const(0x96) # Y channel data (16-bit LE)
|
|
69
|
+
_TCS3430_REG_CH2DATAL = const(0x98) # IR1 channel data (16-bit LE)
|
|
70
|
+
_TCS3430_REG_CH3DATAL = const(0x9A) # X or IR2 channel data (16-bit LE)
|
|
71
|
+
_TCS3430_REG_CFG2 = const(0x9F) # Configuration register 2
|
|
72
|
+
_TCS3430_REG_CFG3 = const(0xAB) # Configuration register 3
|
|
73
|
+
_TCS3430_REG_AZ_CONFIG = const(0xD6) # Auto zero configuration
|
|
74
|
+
_TCS3430_REG_INTENAB = const(0xDD) # Interrupt enables
|
|
75
|
+
|
|
76
|
+
# Expected chip ID
|
|
77
|
+
_TCS3430_CHIP_ID = const(0xDC)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# -----------------------------------------------------------------------
|
|
81
|
+
# CV helper – same pattern as adafruit_apds9999
|
|
82
|
+
# -----------------------------------------------------------------------
|
|
83
|
+
class CV:
|
|
84
|
+
"""Constant-value helper for enum-like classes."""
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def is_valid(cls, value: int) -> bool:
|
|
88
|
+
"""Validate that *value* is a member of this CV class."""
|
|
89
|
+
IGNORE = [cls.__module__, cls.__name__]
|
|
90
|
+
return value in cls.__dict__.values() and value not in IGNORE
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def get_name(cls, value: int) -> str:
|
|
94
|
+
"""Return the attribute name for *value*."""
|
|
95
|
+
for k, v in cls.__dict__.items():
|
|
96
|
+
if v == value:
|
|
97
|
+
return k
|
|
98
|
+
raise ValueError(f"Unknown value {value}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# -----------------------------------------------------------------------
|
|
102
|
+
# Enum-like CV classes
|
|
103
|
+
# -----------------------------------------------------------------------
|
|
104
|
+
class ALSGain(CV):
|
|
105
|
+
"""ALS gain settings for CFG1 register bits 1:0.
|
|
106
|
+
|
|
107
|
+
+-------------------------------+----------+
|
|
108
|
+
| Setting | Gain |
|
|
109
|
+
+===============================+==========+
|
|
110
|
+
| :py:const:`ALSGain.GAIN_1X` | 1x gain |
|
|
111
|
+
+-------------------------------+----------+
|
|
112
|
+
| :py:const:`ALSGain.GAIN_4X` | 4x gain |
|
|
113
|
+
+-------------------------------+----------+
|
|
114
|
+
| :py:const:`ALSGain.GAIN_16X` | 16x gain |
|
|
115
|
+
+-------------------------------+----------+
|
|
116
|
+
| :py:const:`ALSGain.GAIN_64X` | 64x gain |
|
|
117
|
+
+-------------------------------+----------+
|
|
118
|
+
| :py:const:`ALSGain.GAIN_128X` | 128x gain|
|
|
119
|
+
+-------------------------------+----------+
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
GAIN_1X = 0x00
|
|
123
|
+
GAIN_4X = 0x01
|
|
124
|
+
GAIN_16X = 0x02
|
|
125
|
+
GAIN_64X = 0x03
|
|
126
|
+
GAIN_128X = 0x04 # Requires HGAIN bit in CFG2
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class InterruptPersistence(CV):
|
|
130
|
+
"""ALS interrupt persistence filter values for PERS register bits 3:0.
|
|
131
|
+
|
|
132
|
+
+----------------------------------------------+------------------------------------+
|
|
133
|
+
| Setting | Description |
|
|
134
|
+
+==============================================+====================================+
|
|
135
|
+
| :py:const:`InterruptPersistence.EVERY` | Every ALS cycle |
|
|
136
|
+
+----------------------------------------------+------------------------------------+
|
|
137
|
+
| :py:const:`InterruptPersistence.CYCLES_1` | 1 consecutive value out of range |
|
|
138
|
+
+----------------------------------------------+------------------------------------+
|
|
139
|
+
| :py:const:`InterruptPersistence.CYCLES_2` | 2 consecutive values out of range |
|
|
140
|
+
+----------------------------------------------+------------------------------------+
|
|
141
|
+
| :py:const:`InterruptPersistence.CYCLES_3` | 3 consecutive values out of range |
|
|
142
|
+
+----------------------------------------------+------------------------------------+
|
|
143
|
+
| :py:const:`InterruptPersistence.CYCLES_5` | 5 consecutive values out of range |
|
|
144
|
+
+----------------------------------------------+------------------------------------+
|
|
145
|
+
| :py:const:`InterruptPersistence.CYCLES_10` | 10 consecutive values out of range |
|
|
146
|
+
+----------------------------------------------+------------------------------------+
|
|
147
|
+
| :py:const:`InterruptPersistence.CYCLES_15` | 15 consecutive values out of range |
|
|
148
|
+
+----------------------------------------------+------------------------------------+
|
|
149
|
+
| :py:const:`InterruptPersistence.CYCLES_20` | 20 consecutive values out of range |
|
|
150
|
+
+----------------------------------------------+------------------------------------+
|
|
151
|
+
| :py:const:`InterruptPersistence.CYCLES_25` | 25 consecutive values out of range |
|
|
152
|
+
+----------------------------------------------+------------------------------------+
|
|
153
|
+
| :py:const:`InterruptPersistence.CYCLES_30` | 30 consecutive values out of range |
|
|
154
|
+
+----------------------------------------------+------------------------------------+
|
|
155
|
+
| :py:const:`InterruptPersistence.CYCLES_35` | 35 consecutive values out of range |
|
|
156
|
+
+----------------------------------------------+------------------------------------+
|
|
157
|
+
| :py:const:`InterruptPersistence.CYCLES_40` | 40 consecutive values out of range |
|
|
158
|
+
+----------------------------------------------+------------------------------------+
|
|
159
|
+
| :py:const:`InterruptPersistence.CYCLES_45` | 45 consecutive values out of range |
|
|
160
|
+
+----------------------------------------------+------------------------------------+
|
|
161
|
+
| :py:const:`InterruptPersistence.CYCLES_50` | 50 consecutive values out of range |
|
|
162
|
+
+----------------------------------------------+------------------------------------+
|
|
163
|
+
| :py:const:`InterruptPersistence.CYCLES_55` | 55 consecutive values out of range |
|
|
164
|
+
+----------------------------------------------+------------------------------------+
|
|
165
|
+
| :py:const:`InterruptPersistence.CYCLES_60` | 60 consecutive values out of range |
|
|
166
|
+
+----------------------------------------------+------------------------------------+
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
EVERY = 0x00
|
|
170
|
+
CYCLES_1 = 0x01
|
|
171
|
+
CYCLES_2 = 0x02
|
|
172
|
+
CYCLES_3 = 0x03
|
|
173
|
+
CYCLES_5 = 0x04
|
|
174
|
+
CYCLES_10 = 0x05
|
|
175
|
+
CYCLES_15 = 0x06
|
|
176
|
+
CYCLES_20 = 0x07
|
|
177
|
+
CYCLES_25 = 0x08
|
|
178
|
+
CYCLES_30 = 0x09
|
|
179
|
+
CYCLES_35 = 0x0A
|
|
180
|
+
CYCLES_40 = 0x0B
|
|
181
|
+
CYCLES_45 = 0x0C
|
|
182
|
+
CYCLES_50 = 0x0D
|
|
183
|
+
CYCLES_55 = 0x0E
|
|
184
|
+
CYCLES_60 = 0x0F
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# -----------------------------------------------------------------------
|
|
188
|
+
# Driver class
|
|
189
|
+
# -----------------------------------------------------------------------
|
|
190
|
+
class TCS3430:
|
|
191
|
+
"""CircuitPython driver for the AMS TCS3430 XYZ Color and ALS Sensor.
|
|
192
|
+
|
|
193
|
+
:param ~busio.I2C i2c_bus: The I2C bus the device is connected to.
|
|
194
|
+
:param int address: The I2C device address. Defaults to :const:`0x39`.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
# -- ENABLE register (0x80) bits --
|
|
198
|
+
power_on = RWBit(_TCS3430_REG_ENABLE, 0) # PON
|
|
199
|
+
"""Power on/off the sensor. True for on, False for off."""
|
|
200
|
+
|
|
201
|
+
als_enabled = RWBit(_TCS3430_REG_ENABLE, 1) # AEN
|
|
202
|
+
"""Enable/disable ALS functionality"""
|
|
203
|
+
|
|
204
|
+
wait_enabled = RWBit(_TCS3430_REG_ENABLE, 3) # WEN
|
|
205
|
+
"""Enable/disable wait functionality"""
|
|
206
|
+
|
|
207
|
+
# -- ATIME register (0x81) – full byte --
|
|
208
|
+
integration_cycles = UnaryStruct(_TCS3430_REG_ATIME, "B")
|
|
209
|
+
"""The number of integration cycles (1-256)"""
|
|
210
|
+
|
|
211
|
+
# -- WTIME register (0x83) – full byte --
|
|
212
|
+
wait_cycles = UnaryStruct(_TCS3430_REG_WTIME, "B")
|
|
213
|
+
"""The number of wait cycles (1-256)"""
|
|
214
|
+
|
|
215
|
+
# -- ALS interrupt thresholds (16-bit little-endian) --
|
|
216
|
+
als_threshold_low = UnaryStruct(_TCS3430_REG_AILTL, "<H")
|
|
217
|
+
"""The low threshold value for ALS"""
|
|
218
|
+
|
|
219
|
+
als_threshold_high = UnaryStruct(_TCS3430_REG_AIHTL, "<H")
|
|
220
|
+
"""The high threshold value for ALS"""
|
|
221
|
+
|
|
222
|
+
# -- PERS register (0x8C), bits 3:0 --
|
|
223
|
+
interrupt_persistence = RWBits(4, _TCS3430_REG_PERS, 0)
|
|
224
|
+
"""Enable/disable The interrupt persistence functionality"""
|
|
225
|
+
|
|
226
|
+
# -- CFG0 register (0x8D) --
|
|
227
|
+
wait_long = RWBit(_TCS3430_REG_CFG0, 2) # WLONG
|
|
228
|
+
"""Enable/disable longer wait functionality. True to enable 12x time multiplier"""
|
|
229
|
+
|
|
230
|
+
# -- CFG1 register (0x90) --
|
|
231
|
+
_als_gain = RWBits(2, _TCS3430_REG_CFG1, 0) # AGAIN bits 1:0
|
|
232
|
+
als_mux_ir2 = RWBit(_TCS3430_REG_CFG1, 3) # AMUX
|
|
233
|
+
"""ALS MUX setting for IR2 or X channel. True for IR2, False for X."""
|
|
234
|
+
|
|
235
|
+
# -- REVID register (0x91) – read-only --
|
|
236
|
+
rev_id = ROBits(8, _TCS3430_REG_REVID, 0)
|
|
237
|
+
"""Revision ID"""
|
|
238
|
+
|
|
239
|
+
# -- ID register (0x92) – read-only --
|
|
240
|
+
chip_id = ROBits(8, _TCS3430_REG_ID, 0)
|
|
241
|
+
"""Chip ID"""
|
|
242
|
+
|
|
243
|
+
# -- STATUS register (0x93) --
|
|
244
|
+
_status = UnaryStruct(_TCS3430_REG_STATUS, "B")
|
|
245
|
+
_als_interrupt_status = ROBits(1, _TCS3430_REG_STATUS, 4) # AINT
|
|
246
|
+
_als_saturated_status = ROBits(1, _TCS3430_REG_STATUS, 7) # ASAT
|
|
247
|
+
|
|
248
|
+
# -- Individual Channel data (16-bit little-endian) --
|
|
249
|
+
_channel_x_or_ir2 = UnaryStruct(_TCS3430_REG_CH3DATAL, "<H") # CH3 = X or IR2
|
|
250
|
+
|
|
251
|
+
# -- All 4 channels as a single 8-byte burst read (Z, Y, IR1, X/IR2) --
|
|
252
|
+
_channel_data_raw = ROBits(64, _TCS3430_REG_CH0DATAL, 0, register_width=8)
|
|
253
|
+
|
|
254
|
+
# -- CFG2 register (0x9F) --
|
|
255
|
+
_hgain = RWBit(_TCS3430_REG_CFG2, 4) # HGAIN
|
|
256
|
+
|
|
257
|
+
# -- CFG3 register (0xAB) --
|
|
258
|
+
interrupt_clear_on_read = RWBit(_TCS3430_REG_CFG3, 7) # INT_READ_CLEAR
|
|
259
|
+
"""Enable/disable interrupt clear on reading"""
|
|
260
|
+
|
|
261
|
+
sleep_after_interrupt = RWBit(_TCS3430_REG_CFG3, 4) # SAI
|
|
262
|
+
"""Enable/disable sleep after interrupt"""
|
|
263
|
+
|
|
264
|
+
# -- AZ_CONFIG register (0xD6) --
|
|
265
|
+
auto_zero_mode = RWBit(_TCS3430_REG_AZ_CONFIG, 7) # AZ_MODE
|
|
266
|
+
"""Enable/disable auto-zero mode"""
|
|
267
|
+
|
|
268
|
+
auto_zero_nth = RWBits(7, _TCS3430_REG_AZ_CONFIG, 0) # AZ_NTH_ITERATION
|
|
269
|
+
"""Auto-zero interval. Run auto-zero every N measurements"""
|
|
270
|
+
|
|
271
|
+
# -- INTENAB register (0xDD) --
|
|
272
|
+
saturation_interrupt_enabled = RWBit(_TCS3430_REG_INTENAB, 7) # ASIEN
|
|
273
|
+
"""Enable/disable saturation interrupt"""
|
|
274
|
+
|
|
275
|
+
als_interrupt_enabled = RWBit(_TCS3430_REG_INTENAB, 4) # AIEN
|
|
276
|
+
"""Enable/disable als interrupt"""
|
|
277
|
+
|
|
278
|
+
def __init__(self, i2c_bus: "busio.I2C", address: int = _TCS3430_DEFAULT_ADDR) -> None:
|
|
279
|
+
self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
|
|
280
|
+
|
|
281
|
+
# Verify chip ID
|
|
282
|
+
chip_id = self.chip_id
|
|
283
|
+
if chip_id != _TCS3430_CHIP_ID:
|
|
284
|
+
raise RuntimeError(
|
|
285
|
+
"Failed to find TCS3430 – check your wiring! "
|
|
286
|
+
+ f"Expected ID 0x{_TCS3430_CHIP_ID:02X}, "
|
|
287
|
+
+ f"got 0x{chip_id:02X}."
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# Power on and enable ALS (matches Arduino begin())
|
|
291
|
+
self.power_on = True
|
|
292
|
+
self.als_enabled = True
|
|
293
|
+
|
|
294
|
+
# -----------------------------------------------------------------
|
|
295
|
+
# Integration time (convenience conversions around integration_cycles)
|
|
296
|
+
# -----------------------------------------------------------------
|
|
297
|
+
@property
|
|
298
|
+
def integration_time(self) -> float:
|
|
299
|
+
"""Integration time in milliseconds.
|
|
300
|
+
|
|
301
|
+
Computed from :attr:`integration_cycles` as ``(cycles + 1) * 2.78``.
|
|
302
|
+
Setting this property writes the closest cycle count back to the
|
|
303
|
+
ATIME register.
|
|
304
|
+
"""
|
|
305
|
+
return (self.integration_cycles + 1) * 2.78
|
|
306
|
+
|
|
307
|
+
@integration_time.setter
|
|
308
|
+
def integration_time(self, ms: float) -> None:
|
|
309
|
+
self.integration_cycles = int(ms / 2.78 - 1)
|
|
310
|
+
|
|
311
|
+
# -----------------------------------------------------------------
|
|
312
|
+
# Wait time (convenience conversions around wait_cycles)
|
|
313
|
+
# -----------------------------------------------------------------
|
|
314
|
+
@property
|
|
315
|
+
def wait_time(self) -> float:
|
|
316
|
+
"""Wait time in milliseconds.
|
|
317
|
+
|
|
318
|
+
Computed from :attr:`wait_cycles` as ``(cycles + 1) * 2.78``.
|
|
319
|
+
When :attr:`wait_long` is enabled the actual wait is multiplied by 12.
|
|
320
|
+
Setting this property writes the closest cycle count back to the
|
|
321
|
+
WTIME register (it does **not** account for :attr:`wait_long`).
|
|
322
|
+
"""
|
|
323
|
+
return (self.wait_cycles + 1) * 2.78
|
|
324
|
+
|
|
325
|
+
@wait_time.setter
|
|
326
|
+
def wait_time(self, ms: float) -> None:
|
|
327
|
+
self.wait_cycles = int(ms / 2.78 - 1)
|
|
328
|
+
|
|
329
|
+
# -----------------------------------------------------------------
|
|
330
|
+
# ALS gain (spans CFG1 AGAIN bits and CFG2 HGAIN bit)
|
|
331
|
+
# -----------------------------------------------------------------
|
|
332
|
+
@property
|
|
333
|
+
def als_gain(self) -> int:
|
|
334
|
+
"""ALS analogue gain.
|
|
335
|
+
|
|
336
|
+
Must be an :class:`ALSGain` value. ``ALSGain.GAIN_128X`` is
|
|
337
|
+
achieved by setting the hardware gain to 64x **and** asserting the
|
|
338
|
+
HGAIN bit in CFG2.
|
|
339
|
+
|
|
340
|
+
* ``ALSGain.GAIN_1X``
|
|
341
|
+
* ``ALSGain.GAIN_4X``
|
|
342
|
+
* ``ALSGain.GAIN_16X``
|
|
343
|
+
* ``ALSGain.GAIN_64X``
|
|
344
|
+
* ``ALSGain.GAIN_128X``
|
|
345
|
+
"""
|
|
346
|
+
if self._als_gain == ALSGain.GAIN_64X and self._hgain:
|
|
347
|
+
return ALSGain.GAIN_128X
|
|
348
|
+
return self._als_gain
|
|
349
|
+
|
|
350
|
+
@als_gain.setter
|
|
351
|
+
def als_gain(self, value: int) -> None:
|
|
352
|
+
if not ALSGain.is_valid(value):
|
|
353
|
+
raise ValueError("als_gain must be an ALSGain value")
|
|
354
|
+
if value == ALSGain.GAIN_128X:
|
|
355
|
+
self._als_gain = ALSGain.GAIN_64X
|
|
356
|
+
self._hgain = True
|
|
357
|
+
else:
|
|
358
|
+
self._als_gain = value
|
|
359
|
+
self._hgain = False
|
|
360
|
+
|
|
361
|
+
# -----------------------------------------------------------------
|
|
362
|
+
# Status helpers
|
|
363
|
+
# -----------------------------------------------------------------
|
|
364
|
+
@property
|
|
365
|
+
def als_saturated(self) -> bool:
|
|
366
|
+
"""``True`` if the ALS data is saturated (read-only).
|
|
367
|
+
|
|
368
|
+
Use :meth:`clear_als_saturated` to clear the flag.
|
|
369
|
+
"""
|
|
370
|
+
return bool(self._als_saturated_status)
|
|
371
|
+
|
|
372
|
+
def clear_als_saturated(self) -> None:
|
|
373
|
+
"""Clear the ALS saturation flag by writing 0x80 to the STATUS register."""
|
|
374
|
+
self._status = 0x80
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def als_interrupt(self) -> bool:
|
|
378
|
+
"""``True`` if the ALS interrupt flag is set (read-only).
|
|
379
|
+
|
|
380
|
+
Use :meth:`clear_als_interrupt` to clear the flag.
|
|
381
|
+
"""
|
|
382
|
+
return bool(self._als_interrupt_status)
|
|
383
|
+
|
|
384
|
+
def clear_als_interrupt(self) -> None:
|
|
385
|
+
"""Clear the ALS interrupt (and all other status flags) by writing
|
|
386
|
+
0xFF to the STATUS register.
|
|
387
|
+
|
|
388
|
+
.. note::
|
|
389
|
+
If the threshold condition still exists and ALS is running,
|
|
390
|
+
the interrupt will re-fire on the next integration cycle.
|
|
391
|
+
"""
|
|
392
|
+
self._status = 0xFF
|
|
393
|
+
|
|
394
|
+
# -----------------------------------------------------------------
|
|
395
|
+
# Channel reads
|
|
396
|
+
# -----------------------------------------------------------------
|
|
397
|
+
@property
|
|
398
|
+
def channels(self) -> Tuple[int, int, int, int]:
|
|
399
|
+
"""Read the X, Y, Z, and IR1 channels in a single burst.
|
|
400
|
+
|
|
401
|
+
If the ALS MUX is currently set to IR2 mode, it is temporarily
|
|
402
|
+
switched back to X mode for the read and then restored.
|
|
403
|
+
|
|
404
|
+
Returns a tuple ``(x, y, z, ir1)`` of 16-bit unsigned values.
|
|
405
|
+
"""
|
|
406
|
+
was_ir2 = self.als_mux_ir2
|
|
407
|
+
if was_ir2:
|
|
408
|
+
self.als_mux_ir2 = False
|
|
409
|
+
|
|
410
|
+
raw = self._channel_data_raw
|
|
411
|
+
z = raw & 0xFFFF
|
|
412
|
+
y = (raw >> 16) & 0xFFFF
|
|
413
|
+
ir1 = (raw >> 32) & 0xFFFF
|
|
414
|
+
x = (raw >> 48) & 0xFFFF
|
|
415
|
+
|
|
416
|
+
if was_ir2:
|
|
417
|
+
self.als_mux_ir2 = True
|
|
418
|
+
|
|
419
|
+
return (x, y, z, ir1)
|
|
420
|
+
|
|
421
|
+
@property
|
|
422
|
+
def ir2(self) -> int:
|
|
423
|
+
"""Read the IR2 channel value.
|
|
424
|
+
|
|
425
|
+
This temporarily switches the ALS MUX to IR2, waits one integration
|
|
426
|
+
period for fresh data, reads CH3, and restores the previous MUX
|
|
427
|
+
setting.
|
|
428
|
+
"""
|
|
429
|
+
was_ir2 = self.als_mux_ir2
|
|
430
|
+
if not was_ir2:
|
|
431
|
+
self.als_mux_ir2 = True
|
|
432
|
+
|
|
433
|
+
# Wait for one full integration cycle so data is fresh
|
|
434
|
+
time.sleep(self.integration_time / 1000.0)
|
|
435
|
+
|
|
436
|
+
value = self._channel_x_or_ir2
|
|
437
|
+
|
|
438
|
+
if not was_ir2:
|
|
439
|
+
self.als_mux_ir2 = False
|
|
440
|
+
|
|
441
|
+
return value
|