Skip to content

Commit 74d02c4

Browse files
authored
Update pin.py
lgpio native changes
1 parent e1780c0 commit 74d02c4

File tree

1 file changed

+85
-28
lines changed
  • src/adafruit_blinka/microcontroller/bcm283x

1 file changed

+85
-28
lines changed

src/adafruit_blinka/microcontroller/bcm283x/pin.py

Lines changed: 85 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,65 @@
22
#
33
# SPDX-License-Identifier: MIT
44
"""Broadcom BCM283x pin names"""
5-
from RPi import GPIO
5+
from pathlib import Path
6+
import lgpio
67

7-
GPIO.setmode(GPIO.BCM) # Use BCM pins D4 = GPIO #4
8-
GPIO.setwarnings(False) # shh!
8+
def _get_gpiochip():
9+
"""
10+
Determines the handle of the GPIO chip device to access.
11+
12+
iterate through sysfs to find a GPIO chip device with a driver known to be
13+
used for userspace GPIO access.
14+
"""
15+
for dev in Path('/sys/bus/gpio/devices').glob('gpiochip*'):
16+
drivers = set((dev / 'of_node/compatible').read_text().split('\0'))
17+
# check if driver names are intended for userspace control
18+
if drivers & {'raspberrypi,rp1-gpio',
19+
'raspberrypi,bcm2835-gpio',
20+
'raspberrypi,bcm2711-gpio'}:
21+
return lgpio.gpiochip_open(int(dev.name[-1]))
22+
# return chip0 as a fallback
23+
return lgpio.gpiochip_open(0)
24+
25+
26+
CHIP = _get_gpiochip()
927

1028

1129
class Pin:
1230
"""Pins dont exist in CPython so...lets make our own!"""
1331

14-
IN = 0
15-
OUT = 1
1632
LOW = 0
1733
HIGH = 1
18-
PULL_NONE = 0
19-
PULL_UP = 1
20-
PULL_DOWN = 2
34+
OFF = LOW
35+
ON = HIGH
36+
37+
# values of lg mode constants
38+
PULL_NONE = 0x80
39+
PULL_UP = 0x20
40+
PULL_DOWN = 0x40
41+
ACTIVE_LOW = 0x02
42+
43+
# drive mode lg constants
44+
OPEN_DRAIN = 0x04
45+
IN = 0x0100
46+
OUT = 0x0200
47+
48+
# LG mode constants
49+
_LG_ALERT = 0x400
50+
_LG_GROUP = 0x800
51+
_LG_MODES = IN | OUT | _LG_ALERT | _LG_GROUP
52+
_LG_PULLS = PULL_NONE | PULL_UP | PULL_NONE | ACTIVE_LOW
53+
_LG_DRIVES = OPEN_DRAIN
2154

2255
id = None
2356
_value = LOW
2457
_mode = IN
2558

59+
# we want exceptions
60+
lgpio.exceptions = True
61+
2662
def __init__(self, bcm_number):
27-
self.id = bcm_number
63+
self.id = bcm_number # pylint: disable=invalid-name
2864

2965
def __repr__(self):
3066
return str(self.id)
@@ -35,40 +71,61 @@ def __eq__(self, other):
3571
def init(self, mode=IN, pull=None):
3672
"""Initialize the Pin"""
3773
if mode is not None:
38-
if mode == self.IN:
39-
self._mode = self.IN
40-
GPIO.setup(self.id, GPIO.IN)
74+
if mode == Pin.IN:
75+
self._mode = Pin.IN
76+
self._set_gpio_mode_in()
4177
elif mode == self.OUT:
42-
self._mode = self.OUT
43-
GPIO.setup(self.id, GPIO.OUT)
78+
self._mode = Pin.OUT
79+
Pin._check_result(lgpio.gpio_claim_output(CHIP, self.id,
80+
Pin.LOW))
4481
else:
45-
raise RuntimeError("Invalid mode for pin: %s" % self.id)
82+
raise RuntimeError(f"Invalid mode for pin: {self.id}")
4683
if pull is not None:
47-
if self._mode != self.IN:
48-
raise RuntimeError("Cannot set pull resistor on output")
49-
if pull == self.PULL_UP:
50-
GPIO.setup(self.id, GPIO.IN, pull_up_down=GPIO.PUD_UP)
51-
elif pull == self.PULL_DOWN:
52-
GPIO.setup(self.id, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
84+
if self._mode != Pin.IN:
85+
raise RuntimeError("Can only set pull resistor on input")
86+
if pull in {Pin.PULL_UP, Pin.PULL_DOWN, Pin.PULL_NONE}:
87+
self._set_gpio_mode_in(lflags=pull)
5388
else:
54-
raise RuntimeError("Invalid pull for pin: %s" % self.id)
89+
raise RuntimeError(f"Invalid pull for pin: {self.id}")
5590

5691
def value(self, val=None):
5792
"""Set or return the Pin Value"""
5893
if val is not None:
59-
if val == self.LOW:
94+
if val == Pin.LOW:
6095
self._value = val
61-
GPIO.output(self.id, val)
62-
elif val == self.HIGH:
96+
Pin._check_result(lgpio.gpio_write(CHIP, self.id, val))
97+
elif val == Pin.HIGH:
6398
self._value = val
64-
GPIO.output(self.id, val)
99+
Pin._check_result(lgpio.gpio_write(CHIP, self.id, val))
65100
else:
66101
raise RuntimeError("Invalid value for pin")
67102
return None
68-
return GPIO.input(self.id)
103+
return Pin._check_result(lgpio.gpio_read(CHIP, self.id))
104+
105+
@staticmethod
106+
def _check_result(result):
107+
"""
108+
convert any result other than zero to a text message and pass it back
109+
as a runtime exception. Typical usage: use the lgpio call as the
110+
argument.
111+
"""
112+
if result < 0:
113+
raise RuntimeError(lgpio.error_text(result))
114+
return result
115+
116+
def _set_gpio_mode_in(self, lflags=0):
117+
"""
118+
claim a gpio as input, or modify the flags (PULL_UP, PULL_DOWN, ... )
119+
"""
120+
# This gpio_free may seem redundant, but is required when
121+
# changing the line-flags of an already acquired input line
122+
try:
123+
lgpio.gpio_free(CHIP, self.id)
124+
except lgpio.error:
125+
pass
126+
Pin._check_result(lgpio.gpio_claim_input(CHIP, self.id, lFlags=lflags))
69127

70128

71-
# Pi 1B rev1 only?
72129
D0 = Pin(0)
73130
D1 = Pin(1)
74131

0 commit comments

Comments
 (0)