-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgpio_expander.py
165 lines (115 loc) · 5.29 KB
/
gpio_expander.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2022 Gabriele Pongelli
#
# SPDX-License-Identifier: MIT
"""
`gpio_expander`.
================================================================================
CircuitPython helper library for gpio expanders (Texas Instrument PCA95xx and TCA95xx chips).
* Author(s): Gabriele Pongelli
Implementation Notes
--------------------
**Hardware:**
* `Texas Instrument PCA9534 <https://www.ti.com/lit/ds/symlink/pca9534.pdf>`_
* `Texas Instrument PCA9535 <https://www.ti.com/lit/ds/symlink/pca9535.pdf>`_
* `Texas Instrument PCA9555 <https://www.ti.com/lit/ds/symlink/pca9555.pdf>`_
* `Texas Instrument TCA9534 <https://www.ti.com/lit/ds/symlink/tca9534.pdf>`_
* `Texas Instrument TCA9535 <https://www.ti.com/lit/ds/symlink/tca9535.pdf>`_
* `Texas Instrument TCA9555 <https://www.ti.com/lit/ds/symlink/tca9555.pdf>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://circuitpython.org/downloads
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
"""
# imports
try:
from busio import I2C
except ImportError:
pass
__version__ = "0.3.2"
__repo__ = "https://github.com/gpongelli/CircuitPython_gpio_expander.git"
import adafruit_bus_device.i2c_device as i2cdevice
from adafruit_register.i2c_bit import ROBit, RWBit
from adafruit_register.i2c_bits import ROBits, RWBits
from micropython import const
# For the PCA 953X and 955X series, the chips with 8 GPIO's have these port numbers
# The chips with 16 GPIO's have the first port for each type at double these numbers
# IE The first config port is 6
_INPUT_PORT = const(0)
_OUTPUT_PORT = const(1)
_POLARITY_REGISTER = const(2)
_CONFIG_REGISTER = const(3)
def _get_registry_params(value, x):
_name = ""
_reg_address_multiplier = 1
_idx = x % 8
_adder = 0
if x > 7:
_adder = 1
if value > 8:
_reg_address_multiplier = 2
# datasheet bit field's name has underscore in place of dot for 16 bit expander
if x >= 8:
_name = "1_"
else:
_name = "0_"
return _name, _reg_address_multiplier, _adder, _idx
class _MetaGPIOExpander(type):
def __new__(mcs, clsname, bases, dct, *args, **kwargs): # pylint: disable=unused-argument,too-many-locals
_result_dct = {}
for key, value in dct.items():
# variable has full qualified name
_result_dct[key] = value
if key == '_NUM_GPIO':
# call to get only interesting data
_, _width, _, _ = _get_registry_params(value, 1)
# entire registries
_result_dct['input_ports'] = ROBits(8 * _width, _INPUT_PORT * _width, 0, register_width=_width)
_result_dct['output_ports'] = RWBits(8 * _width, _OUTPUT_PORT * _width, 0, register_width=_width)
_result_dct['polarity_inversions'] = RWBits(
8 * _width, _POLARITY_REGISTER * _width, 0, register_width=_width
)
_result_dct['configuration_ports'] = RWBits(
8 * _width, _CONFIG_REGISTER * _width, 0, register_width=_width
)
# create single bit registries
for x in range(value):
_name, _reg_address_multiplier, _adder, _idx = _get_registry_params(value, x)
# REGISTRY 0 and 1 INPUT PORT
_result_dct[f"I{_name}{_idx}"] = ROBit(_INPUT_PORT * _reg_address_multiplier + _adder, _idx)
# REGISTRY 2 and 3 OUTPUT PORT
_result_dct[f"O{_name}{_idx}"] = RWBit(_OUTPUT_PORT * _reg_address_multiplier + _adder, _idx)
# REGISTRY 4 and 5 POLARITY INVERSION REGISTER
_result_dct[f"N{_name}{_idx}"] = RWBit(_POLARITY_REGISTER * _reg_address_multiplier + _adder, _idx)
# REGISTRY 6 and 7 CONFIGURATION REGISTER
_result_dct[f"C{_name}{_idx}"] = RWBit(_CONFIG_REGISTER * _reg_address_multiplier + _adder, _idx)
return super(_MetaGPIOExpander, mcs).__new__(mcs, clsname, bases, _result_dct)
class _BaseGPIOExpander(metaclass=_MetaGPIOExpander):
def __init__(self, i2c_bus: I2C, address: int, **kwargs) -> None: # pylint: disable=unused-argument
self.i2c_device = i2cdevice.I2CDevice(i2c_bus, address)
def max_gpios(self) -> int:
"""Return subclass' gpio number.
:return int value from subclass's attribute.
"""
return getattr(self, '_NUM_GPIO')
# PCA series
class PCA9534(_BaseGPIOExpander):
"""PCA9534 8-Bit I2C I/O Expander."""
_NUM_GPIO = 8
class PCA9535(_BaseGPIOExpander):
"""PCA9535 16-Bit I2C I/O Expander."""
_NUM_GPIO = 16
class PCA9555(_BaseGPIOExpander):
"""PCA9555 16-Bit I2C I/O Expander."""
_NUM_GPIO = 16
# TCA series
class TCA9534(_BaseGPIOExpander):
"""TCA9534 Low-Voltage 8-Bit I2C I/O Expander."""
_NUM_GPIO = 8
class TCA9535(_BaseGPIOExpander):
"""TCA9535 Low-Voltage 16-Bit I2C I/O Expander."""
_NUM_GPIO = 16
class TCA9555(_BaseGPIOExpander):
"""TCA9555 Low-Voltage 16-Bit I2C I/O Expander."""
_NUM_GPIO = 16