44#
55# SPDX-License-Identifier: MIT
66
7- # pylint: disable=too-many-public-methods
7+ # pylint: disable=too-many-public-methods, duplicate-code
8+ # Note: there is a bit of duplicated code between this and the PCAL9555. This code is duplicated
9+ # for these two expanders, but may not be if other expanders are added to this library. I
10+ # therefore want to keep is separate in these two classes. The line above disables the
11+ # pylint check for this.
812
9- # TODO: mostly a copy/paste from the PCAL9555, make sure this stuff is still true here.
1013"""
1114`PCAL9554`
1215====================================================
@@ -77,16 +80,191 @@ def __init__(self, i2c, address=_PCAL9554_ADDRESS, reset=True):
7780 super ().__init__ (
7881 i2c , address , False
7982 ) # This initializes the PCA9554 compatible registers.
80- self ._capability = (
83+ self .capability = (
8184 _enable_bit (0x00 , Capability .PULL_UP )
8285 | _enable_bit (0x00 , Capability .PULL_DOWN )
8386 | _enable_bit (0x00 , Capability .INVERT_POL )
84- | _enable_bit (0x00 , Capability .DRIVE_MODE )
8587 ) # TODO: This device does not really have a capability to set drive mode the way
8688 # digitalio is expecting. I should probably not set this here.
8789 if reset :
8890 self .reset_to_defaults ()
8991
92+ def set_int_pin (self , pin , latch = False ):
93+ """Enable interrupt on a pin. Interrupts are generally triggered by any state change
94+ of the pin. There is an exception to this, see info below on latching for details.
95+
96+ :param pin: Pin number to modify.
97+ :param latch: Set to True to enable latching on this interrupt. Defaults to False.
98+ :return: Nothing.
99+ """
100+ # Validate inputs
101+ self ._validate_pin (pin )
102+ if not isinstance (latch , (bool )):
103+ raise ValueError ("latch must be True or False" )
104+
105+ self .irq_mask = _clear_bit (self .irq_mask , pin )
106+
107+ if latch :
108+ self .input_latch = _enable_bit (self .input_latch , pin )
109+ else :
110+ self .input_latch = _clear_bit (self .input_latch , pin )
111+
112+ def clear_int_pin (self , pin ):
113+ """Disable interrupts on a pin.
114+
115+ :param pin: Pin number to modify.
116+ :return: Nothing.
117+ """
118+ self ._validate_pin (pin )
119+ self .irq_mask = _enable_bit (self .irq_mask , pin )
120+
121+ def get_int_pins (self ):
122+ """Returns a list of pins causing an interrupt. It is possible for multiple pins
123+ to be causing an interrupt. Calling this function will not clear the interrupt state.
124+
125+ :return: Returns a list of pin numbers.
126+ """
127+ output = []
128+ reg = self .irq_status
129+ for i in range (self .maxpins ):
130+ if ((reg >> i ) & 1 ) == 1 :
131+ output .append (i )
132+ return output
133+
134+ def set_int_latch (self , pin ):
135+ """Set the interrupt on 'pin' to latching operation. Note this does not enable
136+ or disable the interrupt or clear the interrupt state.
137+
138+ :param pin: Pin number to modify.
139+ :return: Nothing.
140+ """
141+ self ._validate_pin (pin )
142+ self .input_latch = _enable_bit (self .input_latch , pin )
143+
144+ def clear_int_latch (self , pin ):
145+ """Set the interrupt on 'pin' to non-latching operation. Note this does not enable
146+ or disable the interrupt. This does not clear the interrupt state.
147+
148+ :param pin: Pin number to modify.
149+ :return: Nothing.
150+ """
151+ self ._validate_pin (pin )
152+ self .input_latch = _clear_bit (self .input_latch , pin )
153+
154+ """Interrupt latch behavior
155+ By default (non-latched) if an interrupt enabled pin changes state, but changes back before the GPIO state register is read, the interrupt state
156+ will be cleared. Setting the interrupt latch will cause the device to latch on a state change of the input pin. With latching enabled, on a state
157+ change to the pin, the interrupt pin will be asserted and will not deassert until the input register is read. The value read from the input register
158+ will be the value that caused the interrupt, not nessecarially the current value of the pin. If the pin changed state, but changed back before the
159+ input register was read, the changed state will be what is returned in the register. The state change back to the original state will not trigger
160+ another interrupt as long as it happens before the input register is read. If the input register is read before the pin state changes back to the
161+ original value, both state changes will cause an interrupt.
162+ """
163+
164+ def get_pupd (self , pin ):
165+ """Checks the state of a pin to see if pull up/down is enabled.
166+
167+ :param pin: Pin number to check.
168+ :return: Returns 'digitalio.Pull.UP', 'digitalio.Pull.DOWN' or 'None'
169+ to indicate the state of the pin.
170+ """
171+ self ._validate_pin (pin )
172+ # The else statements here are extaneous, but without them, it is harder to tell
173+ # what the code is doing. Disable pylint for that error here only.
174+ if _get_bit (self .pupd_en , pin ):
175+ if _get_bit (self .pupd_sel , pin ): # pylint: disable=no-else-return
176+ return digitalio .Pull .UP
177+ else :
178+ return digitalio .Pull .DOWN
179+ else :
180+ return None
181+
182+ def set_pupd (self , pin , status ):
183+ """Sets the state of the pull up/down resistors on a pin.
184+
185+ :param pin: Pin number to modify.
186+ :param status: The new state of the pull up/down resistors. Should be one of
187+ 'digitalio.Pull.UP', 'digitalio.Pull.DOWN' or 'None'.
188+ :return: Nothing.
189+ """
190+ self ._validate_pin (pin )
191+
192+ if status is None :
193+ self .pupd_en = _clear_bit (self .pupd_en , pin )
194+ return
195+
196+ self .pupd_en = _enable_bit (self .pupd_en , pin )
197+
198+ if status == digitalio .Pull .UP :
199+ self .pupd_sel = _enable_bit (self .pupd_sel , pin )
200+ elif status == digitalio .Pull .DOWN :
201+ self .pupd_sel = _clear_bit (self .pupd_sel , pin )
202+ else :
203+ raise ValueError ("Expected UP, DOWN, or None for pull state." )
204+
205+ def set_output_drive (self , pin , drive ):
206+ """Sets the output drive strength of a pin.
207+
208+ :param pin: Pin number to modify.
209+ :param drive: The drive strength value to set. See the class 'Drive_strength'
210+ for valid values to set.
211+ :return: Nothing.
212+ """
213+ self ._validate_pin (pin )
214+ # Check inputs to make sure they are valid
215+ if (drive > 3 ) or (drive < 0 ):
216+ raise ValueError ("Invalid drive strength value." )
217+
218+ loc = pin * 2 # Bit location in the register
219+ val = drive << loc # Value to set shifted to the proper location
220+ mask = ~ (3 << loc ) & 0xFFFF # Mask to clear the two bits we need to set.
221+
222+ self .out_drive = ((self .out_drive ) & (mask )) | val
223+
224+ def get_output_drive (self , pin ):
225+ """Reads the drive strength value of the given pin.
226+
227+ :param pin: Pin number to check.
228+ :return: The current drive strength. Return values are shown in the
229+ 'Drive_strength' class
230+ """
231+ self ._validate_pin (pin )
232+
233+ val = self .out_drive
234+ loc = pin * 2 # Bit location in the register
235+ return (val >> loc ) & 0x03
236+
237+ def set_drive_mode (self , mode ):
238+ """Configures the output drive of the entire output bank. Sets the outputs to either
239+ open drain or push-pull. Note that this is not a per-pin setting. All pins are set to the
240+ same mode.
241+
242+ :param mode: The mode to set. Should be one of either 'digitalio.DriveMode.PUSH_PULL'
243+ or 'digitalio.DriveMode.OPEN_DRAIN'.
244+
245+ :return: Nothing.
246+ """
247+
248+ if mode == digitalio .DriveMode .PUSH_PULL :
249+ self .out_port_config = _clear_bit (self .out_port_config , 0 )
250+ elif mode == digitalio .DriveMode .OPEN_DRAIN :
251+ self .out_port_config = _enable_bit (self .out_port_config , 0 )
252+ else :
253+ raise ValueError (
254+ "Invalid drive mode. It should be either 'digitalio.DriveMode.PUSH_PULL' "
255+ "or 'digitalio.DriveMode.OPEN_DRAIN'."
256+ )
257+
258+ def get_drive_mode (self ):
259+ """Returns the drive mode of the output bank. This is the drive mode of all pins.
260+
261+ :return: The drive mode. Either 'digitalio.DriveMode.PUSH_PULL'
262+ or 'digitalio.DriveMode.OPEN_DRAIN'.
263+ """
264+ if _get_bit (self .out_port_config , 0 ) == 0x01 :
265+ return digitalio .DriveMode .OPEN_DRAIN
266+ return digitalio .DriveMode .PUSH_PULL
267+
90268 def reset_to_defaults (self ):
91269 """Reset all registers to their default state. This is also
92270 done with a power cycle, but it can be called by software here.
@@ -97,16 +275,38 @@ def reset_to_defaults(self):
97275 # memory addresses and default states?
98276 # Input port and interrupt status registers are read only.
99277 self .gpio = 0xFF
100- self .ipol = 0x0000
278+ self .ipol = 0x00
101279 self .iodir = 0xFF
102280
103- # self.out0_drive = 0xFFFF
104- # self.out1_drive = 0xFFFF
105- # self.input_latch = 0x0000
106- # self.pupd_en = 0xFFFF
107- # self.pupd_sel = 0xFFFF
108- # self.irq_mask = 0xFFFF
109- # self.out_port_config = 0x00
281+ self .out_drive = 0xFFFF
282+ self .input_latch = 0x00
283+ self .pupd_en = 0x00 # TODO: 0xFF for PCAL9554, 0x00 for PCAL9538
284+ self .pupd_sel = 0xFF
285+ self .irq_mask = 0xFF
286+ self .out_port_config = 0x00
287+
288+ """ Low level register access. These functions directly set or read the values of the
289+ registers on the device. In general, you should not need to call these
290+ functions directly.
291+ """
292+
293+ @property
294+ def out_drive (self ):
295+ """Output drive strength of pins 0-7."""
296+ return self ._read_u16le (_PCAL9554_OUTPUT_DRIVE_1 )
297+
298+ @out_drive .setter
299+ def out_drive (self , val ):
300+ self ._write_u16le (_PCAL9554_OUTPUT_DRIVE_1 , val )
301+
302+ @property
303+ def input_latch (self ):
304+ """Sets latching or non-latching interrupts per pin."""
305+ return self ._read_u8 (_PCAL9554_INPUT_LATCH )
306+
307+ @input_latch .setter
308+ def input_latch (self , val ):
309+ self ._write_u8 (_PCAL9554_INPUT_LATCH , val )
110310
111311 @property
112312 def pupd_en (self ):
@@ -126,21 +326,30 @@ def pupd_sel(self):
126326 def pupd_sel (self , val ):
127327 self ._write_u8 (_PCAL9554_PUPD_SEL , val )
128328
129- # Enable interrupt on a pin. Interrupts are triggered by any state change of the pin.
130- def set_int_pin (self , pin ):
131- """Set interrupt pin"""
132- self ._write_u8 (
133- _PCAL9554_IRQ_MASK , _clear_bit (self ._read_u8 (_PCAL9554_IRQ_MASK ), pin )
134- )
329+ @property
330+ def irq_mask (self ):
331+ """Masks or unmasks pins for generating interrupts."""
332+ return self ._read_u8 (_PCAL9554_IRQ_MASK )
135333
136- # Disable interrupts on a pin.
137- def clear_int_pin (self , pin ):
138- """Clear interrupt pin"""
139- self ._write_u8 (
140- _PCAL9554_IRQ_MASK , _enable_bit (self ._read_u8 (_PCAL9554_IRQ_MASK ), pin )
141- )
334+ @irq_mask .setter
335+ def irq_mask (self , val ):
336+ self ._write_u8 (_PCAL9554_IRQ_MASK , val )
142337
143338 @property
144- def get_int_status (self ):
145- """Get interrupt status """
339+ def irq_status (self ):
340+ """Indicates which pin caused an interrupt. """
146341 return self ._read_u8 (_PCAL9554_IRQ_STATUS )
342+
343+ @irq_status .setter
344+ def irq_status (self , val ):
345+ # Regsiter is read only
346+ pass
347+
348+ @property
349+ def out_port_config (self ):
350+ """Sets output banks to open drain or push-pull operation."""
351+ return self ._read_u8 (_PCAL9554_OUTPUT_PORT_CONFIG )
352+
353+ @out_port_config .setter
354+ def out_port_config (self , val ):
355+ self ._write_u8 (_PCAL9554_OUTPUT_PORT_CONFIG , val )
0 commit comments