]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/bcm283x/pin.py
Add files via upload
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / bcm283x / pin.py
1 # SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2 #
3 # SPDX-License-Identifier: MIT
4 """Broadcom BCM283x pin names"""
5 from pathlib import Path
6 import lgpio
7
8
9 def _get_gpiochip():
10     """
11     Determines the handle of the GPIO chip device to access.
12
13     iterate through sysfs  to find a GPIO chip device with a driver known to be
14     used for userspace GPIO access.
15     """
16     for dev in Path("/sys/bus/gpio/devices").glob("gpiochip*"):
17         drivers = set((dev / "of_node/compatible").read_text().split("\0"))
18         #   check if driver names are intended for userspace control
19         if drivers & {
20             "raspberrypi,rp1-gpio",
21             "raspberrypi,bcm2835-gpio",
22             "raspberrypi,bcm2711-gpio",
23         }:
24             return lgpio.gpiochip_open(int(dev.name[-1]))
25     # return chip0 as a fallback
26     return lgpio.gpiochip_open(0)
27
28
29 CHIP = _get_gpiochip()
30
31
32 class Pin:
33     """Pins dont exist in CPython so...lets make our own!"""
34
35     LOW = 0
36     HIGH = 1
37     OFF = LOW
38     ON = HIGH
39
40     # values of lg mode constants
41     PULL_NONE = 0x80
42     PULL_UP = 0x20
43     PULL_DOWN = 0x40
44     ACTIVE_LOW = 0x02
45
46     # drive mode lg constants
47     OPEN_DRAIN = 0x04
48     IN = 0x0100
49     OUT = 0x0200
50
51     # LG mode constants
52     _LG_ALERT = 0x400
53     _LG_GROUP = 0x800
54     _LG_MODES = IN | OUT | _LG_ALERT | _LG_GROUP
55     _LG_PULLS = PULL_NONE | PULL_UP | PULL_NONE | ACTIVE_LOW
56     _LG_DRIVES = OPEN_DRAIN
57
58     id = None
59     _value = LOW
60     _mode = IN
61
62     # we want exceptions
63     lgpio.exceptions = True
64
65     def __init__(self, bcm_number):
66         self.id = bcm_number  # pylint: disable=invalid-name
67
68     def __repr__(self):
69         return str(self.id)
70
71     def __eq__(self, other):
72         return self.id == other
73
74     def init(self, mode=IN, pull=None):
75         """Initialize the Pin"""
76         if mode is not None:
77             if mode == Pin.IN:
78                 self._mode = Pin.IN
79                 self._set_gpio_mode_in()
80             elif mode == self.OUT:
81                 self._mode = Pin.OUT
82                 Pin._check_result(lgpio.gpio_claim_output(CHIP, self.id, Pin.LOW))
83             else:
84                 raise RuntimeError(f"Invalid mode for pin: {self.id}")
85         if pull is not None:
86             if self._mode != Pin.IN:
87                 raise RuntimeError("Can only set pull resistor on input")
88             if pull in {Pin.PULL_UP, Pin.PULL_DOWN, Pin.PULL_NONE}:
89                 self._set_gpio_mode_in(lflags=pull)
90             else:
91                 raise RuntimeError(f"Invalid pull for pin: {self.id}")
92
93     def value(self, val=None):
94         """Set or return the Pin Value"""
95         if val is not None:
96             if val == Pin.LOW:
97                 self._value = val
98                 Pin._check_result(lgpio.gpio_write(CHIP, self.id, val))
99             elif val == Pin.HIGH:
100                 self._value = val
101                 Pin._check_result(lgpio.gpio_write(CHIP, self.id, val))
102             else:
103                 raise RuntimeError("Invalid value for pin")
104             return None
105         return Pin._check_result(lgpio.gpio_read(CHIP, self.id))
106
107     @staticmethod
108     def _check_result(result):
109         """
110         convert any result other than zero to a text message and pass it back
111         as a runtime exception.  Typical usage:  use the lgpio call as the
112         argument.
113         """
114         if result < 0:
115             raise RuntimeError(lgpio.error_text(result))
116         return result
117
118     def _set_gpio_mode_in(self, lflags=0):
119         """
120         claim a gpio as input, or modify the flags (PULL_UP, PULL_DOWN, ... )
121         """
122         # This gpio_free may seem redundant, but is required when
123         #  changing the line-flags of an already acquired input line
124         try:
125             lgpio.gpio_free(CHIP, self.id)
126         except lgpio.error:
127             pass
128         Pin._check_result(lgpio.gpio_claim_input(CHIP, self.id, lFlags=lflags))
129
130
131 D0 = Pin(0)
132 D1 = Pin(1)
133
134 D2 = Pin(2)
135 SDA = Pin(2)
136 D3 = Pin(3)
137 SCL = Pin(3)
138
139 D4 = Pin(4)
140 D5 = Pin(5)
141 D6 = Pin(6)
142
143 D7 = Pin(7)
144 CE1 = Pin(7)
145 D8 = Pin(8)
146 CE0 = Pin(8)
147 D9 = Pin(9)
148 MISO = Pin(9)
149 D10 = Pin(10)
150 MOSI = Pin(10)
151 D11 = Pin(11)
152 SCLK = Pin(11)  # Raspberry Pi naming
153 SCK = Pin(11)  # CircuitPython naming
154
155 D12 = Pin(12)
156 D13 = Pin(13)
157
158 D14 = Pin(14)
159 TXD = Pin(14)
160 D15 = Pin(15)
161 RXD = Pin(15)
162
163 D16 = Pin(16)
164 D17 = Pin(17)
165 D18 = Pin(18)
166 D19 = Pin(19)
167 MISO_1 = Pin(19)
168 D20 = Pin(20)
169 MOSI_1 = Pin(20)
170 D21 = Pin(21)
171 SCLK_1 = Pin(21)
172 SCK_1 = Pin(21)
173 D22 = Pin(22)
174 D23 = Pin(23)
175 D24 = Pin(24)
176 D25 = Pin(25)
177 D26 = Pin(26)
178 D27 = Pin(27)
179 D28 = Pin(28)
180 D29 = Pin(29)
181 D30 = Pin(30)
182 D31 = Pin(31)
183 D32 = Pin(32)
184 D33 = Pin(33)
185 D34 = Pin(34)
186 D35 = Pin(35)
187 D36 = Pin(36)
188 D37 = Pin(37)
189 D38 = Pin(38)
190 D39 = Pin(39)
191 D40 = Pin(40)
192 MISO_2 = Pin(40)
193 D41 = Pin(41)
194 MOSI_2 = Pin(41)
195 D42 = Pin(42)
196 SCLK_2 = Pin(42)
197 SCK_2 = Pin(43)
198 D43 = Pin(43)
199 D44 = Pin(44)
200 D45 = Pin(45)
201
202 # ordered as spiId, sckId, mosiId, misoId
203 spiPorts = (
204     (0, SCLK, MOSI, MISO),
205     (1, SCLK_1, MOSI_1, MISO_1),
206     (2, SCLK_2, MOSI_2, MISO_2),
207 )
208
209 # ordered as uartId, txId, rxId
210 uartPorts = ((1, TXD, RXD),)
211
212 # These are the known hardware I2C ports / pins.
213 # For software I2C ports created with the i2c-gpio overlay, see:
214 #     https://github.com/adafruit/Adafruit_Python_Extended_Bus
215 i2cPorts = (
216     (1, SCL, SDA),
217     (0, D1, D0),  # both pi 1 and pi 2 i2c ports!
218 )