From: Melissa LeBlanc-Williams Date: Thu, 9 Jan 2020 17:43:01 +0000 (-0800) Subject: Rebasing due to this being old X-Git-Tag: 3.7.0^2~10^2^2 X-Git-Url: https://git.ayoreis.com/Adafruit_Blinka-hackapet.git/commitdiff_plain/82ff2f40b52f57e3d5ac746ca965fdc026f38d9e?hp=fafe6bc929c4e9c4430da3128b1f88bda8b2ca2d Rebasing due to this being old --- diff --git a/.travis.yml b/.travis.yml index 58f60ff..14a1017 100755 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ deploy: tags: true install: + - sudo apt-get install libudev-dev libusb-1.0 - pip install -r requirements.txt - pip install --force-reinstall pylint==1.9.2 - pip install circuitpython-build-tools Sphinx sphinx-rtd-theme diff --git a/README.rst b/README.rst index d33adb4..07266d7 100755 --- a/README.rst +++ b/README.rst @@ -18,6 +18,7 @@ on hosts running micropython. Working code exists to emulate the CircuitPython p * **board** - breakout-specific pin identities * **microcontroller** - chip-specific pin identities +* **analogio** - analog input/output pins, using pin identities from board+microcontroller packages * **digitalio** - digital input/output pins, using pin identities from board+microcontroller packages * **bitbangio** - software-driven interfaces for I2C, SPI * **busio** - hardware-driven interfaces for I2C, SPI, UART diff --git a/requirements.txt b/requirements.txt index daaff66..a2cfda9 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,9 @@ Adafruit-PlatformDetect Adafruit-PureIO +Jetson.GPIO; platform_machine=='aarch64' RPi.GPIO; platform_machine=='armv7l' or platform_machine=='armv6l' rpi_ws281x>=4.0.0; platform_machine=='armv7l' or platform_machine=='armv6l' -spidev; sys_platform == 'linux' -sysv_ipc +spidev>=3.4; sys_platform == 'linux' and platform_machine!='mips' +sysv_ipc; sys_platform == 'linux' and platform_machine!='mips' +pyftdi>=0.40.0 +binho-host-adapter>=0.1.4 diff --git a/setup.py b/setup.py index cb3549c..0bd1560 100755 --- a/setup.py +++ b/setup.py @@ -17,6 +17,18 @@ here = os.path.abspath(os.path.dirname(__file__)) with io.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = '\n' + f.read() +board_reqs = [] +if os.path.exists('/proc/device-tree/compatible'): + with open('/proc/device-tree/compatible', 'rb') as f: + compat = f.read() + if b'nvidia,tegra' in compat: + board_reqs = ['Jetson.GPIO'] + if b'brcm,bcm2835' in compat or \ + b'brcm,bcm2836' in compat or \ + b'brcm,bcm2837' in compat or \ + b'brcm,bcm2838' in compat: + board_reqs = ['RPi.GPIO', 'rpi_ws281x>=4.0.0'] + setup( name='Adafruit-Blinka', use_scm_version=True, @@ -32,16 +44,15 @@ setup( packages=find_packages("src"), # py_modules lists top-level single file packages to include. # find_packages only finds packages in directories with __init__.py files. - py_modules=['bitbangio', 'board', 'busio', 'digitalio', 'micropython', 'pulseio', 'neopixel_write'], + py_modules=['analogio', 'bitbangio', 'board', 'busio', 'digitalio', 'micropython', 'pulseio', 'neopixel_write'], package_data={'adafruit_blinka.microcontroller.bcm283x.pulseio': ['libgpiod_pulsein']}, install_requires=[ "Adafruit-PlatformDetect", "Adafruit-PureIO", - "RPi.GPIO; platform_machine=='armv7l' or platform_machine=='armv6l'", - "rpi_ws281x>=4.0.0; platform_machine=='armv7l' or platform_machine=='armv6l'", - "spidev; sys_platform=='linux'", - "sysv_ipc; platform_system != 'Windows'" - ], + "spidev>=3.4; sys_platform=='linux' and platform_machine!='mips'", + "sysv_ipc; platform_system != 'Windows' and platform_machine != 'mips'", + "pyftdi>=0.40.0" + ] + board_reqs, license='MIT', classifiers=[ # Trove classifiers diff --git a/src/adafruit_blinka/board/beaglebone_pocketbeagle.py b/src/adafruit_blinka/board/beaglebone_pocketbeagle.py index a56e5f7..fc0bb3a 100644 --- a/src/adafruit_blinka/board/beaglebone_pocketbeagle.py +++ b/src/adafruit_blinka/board/beaglebone_pocketbeagle.py @@ -40,10 +40,10 @@ P1_29 = pin.P1_29 # GPIO3_21 - GPIO_117 P1_30 = pin.P1_30 # UART0_TXD - GPIO_43 P1_31 = pin.P1_31 # GPIO3_18 - GPIO_114 P1_32 = pin.P1_32 # UART0_RXD - GPIO_42 -P1_33 = pin.P1_33 # GPIO3_15 - GPIO_111 +P1_33 = pin.P1_33 # GPIO3_15 - GPIO_111 - EHRPWM0B (ehrpwm.0:1) P1_34 = pin.P1_34 # GPIO0_26 - GPIO_26 P1_35 = pin.P1_35 # GPIO2_24 - GPIO_88 -P1_36 = pin.P1_36 # EHRPWM0A - GPIO_110 +P1_36 = pin.P1_36 # EHRPWM0A - GPIO_110 - EHRPWM0A (ehrpwm.0:0) P2_1 = pin.P2_1 # EHRPWM1A - GPIO_50 diff --git a/src/adafruit_blinka/board/binho_nova.py b/src/adafruit_blinka/board/binho_nova.py new file mode 100644 index 0000000..0dfe4a4 --- /dev/null +++ b/src/adafruit_blinka/board/binho_nova.py @@ -0,0 +1,20 @@ +from adafruit_blinka.microcontroller.nova import pin + +IO0 = pin.IO0 +IO1 = pin.IO1 +IO2 = pin.IO2 +IO3 = pin.IO3 +IO4 = pin.IO4 + +TX = IO4 +RX = IO3 + +SDA = pin.SDA +SCL = pin.SCL + +SCK = pin.SCK +SCLK = pin.SCLK +MOSI = pin.MOSI +MISO = pin.MISO +SS0 = pin.SS0 +SS1 = pin.SS1 diff --git a/src/adafruit_blinka/board/ftdi_ft232h.py b/src/adafruit_blinka/board/ftdi_ft232h.py new file mode 100644 index 0000000..5c5b278 --- /dev/null +++ b/src/adafruit_blinka/board/ftdi_ft232h.py @@ -0,0 +1,22 @@ +from adafruit_blinka.microcontroller.ft232h import pin + +D4 = pin.D4 +D5 = pin.D5 +D6 = pin.D6 +D7 = pin.D7 +C0 = pin.C0 +C1 = pin.C1 +C2 = pin.C2 +C3 = pin.C3 +C4 = pin.C4 +C5 = pin.C5 +C6 = pin.C6 +C7 = pin.C7 + +SDA = pin.SDA +SCL = pin.SCL + +SCK = pin.SCK +SCLK = pin.SCLK +MOSI = pin.MOSI +MISO = pin.MISO diff --git a/src/adafruit_blinka/board/jetson_nano.py b/src/adafruit_blinka/board/jetson_nano.py index 4da8cf5..8b9b77c 100644 --- a/src/adafruit_blinka/board/jetson_nano.py +++ b/src/adafruit_blinka/board/jetson_nano.py @@ -29,3 +29,17 @@ D24 = pin.B07 D25 = pin.B05 D26 = pin.B04 D27 = pin.B06 + +CE1 = D7 +CE0 = D8 +MISO = D9 +MOSI = D10 +SCLK = D11 +SCK = D11 + +CE1_1 = D23 +CE0_1 = D24 +MISO_1 = D25 +MOSI_1 = D26 +SCLK_1 = D27 +SCK_1 = D27 diff --git a/src/adafruit_blinka/board/jetson_tx1.py b/src/adafruit_blinka/board/jetson_tx1.py index 05fc390..cfa70dc 100644 --- a/src/adafruit_blinka/board/jetson_tx1.py +++ b/src/adafruit_blinka/board/jetson_tx1.py @@ -29,3 +29,10 @@ D24 = pin.X00 D25 = pin.P16 D26 = pin.X03 D27 = pin.E06 + +CE1 = D7 +CE0 = D8 +MISO = D9 +MOSI = D10 +SCLK = D11 +SCK = D11 diff --git a/src/adafruit_blinka/board/jetson_tx2.py b/src/adafruit_blinka/board/jetson_tx2.py index 906fa56..47c1624 100644 --- a/src/adafruit_blinka/board/jetson_tx2.py +++ b/src/adafruit_blinka/board/jetson_tx2.py @@ -10,6 +10,7 @@ SCL_1 = pin.SCL_1 D4 = pin.J04 D5 = pin.J06 D6 = pin.AA02 +D7 = pin.N03 D8 = pin.N06 D9 = pin.N04 D10 = pin.N05 @@ -28,3 +29,10 @@ D24 = pin.Y01 D25 = pin.P16 D26 = pin.I04 D27 = pin.J05 + +CE1 = D7 +CE0 = D8 +MISO = D9 +MOSI = D10 +SCLK = D11 +SCK = D11 diff --git a/src/adafruit_blinka/board/jetson_xavier.py b/src/adafruit_blinka/board/jetson_xavier.py index 24e229f..2910582 100644 --- a/src/adafruit_blinka/board/jetson_xavier.py +++ b/src/adafruit_blinka/board/jetson_xavier.py @@ -29,3 +29,10 @@ D24 = pin.H00 D25 = pin.Q01 D26 = pin.AA01 D27 = pin.R00 + +CE1 = D7 +CE0 = D8 +MISO = D9 +MOSI = D10 +SCLK = D11 +SCK = D11 diff --git a/src/adafruit_blinka/board/microchip_mcp2221.py b/src/adafruit_blinka/board/microchip_mcp2221.py new file mode 100644 index 0000000..bdb3ba2 --- /dev/null +++ b/src/adafruit_blinka/board/microchip_mcp2221.py @@ -0,0 +1,9 @@ +from adafruit_blinka.microcontroller.mcp2221 import pin + +G0 = pin.G0 +G1 = pin.G1 +G2 = pin.G2 +G3 = pin.G3 + +SCL = pin.SCL +SDA = pin.SDA \ No newline at end of file diff --git a/src/adafruit_blinka/board/orangepipc.py b/src/adafruit_blinka/board/orangepipc.py index 8c6e88e..7f32cdf 100644 --- a/src/adafruit_blinka/board/orangepipc.py +++ b/src/adafruit_blinka/board/orangepipc.py @@ -1,6 +1,6 @@ """Pin definitions for the Orange Pi PC.""" -from adafruit_blinka.microcontroller.allwinner_h3 import pin +from adafruit_blinka.microcontroller.allwinner.h3 import pin PA12 = pin.PA12 SDA = pin.PA12 diff --git a/src/adafruit_blinka/board/orangepir1.py b/src/adafruit_blinka/board/orangepir1.py index 9319450..0752c51 100644 --- a/src/adafruit_blinka/board/orangepir1.py +++ b/src/adafruit_blinka/board/orangepir1.py @@ -1,6 +1,6 @@ """Pin definitions for the Orange Pi R1.""" -from adafruit_blinka.microcontroller.allwinner_h3 import pin +from adafruit_blinka.microcontroller.allwinner.h3 import pin PA12 = pin.PA12 SDA = pin.PA12 diff --git a/src/adafruit_blinka/board/orangepizero.py b/src/adafruit_blinka/board/orangepizero.py new file mode 100644 index 0000000..a1dd925 --- /dev/null +++ b/src/adafruit_blinka/board/orangepizero.py @@ -0,0 +1,36 @@ +"""Pin definitions for the Orange Pi Zero.""" + +# The Orange Pi Zero uses the AllWinner H2 SoC, but pins +# are the same as the AllWinner H3 SoC, so we import those +from adafruit_blinka.microcontroller.allwinner.h3 import pin + +PA12 = pin.PA12 +SDA = pin.PA12 +PA11 = pin.PA11 +SCL = pin.PA11 +PA6 = pin.PA6 +PWM1 = pin.PA6 +PA1 = pin.PA1 +UART2_RX = pin.PA1 +PA0 = pin.PA0 +UART2_TX = pin.PA0 +PA3 = pin.PA3 +UART2_CTS = pin.PA3 +PA10 = pin.PA10 + +PA13 = pin.PA13 +SPI1_CS = pin.PA13 +PA14 = pin.PA14 +SPI1_CLK = pin.PA14 +PA2 = pin.PA2 +UART2_RTS = pin.PA2 +PA18 = pin.PA18 +TWI1_SCK = pin.PA18 +PG6 = pin.PG6 +UART1_TX = pin.PG6 +PG7 = pin.PG7 +UART1_RX = pin.PG7 + +SCLK = pin.PA14 +MOSI = pin.PA15 +MISO = pin.PA16 diff --git a/src/adafruit_blinka/board/raspi_1b_rev1.py b/src/adafruit_blinka/board/raspi_1b_rev1.py index 817e911..59168dc 100644 --- a/src/adafruit_blinka/board/raspi_1b_rev1.py +++ b/src/adafruit_blinka/board/raspi_1b_rev1.py @@ -24,6 +24,9 @@ D14 = pin.D14 TXD = pin.D14 D15 = pin.D15 RXD = pin.D15 +# create alias for most of the examples +TX = pin.D14 +RX = pin.D15 D17 = pin.D17 D18 = pin.D18 diff --git a/src/adafruit_blinka/board/raspi_1b_rev2.py b/src/adafruit_blinka/board/raspi_1b_rev2.py index 05dd69d..47fc39b 100644 --- a/src/adafruit_blinka/board/raspi_1b_rev2.py +++ b/src/adafruit_blinka/board/raspi_1b_rev2.py @@ -24,6 +24,9 @@ D14 = pin.D14 TXD = pin.D14 D15 = pin.D15 RXD = pin.D15 +# create alias for most of the examples +TX = pin.D14 +RX = pin.D15 D17 = pin.D17 D18 = pin.D18 diff --git a/src/adafruit_blinka/board/raspi_40pin.py b/src/adafruit_blinka/board/raspi_40pin.py index 4758291..91347e0 100644 --- a/src/adafruit_blinka/board/raspi_40pin.py +++ b/src/adafruit_blinka/board/raspi_40pin.py @@ -2,6 +2,9 @@ from adafruit_blinka.microcontroller.bcm283x import pin +D0 = pin.D0 +D1 = pin.D1 + D2 = pin.D2 SDA = pin.SDA D3 = pin.D3 @@ -30,6 +33,9 @@ D14 = pin.D14 TXD = pin.D14 D15 = pin.D15 RXD = pin.D15 +# create alias for most of the examples +TX = pin.D14 +RX = pin.D15 D16 = pin.D16 D17 = pin.D17 diff --git a/src/adafruit_blinka/board/raspi_cm.py b/src/adafruit_blinka/board/raspi_cm.py index eff7f96..3380178 100644 --- a/src/adafruit_blinka/board/raspi_cm.py +++ b/src/adafruit_blinka/board/raspi_cm.py @@ -30,6 +30,9 @@ D14 = pin.D14 TXD = pin.D14 D15 = pin.D15 RXD = pin.D15 +# create alias for most of the examples +TX = pin.D14 +RX = pin.D15 D16 = pin.D16 D17 = pin.D17 diff --git a/src/adafruit_blinka/board/tritium-h3.py b/src/adafruit_blinka/board/tritium-h3.py index 620957c..516528a 100644 --- a/src/adafruit_blinka/board/tritium-h3.py +++ b/src/adafruit_blinka/board/tritium-h3.py @@ -1,6 +1,6 @@ """Pin definitions for the Tritium H3.""" -from adafruit_blinka.microcontroller.allwinner_h3 import pin +from adafruit_blinka.microcontroller.allwinner.h3 import pin PA12 = pin.PA12 SDA = pin.PA12 diff --git a/src/adafruit_blinka/microcontroller/allwinner/__init__.py b/src/adafruit_blinka/microcontroller/allwinner/__init__.py new file mode 100644 index 0000000..78b6459 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/allwinner/__init__.py @@ -0,0 +1 @@ +"""Definition of all Allwinner chips""" \ No newline at end of file diff --git a/src/adafruit_blinka/microcontroller/allwinner/a64/__init__.py b/src/adafruit_blinka/microcontroller/allwinner/a64/__init__.py new file mode 100644 index 0000000..18e8421 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/allwinner/a64/__init__.py @@ -0,0 +1 @@ +"""Definition for the AllWinner A64 chip""" \ No newline at end of file diff --git a/src/adafruit_blinka/microcontroller/allwinner/a64/pin.py b/src/adafruit_blinka/microcontroller/allwinner/a64/pin.py new file mode 100644 index 0000000..0ecf2f2 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/allwinner/a64/pin.py @@ -0,0 +1,65 @@ +from adafruit_blinka.microcontroller.generic_linux.libgpiod_pin import Pin + +PB0 = Pin(32) +UART2_TX = PB0 +PB1 = Pin(33) +UART2_RX = PB1 +PB2 = Pin(34) +PB3 = Pin(35) +PB4 = Pin(36) +PB5 = Pin(37) +PB6 = Pin(38) +PB7 = Pin(39) + +PC4 = Pin(68) + +PD0 = Pin(96) +UART3_TX = PD0 +SPI1_CS = PD0 +PD1 = Pin(97) +SPI1_SCLK = PD1 +UART3_RX = PD1 +PD2 = Pin(98) +UART4_TX = PD2 +SPI1_MOSI = PD2 +PD3 = Pin(99) +UART4_RX = PD3 +SPI1_MISO = PD3 +PD4 = Pin(100) +PD5 = Pin(101) +PD6 = Pin(102) + +PE14 = Pin(142) +TWI2_SCL = PE14 +PE15 = Pin(143) +TWI2_SDA = PE15 + +PH2 = Pin(226) +TWI1_SCL = PH2 +PH3 = Pin(227) +TWI1_SDA = PH3 +PH4 = Pin(228) +PH5 = Pin(229) +PH6 = Pin(230) + +PL2 = Pin(354) +PL3 = Pin(355) +PL9 = Pin(361) +PL10 = Pin(362) + +# ordered as i2cId, sclId, sdaId +i2cPorts = ( + (1, TWI1_SCL, TWI1_SDA), + (2, TWI2_SCL, TWI2_SDA) +) + +# ordered as spiId, sckId, mosiId, misoId +spiPorts = ( + (1, SPI1_SCLK, SPI1_MOSI, SPI1_MISO), +) +# ordered as uartId, txId, rxId +uartPorts = ( + (2, UART2_TX, UART2_RX), + (3, UART3_TX, UART3_RX), + (4, UART4_TX, UART4_RX), +) diff --git a/src/adafruit_blinka/microcontroller/allwinner/h3/__init__.py b/src/adafruit_blinka/microcontroller/allwinner/h3/__init__.py new file mode 100644 index 0000000..e6b08ac --- /dev/null +++ b/src/adafruit_blinka/microcontroller/allwinner/h3/__init__.py @@ -0,0 +1 @@ +"""Definition for the AllWinner H3 chip""" \ No newline at end of file diff --git a/src/adafruit_blinka/microcontroller/allwinner_h3/pin.py b/src/adafruit_blinka/microcontroller/allwinner/h3/pin.py similarity index 82% rename from src/adafruit_blinka/microcontroller/allwinner_h3/pin.py rename to src/adafruit_blinka/microcontroller/allwinner/h3/pin.py index f2ed8c0..7ddf86c 100644 --- a/src/adafruit_blinka/microcontroller/allwinner_h3/pin.py +++ b/src/adafruit_blinka/microcontroller/allwinner/h3/pin.py @@ -55,8 +55,15 @@ PG12 = Pin(204) PG13 = Pin(205) -i2cPorts = ( (0, TWI0_SCL, TWI0_SDA), ) +i2cPorts = ( + (0, TWI0_SCL, TWI0_SDA), +) # ordered as spiId, sckId, mosiId, misoId -spiPorts = ( (0, SPI0_SCLK, SPI0_MOSI, SPI0_MISO), (1, SPI1_SCLK, SPI1_MOSI, SPI1_MISO), ) +spiPorts = ( + (0, SPI0_SCLK, SPI0_MOSI, SPI0_MISO), + (1, SPI1_SCLK, SPI1_MOSI, SPI1_MISO), +) # ordered as uartId, txId, rxId -uartPorts = ( (3, UART3_TX, UART3_RX), ) +uartPorts = ( + (3, UART3_TX, UART3_RX), +) diff --git a/src/adafruit_blinka/microcontroller/am335x/pin.py b/src/adafruit_blinka/microcontroller/am335x/pin.py index e73457d..ca9d027 100644 --- a/src/adafruit_blinka/microcontroller/am335x/pin.py +++ b/src/adafruit_blinka/microcontroller/am335x/pin.py @@ -343,3 +343,10 @@ i2cPorts = ( (1, I2C1_SCL, I2C1_SDA), (2, I2C2_SCL, I2C2_SDA), ) + +PWM1 = P1_36 +PWM2 = P1_33 +PWM3 = P2_1 +PWM4 = P2_3 + +pwmOuts = ( ((0, 0), PWM1), ((0, 1), PWM2), ((2, 0), PWM3), ((4, 1), PWM4) ) diff --git a/src/adafruit_blinka/microcontroller/am335x/sysfs_pwmout.py b/src/adafruit_blinka/microcontroller/am335x/sysfs_pwmout.py new file mode 100644 index 0000000..70bab33 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/am335x/sysfs_pwmout.py @@ -0,0 +1,287 @@ +# Much code from https://github.com/vsergeev/python-periphery/blob/master/periphery/pwm.py +# Copyright (c) 2015-2016 vsergeev / Ivan (Vanya) A. Sergeev +# License: MIT + +import os +import digitalio + +try: + from microcontroller.pin import pwmOuts +except ImportError: + raise RuntimeError("No PWM outputs defined for this board") + +class PWMError(IOError): + """Base class for PWM errors.""" + pass + + +class PWMOut(object): + # Sysfs paths + _sysfs_path = "/sys/class/pwm/" + _channel_path = "pwmchip{}" + + # Channel paths + _export_path = "export" + _unexport_path = "unexport" + _pin_path = "pwm-{}:{}" + + # Pin attribute paths + _pin_period_path = "period" + _pin_duty_cycle_path = "duty_cycle" + _pin_polarity_path = "polarity" + _pin_enable_path = "enable" + + def __init__(self, pin, *, frequency=500, duty_cycle=0, variable_frequency=False): + """Instantiate a PWM object and open the sysfs PWM corresponding to the + specified channel and pin. + + Args: + pin (Pin): CircuitPython Pin object to output to + duty_cycle (int) : The fraction of each pulse which is high. 16-bit + frequency (int) : target frequency in Hertz (32-bit) + variable_frequency (bool) : True if the frequency will change over time + + Returns: + PWMOut: PWMOut object. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if `channel` or `pin` types are invalid. + ValueError: if PWM channel does not exist. + + """ + + self._pwmpin = None + self._open(pin, duty_cycle, frequency, variable_frequency) + + def __del__(self): + self.deinit() + + def __enter__(self): + return self + + def __exit__(self, t, value, traceback): + self.deinit() + + def _open(self, pin, duty=0, freq=500, variable_frequency=False): + self._channel = None + for pwmpair in pwmOuts: + if pwmpair[1] == pin: + self._channel = pwmpair[0][0] + self._pwmpin = pwmpair[0][1] + + self._pin = pin + if self._channel is None: + raise RuntimeError("No PWM channel found for this Pin") + + channel_path = os.path.join(self._sysfs_path, self._channel_path.format(self._channel)) + if not os.path.isdir(channel_path): + raise ValueError("PWM channel does not exist, check that the required modules are loaded.") + + pin_path = os.path.join(channel_path, self._pin_path.format(self._channel,self._pwmpin)) + if not os.path.isdir(pin_path): + try: + with open(os.path.join(channel_path, self._export_path), "w") as f_export: + f_export.write("%d\n" % self._pwmpin) + except IOError as e: + raise PWMError(e.errno, "Exporting PWM pin: " + e.strerror) + + # Look up the period, for fast duty cycle updates + self._period = self._get_period() + + # set frequency + self.frequency = freq + # set duty + self.duty_cycle = duty + + self._set_enabled(True) + + def deinit(self): + try: + """Deinit the sysfs PWM.""" + channel_path = os.path.join(self._sysfs_path, self._channel_path.format(self._channel)) + pin_path = os.path.join(channel_path, self._pin_path.format(self._channel,self._pwmpin)) + + if self._channel is not None: + #self.duty_cycle = 0 + self._set_enabled(False) # make to disable before unexport + try: + #unexport_path = os.path.join(channel_path, self._unexport_path) + with open(os.path.join(channel_path, self._unexport_path), "w") as f_unexport: + f_unexport.write("%d\n" % self._pwmpin) + except IOError as e: + raise PWMError(e.errno, "Unexporting PWM pin: " + e.strerror) + except Exception as e: + # due to a race condition for which I have not yet been + # able to find the root cause, deinit() often fails + # but it does not effect future usage of the pwm pin + print("warning: failed to deinitialize pwm pin {0}:{1} due to: {2}\n".format(self._channel, self._pwmpin, type(e).__name__)) + finally: + self._channel = None + self._pwmpin = None + + def _is_deinited(self): + if self._pwmpin is None: + raise ValueError("Object has been deinitialize and can no longer " + "be used. Create a new object.") + + def _write_pin_attr(self, attr, value): + # Make sure the pin is active + self._is_deinited() + + path = os.path.join( + self._sysfs_path, + self._channel_path.format(self._channel), + self._pin_path.format(self._channel,self._pwmpin), + attr) + + with open(path, 'w') as f_attr: + f_attr.write(value + "\n") + + def _read_pin_attr(self, attr): + # Make sure the pin is active + self._is_deinited() + + path = os.path.join( + self._sysfs_path, + self._channel_path.format(self._channel), + self._pin_path.format(self._channel,self._pwmpin), + attr) + + with open(path, 'r') as f_attr: + return f_attr.read().strip() + + # Mutable properties + + def _get_period(self): + period_ns = self._read_pin_attr(self._pin_period_path) + try: + period_ns = int(period_ns) + except ValueError: + raise PWMError(None, "Unknown period value: \"%s\"" % period_ns) + + # Convert period from nanoseconds to seconds + period = period_ns / 1e9 + + # Update our cached period + self._period = period + + return period + + def _set_period(self, period): + if not isinstance(period, (int, float)): + raise TypeError("Invalid period type, should be int or float.") + + # Convert period from seconds to integer nanoseconds + period_ns = int(period * 1e9) + + self._write_pin_attr(self._pin_period_path, "{}".format(period_ns)) + + # Update our cached period + self._period = float(period) + + period = property(_get_period, _set_period) + + """Get or set the PWM's output period in seconds. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + + :type: int, float + """ + + def _get_duty_cycle(self): + duty_cycle_ns = self._read_pin_attr(self._pin_duty_cycle_path) + try: + duty_cycle_ns = int(duty_cycle_ns) + except ValueError: + raise PWMError(None, "Unknown duty cycle value: \"%s\"" % duty_cycle_ns) + + # Convert duty cycle from nanoseconds to seconds + duty_cycle = duty_cycle_ns / 1e9 + + # Convert duty cycle to ratio from 0.0 to 1.0 + duty_cycle = duty_cycle / self._period + + # convert to 16-bit + duty_cycle = int(duty_cycle * 65535) + return duty_cycle + + def _set_duty_cycle(self, duty_cycle): + if not isinstance(duty_cycle, (int, float)): + raise TypeError("Invalid duty cycle type, should be int or float.") + + # convert from 16-bit + duty_cycle /= 65535.0 + if not 0.0 <= duty_cycle <= 1.0: + raise ValueError("Invalid duty cycle value, should be between 0.0 and 1.0.") + + # Convert duty cycle from ratio to seconds + duty_cycle = duty_cycle * self._period + + # Convert duty cycle from seconds to integer nanoseconds + duty_cycle_ns = int(duty_cycle * 1e9) + + self._write_pin_attr(self._pin_duty_cycle_path, "{}".format(duty_cycle_ns)) + + duty_cycle = property(_get_duty_cycle, _set_duty_cycle) + """Get or set the PWM's output duty cycle as a ratio from 0.0 to 1.0. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + ValueError: if value is out of bounds of 0.0 to 1.0. + + :type: int, float + """ + + def _get_frequency(self): + return 1.0 / self._get_period() + + def _set_frequency(self, frequency): + if not isinstance(frequency, (int, float)): + raise TypeError("Invalid frequency type, should be int or float.") + + self._set_period(1.0 / frequency) + + frequency = property(_get_frequency, _set_frequency) + """Get or set the PWM's output frequency in Hertz. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + + :type: int, float + """ + + def _get_enabled(self): + enabled = self._read_pin_attr(self._pin_enable_path) + + if enabled == "1": + return True + elif enabled == "0": + return False + + raise PWMError(None, "Unknown enabled value: \"%s\"" % enabled) + + def _set_enabled(self, value): + if not isinstance(value, bool): + raise TypeError("Invalid enabled type, should be string.") + + self._write_pin_attr(self._pin_enable_path, "1" if value else "0") + + """Get or set the PWM's output enabled state. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not bool. + + :type: bool + """ + + # String representation + + def __str__(self): + return "PWM%d, pin %s (freq=%f Hz, duty_cycle=%f%%)" % \ + (self._channel, self._pin, self.frequency, self.duty_cycle * 100,) diff --git a/src/adafruit_blinka/microcontroller/bcm283x/pin.py b/src/adafruit_blinka/microcontroller/bcm283x/pin.py index 10835dc..3db76df 100644 --- a/src/adafruit_blinka/microcontroller/bcm283x/pin.py +++ b/src/adafruit_blinka/microcontroller/bcm283x/pin.py @@ -139,6 +139,5 @@ uartPorts = ( ) i2cPorts = ( - (1, SCL, SDA), (0, D1, D0), # both pi 1 and pi 2 i2c ports! + (3, SCL, SDA), (1, SCL, SDA), (0, D1, D0), # both pi 1 and pi 2 i2c ports! ) - diff --git a/src/adafruit_blinka/microcontroller/bcm283x/pulseio/PulseIn.py b/src/adafruit_blinka/microcontroller/bcm283x/pulseio/PulseIn.py index b918c86..289d106 100644 --- a/src/adafruit_blinka/microcontroller/bcm283x/pulseio/PulseIn.py +++ b/src/adafruit_blinka/microcontroller/bcm283x/pulseio/PulseIn.py @@ -48,7 +48,7 @@ class PulseIn: cmd = [dir_path+"/libgpiod_pulsein", "--pulses", str(maxlen), "--queue", str(self._mq.key)] - if not idle_state: + if idle_state: cmd.append("-i") cmd.append("gpiochip0") cmd.append(str(pin)) diff --git a/src/adafruit_blinka/microcontroller/bcm283x/pulseio/libgpiod_pulsein b/src/adafruit_blinka/microcontroller/bcm283x/pulseio/libgpiod_pulsein index c58b443..3bbb65f 100755 Binary files a/src/adafruit_blinka/microcontroller/bcm283x/pulseio/libgpiod_pulsein and b/src/adafruit_blinka/microcontroller/bcm283x/pulseio/libgpiod_pulsein differ diff --git a/src/adafruit_blinka/microcontroller/allwinner_h3/__init__.py b/src/adafruit_blinka/microcontroller/ft232h/__init__.py similarity index 100% rename from src/adafruit_blinka/microcontroller/allwinner_h3/__init__.py rename to src/adafruit_blinka/microcontroller/ft232h/__init__.py diff --git a/src/adafruit_blinka/microcontroller/ft232h/i2c.py b/src/adafruit_blinka/microcontroller/ft232h/i2c.py new file mode 100644 index 0000000..7f733c1 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/ft232h/i2c.py @@ -0,0 +1,37 @@ +from adafruit_blinka.microcontroller.ft232h.pin import Pin + +class I2C: + + def __init__(self, *, frequency=400000): + # change GPIO controller to I2C + from pyftdi.i2c import I2cController + self._i2c = I2cController() + self._i2c.configure('ftdi:///1', frequency=frequency) + Pin.ft232h_gpio = self._i2c.get_gpio() + + def scan(self): + return [addr for addr in range(0x79) if self._i2c.poll(addr)] + + def writeto(self, address, buffer, *, start=0, end=None, stop=True): + end = end if end else len(buffer) + port = self._i2c.get_port(address) + port.write(buffer[start:end], relax=stop) + + def readfrom_into(self, address, buffer, *, start=0, end=None, stop=True): + end = end if end else len(buffer) + port = self._i2c.get_port(address) + result = port.read(len(buffer[start:end]), relax=stop) + for i, b in enumerate(result): + buffer[start+i] = b + + def writeto_then_readfrom(self, address, buffer_out, buffer_in, *, + out_start=0, out_end=None, + in_start=0, in_end=None, stop=False): + out_end = out_end if out_end else len(buffer_out) + in_end = in_end if in_end else len(buffer_in) + port = self._i2c.get_port(address) + result = port.exchange(buffer_out[out_start:out_end], + in_end-in_start, + relax=True) + for i, b in enumerate(result): + buffer_in[in_start+i] = b diff --git a/src/adafruit_blinka/microcontroller/ft232h/pin.py b/src/adafruit_blinka/microcontroller/ft232h/pin.py new file mode 100644 index 0000000..30dbc66 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/ft232h/pin.py @@ -0,0 +1,80 @@ +class Pin: + """A basic Pin class for use with FT232H.""" + + IN = 0 + OUT = 1 + LOW = 0 + HIGH = 1 + + ft232h_gpio = None + + def __init__(self, pin_id=None): + # setup GPIO controller if not done yet + # use one provided by I2C as default + if not Pin.ft232h_gpio: + from pyftdi.i2c import I2cController + i2c = I2cController() + i2c.configure("ftdi:///1") + Pin.ft232h_gpio = i2c.get_gpio() + # check if pin is valid + if pin_id: + if Pin.ft232h_gpio.all_pins & 1 << pin_id == 0: + raise ValueError("Can not use pin {} as GPIO.".format(pin_id)) + # ID is just bit position + self.id = pin_id + + def init(self, mode=IN, pull=None): + if not self.id: + raise RuntimeError("Can not init a None type pin.") + # FT232H does't have configurable internal pulls? + if pull: + raise ValueError("Internal pull up/down not currently supported.") + pin_mask = Pin.ft232h_gpio.pins | 1 << self.id + current = Pin.ft232h_gpio.direction + if mode == self.OUT: + current |= 1 << self.id + else: + current &= ~(1 << self.id) + Pin.ft232h_gpio.set_direction(pin_mask, current) + + def value(self, val=None): + if not self.id: + raise RuntimeError("Can not access a None type pin.") + current = Pin.ft232h_gpio.read(with_output=True) + # read + if val is None: + return 1 if current & 1 << self.id != 0 else 0 + # write + elif val in (self.LOW, self.HIGH): + if val == self.HIGH: + current |= 1 << self.id + else: + current &= ~(1 << self.id) + # must mask out any input pins + Pin.ft232h_gpio.write(current & Pin.ft232h_gpio.direction) + # release the kraken + else: + raise RuntimeError("Invalid value for pin") + +# create pin instances for each pin +# D0 to D3 are used by I2C/SPI +D4 = Pin(4) +D5 = Pin(5) +D6 = Pin(6) +D7 = Pin(7) +C0 = Pin(8) +C1 = Pin(9) +C2 = Pin(10) +C3 = Pin(11) +C4 = Pin(12) +C5 = Pin(13) +C6 = Pin(14) +C7 = Pin(15) +# C8 and C9 are not GPIO + +# create None type pins for I2C and SPI since they are expected to be defined +SCL = Pin() +SDA = Pin() +SCK = SCLK = Pin() +MOSI = Pin() +MISO = Pin() diff --git a/src/adafruit_blinka/microcontroller/ft232h/spi.py b/src/adafruit_blinka/microcontroller/ft232h/spi.py new file mode 100644 index 0000000..a260e72 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/ft232h/spi.py @@ -0,0 +1,54 @@ +from adafruit_blinka.microcontroller.ft232h.pin import Pin + +class SPI: + MSB = 0 + + def __init__(self): + from pyftdi.spi import SpiController + self._spi = SpiController(cs_count=1) + self._spi.configure('ftdi:///1') + self._port = self._spi.get_port(0) + self._port.set_frequency(100000) + self._port._cpol = 0 + self._port._cpha = 0 + # Change GPIO controller to SPI + Pin.ft232h_gpio = self._spi.get_gpio() + + def init(self, baudrate=100000, polarity=0, phase=0, bits=8, + firstbit=MSB, sck=None, mosi=None, miso=None): + self._port.set_frequency(baudrate) + # FTDI device can only support mode 0 and mode 2 + # due to the limitation of MPSSE engine. + # This means CPHA must = 0 + self._port._cpol = polarity + if phase != 0: + raise ValueError("Only SPI phase 0 is supported by FT232H.") + self._port._cpha = phase + + @property + def frequency(self): + return self._port.frequency + + def write(self, buf, start=0, end=None): + end = end if end else len(buf) + chunks, rest = divmod(end - start, self._spi.PAYLOAD_MAX_LENGTH) + for i in range(chunks): + chunk_start = start + i * self._spi.PAYLOAD_MAX_LENGTH + chunk_end = chunk_start + self._spi.PAYLOAD_MAX_LENGTH + self._port.write(buf[chunk_start:chunk_end]) + if rest: + self._port.write(buf[-1*rest:]) + + def readinto(self, buf, start=0, end=None, write_value=0): + end = end if end else len(buf) + result = self._port.read(end-start) + for i, b in enumerate(result): + buf[start+i] = b + + def write_readinto(self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None): + out_end = out_end if out_end else len(buffer_out) + in_end = in_end if in_end else len(buffer_in) + result = self._port.exchange(buffer_out[out_start:out_end], + in_end-in_start, duplex=True) + for i, b in enumerate(result): + buffer_in[in_start+i] = b diff --git a/src/adafruit_blinka/microcontroller/generic_linux/i2c.py b/src/adafruit_blinka/microcontroller/generic_linux/i2c.py index e309e9e..ed8c8b8 100644 --- a/src/adafruit_blinka/microcontroller/generic_linux/i2c.py +++ b/src/adafruit_blinka/microcontroller/generic_linux/i2c.py @@ -58,9 +58,7 @@ class I2C: self.readfrom_into(address, buffer_in, start=in_start, end=in_end) else: # To generate without a stop, do in one block transaction - if out_end-out_start != 1: - raise NotImplementedError("Currently can only write a single byte in writeto_then_readfrom") - readin = self._i2c_bus.read_i2c_block_data(address, buffer_out[out_start:out_end][0], in_end-in_start) + readin = self._i2c_bus.read_i2c_block_data(address, buffer_out[out_start:out_end], in_end-in_start) for i in range(in_end-in_start): buffer_in[i+in_start] = readin[i] diff --git a/src/adafruit_blinka/microcontroller/generic_linux/spi.py b/src/adafruit_blinka/microcontroller/generic_linux/spi.py index 71f74c8..f2ffa82 100755 --- a/src/adafruit_blinka/microcontroller/generic_linux/spi.py +++ b/src/adafruit_blinka/microcontroller/generic_linux/spi.py @@ -33,14 +33,12 @@ class SPI: self.chip = detector.chip def set_no_cs(self): - # Linux SPI driver for AM33XX chip in BeagleBone and PocketBeagle - # does not support setting SPI_NO_CS mode bit (issue #104) - if not self.chip.AM33XX and not self.chip.IMX8MX and not self.chip.SAMA5 \ - and not self.chip.APQ8016: - try: - self._spi.no_cs = True # this doesn't work but try anyways - except AttributeError: - pass + # No kernel seems to support this, so we're just going to pass + pass + + @property + def frequency(self): + return self.baudrate def write(self, buf, start=0, end=None): if not buf: diff --git a/src/adafruit_blinka/microcontroller/mcp2221/__init__.py b/src/adafruit_blinka/microcontroller/mcp2221/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/adafruit_blinka/microcontroller/mcp2221/i2c.py b/src/adafruit_blinka/microcontroller/mcp2221/i2c.py new file mode 100644 index 0000000..9ebb5b6 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/mcp2221/i2c.py @@ -0,0 +1,23 @@ +from .mcp2221 import mcp2221 + +class I2C: + + def __init__(self, *, frequency=100000): + self._mcp2221 = mcp2221 + self._mcp2221.i2c_configure(frequency) + + def scan(self): + return self._mcp2221.i2c_scan() + + def writeto(self, address, buffer, *, start=0, end=None, stop=True): + self._mcp2221.i2c_writeto(address, buffer, start=start, end=end) + + def readfrom_into(self, address, buffer, *, start=0, end=None, stop=True): + self._mcp2221.i2c_readfrom_into(address, buffer, start=start, end=end) + + def writeto_then_readfrom(self, address, buffer_out, buffer_in, *, + out_start=0, out_end=None, + in_start=0, in_end=None, stop=False): + self._mcp2221.i2c_writeto_then_readfrom(address, buffer_out, buffer_in, + out_start=out_start, out_end=out_end, + in_start=in_start, in_end=in_end) diff --git a/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py b/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py new file mode 100644 index 0000000..aae81e5 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py @@ -0,0 +1,315 @@ +import time +import hid + +# from the C driver +# http://ww1.microchip.com/downloads/en/DeviceDoc/mcp2221_0_1.tar.gz +# others (???) determined during driver developement +# pylint: disable=bad-whitespace +RESP_ERR_NOERR = 0x00 +RESP_ADDR_NACK = 0x25 +RESP_READ_ERR = 0x7F +RESP_READ_COMPL = 0x55 +RESP_READ_PARTIAL = 0x54 # ??? +RESP_I2C_IDLE = 0x00 +RESP_I2C_START_TOUT = 0x12 +RESP_I2C_RSTART_TOUT = 0x17 +RESP_I2C_WRADDRL_TOUT = 0x23 +RESP_I2C_WRADDRL_WSEND = 0x21 +RESP_I2C_WRADDRL_NACK = 0x25 +RESP_I2C_WRDATA_TOUT = 0x44 +RESP_I2C_RDDATA_TOUT = 0x52 +RESP_I2C_STOP_TOUT = 0x62 + +RESP_I2C_MOREDATA = 0x43 # ??? +RESP_I2C_PARTIALDATA = 0x41 # ??? +RESP_I2C_WRITINGNOSTOP = 0x45 # ??? + +MCP2221_RETRY_MAX = 50 +MCP2221_MAX_I2C_DATA_LEN = 60 +MASK_ADDR_NACK = 0x40 +# pylint: enable=bad-whitespace + +class MCP2221: + + VID = 0x04D8 + PID = 0x00DD + + GP_GPIO = 0b000 + GP_DEDICATED = 0b001 + GP_ALT0 = 0b010 + GP_ALT1 = 0b011 + GP_ALT2 = 0b100 + + def __init__(self): + self._hid = hid.device() + self._hid.open(MCP2221.VID, MCP2221.PID) + self._reset() + time.sleep(0.25) + + def _hid_xfer(self, report, response=True): + # first byte is report ID, which =0 for MCP2221 + # remaing bytes = 64 byte report data + # https://github.com/libusb/hidapi/blob/083223e77952e1ef57e6b77796536a3359c1b2a3/hidapi/hidapi.h#L185 + self._hid.write(b'\0' + report + b'\0'*(64-len(report))) + if response: + # return is 64 byte response report + return self._hid.read(64) + + #---------------------------------------------------------------- + # MISC + #---------------------------------------------------------------- + def gp_get_mode(self, pin): + return self._hid_xfer(b'\x61')[22+pin] & 0x07 + + def gp_set_mode(self, pin, mode): + # get current settings + current = self._hid_xfer(b'\x61') + # empty report, this is safe since 0's = no change + report = bytearray(b'\x60'+b'\x00'*63) + # set the alter GP flag byte + report[7] = 0xFF + # each pin can be set individually + # but all 4 get set at once, so we need to + # transpose current settings + report[8] = current[22] # GP0 + report[9] = current[23] # GP1 + report[10] = current[24] # GP2 + report[11] = current[25] # GP3 + # then change only the one + report[8+pin] = mode & 0x07 + # and make it so + self._hid_xfer(report) + + def _pretty_report(self, report): + print(" 0 1 2 3 4 5 6 7 8 9") + index = 0 + for row in range(7): + print("{} : ".format(row), end='') + for _ in range(10): + print("{:02x} ".format(report[index]), end='') + index += 1 + if index > 63: + break + print() + + def _status_dump(self): + self._pretty_report(self._hid_xfer(b'\x10')) + + def _sram_dump(self): + self._pretty_report(self._hid_xfer(b'\x61')) + + def _reset(self): + self._hid_xfer(b'\x70\xAB\xCD\xEF', response=False) + start = time.monotonic() + while time.monotonic() - start < 5: + try: + self._hid.open(MCP2221.VID, MCP2221.PID) + except OSError: + # try again + time.sleep(0.1) + continue + return + raise OSError("open failed") + + #---------------------------------------------------------------- + # GPIO + #---------------------------------------------------------------- + def gpio_set_direction(self, pin, mode): + report = bytearray(b'\x50'+b'\x00'*63) # empty set GPIO report + offset = 4 * (pin + 1) + report[offset] = 0x01 # set pin direction + report[offset+1] = mode # to this + self._hid_xfer(report) + + def gpio_set_pin(self, pin, value): + report = bytearray(b'\x50'+b'\x00'*63) # empty set GPIO report + offset = 2 + 4 * pin + report[offset] = 0x01 # set pin value + report[offset+1] = value # to this + self._hid_xfer(report) + + def gpio_get_pin(self, pin): + resp = self._hid_xfer(b'\x51') + offset = 2 + 2 * pin + if resp[offset] == 0xEE: + raise RuntimeError("Pin is not set for GPIO operation.") + else: + return resp[offset] + + #---------------------------------------------------------------- + # I2C + #---------------------------------------------------------------- + def _i2c_status(self): + resp = self._hid_xfer(b'\x10') + if resp[1] != 0: + raise RuntimeError("Couldn't get I2C status") + return resp + + def _i2c_state(self): + return self._i2c_status()[8] + + def _i2c_cancel(self): + resp = self._hid_xfer(b'\x10\x00\x10') + if resp[1] != 0x00: + raise RuntimeError("Couldn't cancel I2C") + if resp[2] == 0x10: + # bus release will need "a few hundred microseconds" + time.sleep(0.001) + + def _i2c_write(self, cmd, address, buffer, start=0, end=None): + if self._i2c_state() != 0x00: + self._i2c_cancel() + + end = end if end else len(buffer) + length = end - start + retries = 0 + + while (end - start) > 0: + chunk = min(end - start, MCP2221_MAX_I2C_DATA_LEN) + # write out current chunk + resp = self._hid_xfer(bytes([cmd, + length & 0xFF, + (length >> 8) & 0xFF, + address << 1]) + + buffer[start:(start+chunk)]) + # check for success + if resp[1] != 0x00: + if resp[2] in (RESP_I2C_START_TOUT, + RESP_I2C_WRADDRL_TOUT, + RESP_I2C_WRADDRL_NACK, + RESP_I2C_WRDATA_TOUT, + RESP_I2C_STOP_TOUT): + raise RuntimeError("Unrecoverable I2C state failure") + retries += 1 + if retries >= MCP2221_RETRY_MAX: + raise RuntimeError("I2C write error, max retries reached.") + time.sleep(0.001) + continue # try again + # yay chunk sent! + while self._i2c_state() == RESP_I2C_PARTIALDATA: + time.sleep(0.001) + start += chunk + retries = 0 + + # check status in another loop + for _ in range(MCP2221_RETRY_MAX): + status = self._i2c_status() + if status[20] & MASK_ADDR_NACK: + raise RuntimeError("I2C slave address was NACK'd") + usb_cmd_status = status[8] + if usb_cmd_status == 0: + break + if usb_cmd_status == RESP_I2C_WRITINGNOSTOP and cmd == 0x94: + break # this is OK too! + if usb_cmd_status in (RESP_I2C_START_TOUT, + RESP_I2C_WRADDRL_TOUT, + RESP_I2C_WRADDRL_NACK, + RESP_I2C_WRDATA_TOUT, + RESP_I2C_STOP_TOUT): + raise RuntimeError("Unrecoverable I2C state failure") + time.sleep(0.001) + else: + raise RuntimeError("I2C write error: max retries reached.") + # whew success! + + def _i2c_read(self, cmd, address, buffer, start=0, end=None): + if self._i2c_state() not in (RESP_I2C_WRITINGNOSTOP, 0): + self._i2c_cancel() + + end = end if end else len(buffer) + length = end - start + + # tell it we want to read + resp = self._hid_xfer(bytes([cmd, + length & 0xFF, + (length >> 8) & 0xFF, + (address << 1) | 0x01])) + + # check for success + if resp[1] != 0x00: + raise RuntimeError("Unrecoverable I2C read failure") + + # and now the read part + while (end - start) > 0: + for retry in range(MCP2221_RETRY_MAX): + # the actual read + resp = self._hid_xfer(b'\x40') + # check for success + if resp[1] == RESP_I2C_PARTIALDATA: + time.sleep(0.001) + continue + if resp[1] != 0x00: + raise RuntimeError("Unrecoverable I2C read failure") + if resp[2] == RESP_ADDR_NACK: + raise RuntimeError("I2C NACK") + if resp[3] == 0x00 and resp[2] == 0x00: + break + if resp[3] == RESP_READ_ERR: + time.sleep(0.001) + continue + if resp[2] in (RESP_READ_COMPL, RESP_READ_PARTIAL): + break + + # move data into buffer + chunk = min(end - start, 60) + for i, k in enumerate(range(start, start+chunk)): + buffer[k] = resp[4 + i] + start += chunk + + def i2c_configure(self, baudrate=100000): + self._hid_xfer(bytes([0x10, # set parameters + 0x00, # don't care + 0x00, # no effect + 0x20, # next byte is clock divider + 12000000 // baudrate - 3])) + + def i2c_writeto(self, address, buffer, *, start=0, end=None): + self._i2c_write(0x90, address, buffer, start, end) + + def i2c_readfrom_into(self, address, buffer, *, start=0, end=None): + self._i2c_read(0x91, address, buffer, start, end) + + def i2c_writeto_then_readfrom(self, address, out_buffer, in_buffer, *, + out_start=0, out_end=None, + in_start=0, in_end=None): + self._i2c_write(0x94, address, out_buffer, out_start, out_end) + self._i2c_read(0x93, address, in_buffer, in_start, in_end) + + def i2c_scan(self, *, start=0, end=0x79): + found = [] + for addr in range(start, end+1): + # try a write + try: + self.i2c_writeto(addr, b'\x00') + except RuntimeError: # no reply! + continue + # store if success + found.append(addr) + return found + + #---------------------------------------------------------------- + # ADC + #---------------------------------------------------------------- + def adc_configure(self, vref=0): + report = bytearray(b'\x60'+b'\x00'*63) + report[5] = 1 << 7 | (vref & 0b111) + self._hid_xfer(report) + + def adc_read(self, pin): + resp = self._hid_xfer(b'\x10') + return resp[49 + 2 * pin] << 8 | resp[48 + 2 * pin] + + #---------------------------------------------------------------- + # DAC + #---------------------------------------------------------------- + def dac_configure(self, vref=0): + report = bytearray(b'\x60'+b'\x00'*63) + report[3] = 1 << 7 | (vref & 0b111) + self._hid_xfer(report) + + def dac_write(self, pin, value): + report = bytearray(b'\x60'+b'\x00'*63) + report[4] = 1 << 7 | (value & 0b11111) + self._hid_xfer(report) + +mcp2221 = MCP2221() diff --git a/src/adafruit_blinka/microcontroller/mcp2221/pin.py b/src/adafruit_blinka/microcontroller/mcp2221/pin.py new file mode 100644 index 0000000..139d8b6 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/mcp2221/pin.py @@ -0,0 +1,81 @@ +from .mcp2221 import mcp2221 + +class Pin: + """A basic Pin class for use with MCP2221.""" + + # pin modes + OUT = 0 + IN = 1 + ADC = 2 + DAC = 3 + # pin values + LOW = 0 + HIGH = 1 + + def __init__(self, pin_id=None): + self.id = pin_id + self._mode = None + + def init(self, mode=IN, pull=None): + if self.id is None: + raise RuntimeError("Can not init a None type pin.") + if mode in (Pin.IN, Pin.OUT): + # All pins can do GPIO + mcp2221.gp_set_mode(self.id, mcp2221.GP_GPIO) + mcp2221.gpio_set_direction(self.id, mode) + elif mode == Pin.ADC: + # ADC only available on these pins + if self.id not in (1, 2, 3): + raise ValueError("Pin does not have ADC capabilities") + mcp2221.gp_set_mode(self.id, mcp2221.GP_ALT0) + mcp2221.adc_configure() + elif mode == Pin.DAC: + # DAC only available on these pins + if self.id not in (2, 3): + raise ValueError("Pin does not have DAC capabilities") + mcp2221.gp_set_mode(self.id, mcp2221.GP_ALT1) + mcp2221.dac_configure() + else: + raise ValueError("Incorrect pin mode: {}".format(mode)) + self._mode = mode + + def value(self, val=None): + # Digital In / Out + if self._mode in (Pin.IN, Pin.OUT): + # digital read + if val is None: + return mcp2221.gpio_get_pin(self.id) + # digital write + elif val in (Pin.LOW, Pin.HIGH): + mcp2221.gpio_set_pin(self.id, val) + # nope + else: + raise ValueError("Invalid value for pin.") + # Analog In + elif self._mode == Pin.ADC: + if val is None: + # MCP2221 ADC is 10 bit, scale to 16 bit per CP API + return mcp2221.adc_read(self.id) * 64 + else: + # read only + raise AttributeError("'AnalogIn' object has no attribute 'value'") + # Analog Out + elif self._mode == Pin.DAC: + if val is None: + # write only + raise AttributeError("unreadable attribute") + else: + # scale 16 bit value to MCP2221 5 bit DAC (yes 5 bit) + mcp2221.dac_write(self.id, val // 2048) + else: + raise RuntimeError("No action for mode {} with value {}".format(self._mode, val)) + + +# create pin instances for each pin +G0 = Pin(0) +G1 = Pin(1) +G2 = Pin(2) +G3 = Pin(3) + +SCL = Pin() +SDA = Pin() \ No newline at end of file diff --git a/src/adafruit_blinka/microcontroller/nova/__init__.py b/src/adafruit_blinka/microcontroller/nova/__init__.py new file mode 100644 index 0000000..12ccf0c --- /dev/null +++ b/src/adafruit_blinka/microcontroller/nova/__init__.py @@ -0,0 +1,24 @@ +class Connection: + __instance = None + @staticmethod + def getInstance(): + """ Static access method. """ + if Connection.__instance is None: + Connection() + return Connection.__instance + + def __init__(self): + """ Virtually private constructor. """ + if Connection.__instance is not None: + raise Exception("This class is a singleton!") + + from binhoHostAdapter import binhoHostAdapter + from binhoHostAdapter import binhoUtilities + + utilities = binhoUtilities.binhoUtilities() + devices = utilities.listAvailableDevices() + + if len(devices) > 0: + Connection.__instance = binhoHostAdapter.binhoHostAdapter(devices[0]) + else: + raise RuntimeError('No Binho Nova found!') diff --git a/src/adafruit_blinka/microcontroller/nova/i2c.py b/src/adafruit_blinka/microcontroller/nova/i2c.py new file mode 100644 index 0000000..1919070 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/nova/i2c.py @@ -0,0 +1,75 @@ +class I2C: + + def __init__(self, *, frequency=400000): + from adafruit_blinka.microcontroller.nova import Connection + self._nova = Connection.getInstance() + self._nova.setNumericalBase(10) + self._nova.setOperationMode(0, "I2C") + self._nova.setPullUpStateI2C(0, "EN") + self._nova.setClockI2C(0, frequency) + + def scan(self): + + scanResults = [] + + for i in range(8, 121): + result = self._nova.scanAddrI2C(0, i<<1) + + resp = result.split(" ") + + if resp[3] == 'OK': + scanResults.append(i) + + return scanResults + + def writeto(self, address, buffer, *, start=0, end=None, stop=True): + + end = end if end else len(buffer) + + self._nova.startI2C(0, address<<1) + + for i in range(start, end): + self._nova.writeByteI2C(0, buffer[i]) + + if stop: + self._nova.endI2C(0) + else: + self._nova.endI2C(0, True) + + def readfrom_into(self, address, buffer, *, start=0, end=None, stop=True): + + end = end if end else len(buffer) + + result = self._nova.readBytesI2C(0, address<<1, len(buffer[start:end])) + + if result != "-NG": + resp = result.split(" ") + + for i in range(len(buffer[start:end])): + buffer[start+i] = int(resp[2+i]) + else: + raise RuntimeError("Received error response from Binho Nova, result = " + result) + + def writeto_then_readfrom(self, address, buffer_out, buffer_in, *, + out_start=0, out_end=None, + in_start=0, in_end=None, stop=False): + + out_end = out_end if out_end else len(buffer_out) + in_end = in_end if in_end else len(buffer_in) + + self._nova.startI2C(0, address<<1) + + for i in range(out_start, out_end): + self._nova.writeByteI2C(0, buffer_out[i]) + + self._nova.endI2C(0, True) + + result = self._nova.readBytesI2C(0, address<<1, len(buffer_in[in_start:in_end])) + + if result != "-NG": + resp = result.split(" ") + + for i in range(len(buffer_in[in_start:in_end])): + buffer_in[in_start+i] = int(resp[2+i]) + else: + raise RuntimeError("Received error response from Binho Nova, result = " + result) diff --git a/src/adafruit_blinka/microcontroller/nova/pin.py b/src/adafruit_blinka/microcontroller/nova/pin.py new file mode 100644 index 0000000..235e4ec --- /dev/null +++ b/src/adafruit_blinka/microcontroller/nova/pin.py @@ -0,0 +1,72 @@ +class Pin: + """A basic Pin class for use with Binho Nova.""" + + IN = 'DIN' + OUT = 'DOUT' + AIN = 'AIN' + AOUT = 'AOUT' + PWM = 'PWM' + LOW = 0 + HIGH = 1 + + _nova = None + + def __init__(self, pin_id=None): + if not Pin._nova: + from adafruit_blinka.microcontroller.nova import Connection + Pin._nova = Connection.getInstance() + # check if pin is valid + if pin_id > 4: + raise ValueError("Invalid pin {}.".format(pin_id)) + + self.id = pin_id + + def init(self, mode=IN, pull=None): + if self.id is None: + raise RuntimeError("Can not init a None type pin.") + # Nova does't have configurable internal pulls for + if pull: + raise ValueError("Internal pull up/down not currently supported.") + Pin._nova.setIOpinMode(self.id, mode) + + def value(self, val=None): + if self.id is None: + raise RuntimeError("Can not access a None type pin.") + # read + if val is None: + return int(Pin._nova.getIOpinValue(self.id).split('VALUE ')[1]) + # write + if val in (self.LOW, self.HIGH): + Pin._nova.setIOpinValue(self.id, val) + else: + raise RuntimeError("Invalid value for pin") + +# create pin instances for each pin +IO0 = Pin(0) +IO1 = Pin(1) +IO2 = Pin(2) +IO3 = Pin(3) +IO4 = Pin(4) + +SCL = IO2 +SDA = IO0 +SCK = SCLK = IO3 +MOSI = IO4 +MISO = IO2 +SS0 = IO0 +SS1 = IO1 + +PWM0 = IO0 +# No PWM support on IO1 +PWM2 = IO2 +PWM3 = IO3 +PWM4 = IO4 + +# orderd as (channel, pin), id +pwmOuts = (((1, 0), PWM0), ((1, 2), PWM2), ((1, 3), PWM3), ((1, 4), PWM4)) + +UART1_TX = IO4 +UART1_RX = IO3 + +# ordered as uartId, txId, rxId +uartPorts = ((0, UART1_TX, UART1_RX), ) diff --git a/src/adafruit_blinka/microcontroller/nova/pwmout.py b/src/adafruit_blinka/microcontroller/nova/pwmout.py new file mode 100644 index 0000000..6af2de8 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/nova/pwmout.py @@ -0,0 +1,205 @@ + +try: + from microcontroller.pin import pwmOuts +except ImportError: + raise RuntimeError("No PWM outputs defined for this board") + +from microcontroller.pin import Pin + +class PWMError(IOError): + """Base class for PWM errors.""" + pass + + +class PWMOut(object): + # Nova instance + _nova = None + MAX_CYCLE_LEVEL = 1024 + + def __init__(self, pin, *, frequency=750, duty_cycle=0, variable_frequency=False): + """Instantiate a PWM object and open the sysfs PWM corresponding to the + specified channel and pin. + + Args: + pin (Pin): CircuitPython Pin object to output to + duty_cycle (int) : The fraction of each pulse which is high. 16-bit + frequency (int) : target frequency in Hertz (32-bit) + variable_frequency (bool) : True if the frequency will change over time + + Returns: + PWMOut: PWMOut object. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if `channel` or `pin` types are invalid. + ValueError: if PWM channel does not exist. + + """ + if PWMOut._nova is None: + from adafruit_blinka.microcontroller.nova import Connection + PWMOut._nova = Connection.getInstance() + + PWMOut._nova.setOperationMode(0, 'IO') + self._pwmpin = None + self._open(pin, duty_cycle, frequency, variable_frequency) + + def __del__(self): + self.deinit() + + def __enter__(self): + return self + + def __exit__(self, t, value, traceback): + self.deinit() + + def _open(self, pin, duty=0, freq=750, variable_frequency=False): + self._channel = None + for pwmpair in pwmOuts: + if pwmpair[1] == pin: + self._channel = pwmpair[0][0] + self._pwmpin = pwmpair[0][1] + + self._pin = pin + if self._channel is None: + raise RuntimeError("No PWM channel found for this Pin") + + PWMOut._nova.setIOpinMode(self._pwmpin, Pin.PWM) + + # set frequency + self.frequency = freq + # set period + self._period = self._get_period() + + # set duty + self.duty_cycle = duty + + self._set_enabled(True) + + def deinit(self): + try: + """Deinit the Nova PWM.""" + if self._channel is not None: + #self.duty_cycle = 0 + self._set_enabled(False) # make to disable before unexport + + except Exception as e: + # due to a race condition for which I have not yet been + # able to find the root cause, deinit() often fails + # but it does not effect future usage of the pwm pin + print("warning: failed to deinitialize pwm pin {0}:{1} due to: {2}\n".format(self._channel, self._pwmpin, type(e).__name__)) + finally: + self._channel = None + self._pwmpin = None + + def _is_deinited(self): + if self._pwmpin is None: + raise ValueError("Object has been deinitialize and can no longer " + "be used. Create a new object.") + + # Mutable properties + + def _get_period(self): + return 1.0 / self._get_frequency() + + def _set_period(self, period): + if not isinstance(period, (int, float)): + raise TypeError("Invalid period type, should be int or float.") + + self._set_frequency(1.0 / period) + + period = property(_get_period, _set_period) + + """Get or set the PWM's output period in seconds. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + + :type: int, float + """ + + def _get_duty_cycle(self): + duty_cycle = Pin._nova.getIOpinValue(self._pwmpin) + + # Convert duty cycle to ratio from 0.0 to 1.0 + duty_cycle = duty_cycle / PWMOut.MAX_CYCLE_LEVEL + + # convert to 16-bit + duty_cycle = int(duty_cycle * 65535) + return duty_cycle + + def _set_duty_cycle(self, duty_cycle): + if not isinstance(duty_cycle, (int, float)): + raise TypeError("Invalid duty cycle type, should be int or float.") + + # convert from 16-bit + duty_cycle /= 65535.0 + if not 0.0 <= duty_cycle <= 1.0: + raise ValueError("Invalid duty cycle value, should be between 0.0 and 1.0.") + + # Convert duty cycle from ratio to 1024 levels + duty_cycle = duty_cycle * PWMOut.MAX_CYCLE_LEVEL + + # Set duty cycle + Pin._nova.setIOpinValue(self._pwmpin, duty_cycle) + + duty_cycle = property(_get_duty_cycle, _set_duty_cycle) + """Get or set the PWM's output duty cycle as a ratio from 0.0 to 1.0. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + ValueError: if value is out of bounds of 0.0 to 1.0. + + :type: int, float + """ + + def _get_frequency(self): + return int(PWMOut._nova.getIOpinPWMFreq(self._pwmpin).split('PWMFREQ ')[1]) + + def _set_frequency(self, frequency): + if not isinstance(frequency, (int, float)): + raise TypeError("Invalid frequency type, should be int or float.") + + PWMOut._nova.setIOpinPWMFreq(self._pwmpin, frequency) + + frequency = property(_get_frequency, _set_frequency) + """Get or set the PWM's output frequency in Hertz. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + + :type: int, float + """ + + def _get_enabled(self): + enabled = self._enable + + if enabled == "1": + return True + elif enabled == "0": + return False + + raise PWMError(None, "Unknown enabled value: \"%s\"" % enabled) + + def _set_enabled(self, value): + if not isinstance(value, bool): + raise TypeError("Invalid enabled type, should be string.") + self._enable = value + if not self._enable: + self._set_duty_cycle(0.0) + """Get or set the PWM's output enabled state. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not bool. + + :type: bool + """ + + # String representation + + def __str__(self): + return "PWM%d, pin %s (freq=%f Hz, duty_cycle=%f%%)" % \ + (self._pin, self._pin, self.frequency, self.duty_cycle * 100,) diff --git a/src/adafruit_blinka/microcontroller/nova/spi.py b/src/adafruit_blinka/microcontroller/nova/spi.py new file mode 100644 index 0000000..3926922 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/nova/spi.py @@ -0,0 +1,74 @@ +class SPI: + MSB = 0 + PAYLOAD_MAX_LENGTH = 64 + + def __init__(self, clock): + from adafruit_blinka.microcontroller.nova import Connection + self._nova = Connection.getInstance() + self._nova.setNumericalBase(10) + self._nova.setOperationMode(0, 'SPI') + self._nova.setClockSPI(0, clock) + self._nova.setModeSPI(0, 0) + self._nova.setIOpinMode(0, 'DOUT') + self._nova.setIOpinMode(1, 'DOUT') + self._nova.beginSPI(0) + + # Cpol and Cpha set by mode + # Mode Cpol Cpha + # 0 0 0 + # 1 0 1 + # 2 1 0 + # 3 1 1 + + def init(self, baudrate=100000, polarity=0, phase=0, bits=8, + firstbit=MSB, sck=None, mosi=None, miso=None): + #print("baudrate: " + str(baudrate)) + #print("mode: " + str((polarity<<1) | (phase))) + self._nova.setClockSPI(0, baudrate) + self._nova.setModeSPI(0, (polarity<<1) | (phase)) + + @staticmethod + def get_received_data(lineOutput): + return (lineOutput.split('RXD ')[1]) + + @property + def frequency(self): + return self._nova.getClockSPI(0).split('CLK ')[1] + + def write(self, buf, start=0, end=None): + end = end if end else len(buf) + chunks, rest = divmod(end - start, self.PAYLOAD_MAX_LENGTH) + for i in range(chunks): + chunk_start = start + i * self.PAYLOAD_MAX_LENGTH + chunk_end = chunk_start + self.PAYLOAD_MAX_LENGTH + buffer_data = buf[chunk_start:chunk_end] + self._nova.clearBuffer(0) + self._nova.writeToBuffer(0, 0, buffer_data) + self._nova.transferBufferSPI(0, chunk_end - chunk_start + 1) + if rest: + buffer_data = buf[-1*rest:] + self._nova.clearBuffer(0) + self._nova.writeToBuffer(0, 0, buffer_data) + self._nova.transferBufferSPI(0, rest) + + def readinto(self, buf, start=0, end=None, write_value=0): + end = end if end else len(buf) + for i in range(start, end): + buf[start+i] = int(self.get_received_data(self._nova.transferSPI(0, write_value))) + + def write_readinto(self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None): + out_end = out_end if out_end else len(buffer_out) + in_end = in_end if in_end else len(buffer_in) + readlen = in_end-in_start + writelen = out_end-out_start + if readlen > writelen: + # resize out and pad with 0's + tmp = bytearray(buffer_out) + tmp.extend([0] * (readlen - len(buffer_out))) + buffer_out = tmp + i = 0 + for data_out in buffer_out: + data_in = int(self.get_received_data(self._nova.transferSPI(0, data_out))) + if i < readlen: + buffer_in[in_start+i] = data_in + i += 1 diff --git a/src/adafruit_blinka/microcontroller/nova/uart.py b/src/adafruit_blinka/microcontroller/nova/uart.py new file mode 100644 index 0000000..253d7a7 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/nova/uart.py @@ -0,0 +1,65 @@ +import time + +class UART(): + ESCAPE_SEQUENCE = "+++UART0" + def __init__(self, + portid, + baudrate=9600, + bits=8, + parity=None, + stop=1, + timeout=1000, + read_buf_len=None, + flow=None): + from adafruit_blinka.microcontroller.nova import Connection + self._nova = Connection.getInstance() + + self._id = portid + self._baudrate = baudrate + self._parity = parity + self._bits = bits + self._stop = stop + self._timeout = timeout + + if flow is not None: # default 0 + raise NotImplementedError( + "Parameter '{}' unsupported on Binho Nova".format( + "flow")) + + self._nova.setOperationMode(self._id, 'UART') + self._nova.setBaudRateUART(self._id, baudrate) + self._nova.setDataBitsUART(self._id, bits) + self._nova.setParityUART(self._id, parity) + self._nova.setStopBitsUART(self._id, stop) + self._nova.setEscapeSequenceUART(self._id, UART.ESCAPE_SEQUENCE) + self._nova.beginBridgeUART(self._id) + + def deinit(self): + self._nova.writeBridgeUART(UART.ESCAPE_SEQUENCE) + self._nova.stopBridgeUART(UART.ESCAPE_SEQUENCE) + + def read(self, nbytes=None): + if nbytes is None: + return None + data = bytearray() + for i in range(nbytes): + data.append(ord(self._nova.readBridgeUART())) + return data + + def readinto(self, buf, nbytes=None): + if nbytes is None: + return None + for i in range(nbytes): + buf.append(ord(self._nova.readBridgeUART())) + return buf + + def readline(self): + out = self._nova.readBridgeUART() + line = out + while out != '\r': + out = self._nova.readBridgeUART() + line += out + return line + + def write(self, buf): + return self._nova.writeBridgeUART(buf) diff --git a/src/adafruit_blinka/microcontroller/tegra/t186/pin.py b/src/adafruit_blinka/microcontroller/tegra/t186/pin.py index 25ec2e0..f033b5c 100644 --- a/src/adafruit_blinka/microcontroller/tegra/t186/pin.py +++ b/src/adafruit_blinka/microcontroller/tegra/t186/pin.py @@ -1,7 +1,5 @@ import sys import atexit -sys.path.append("/opt/nvidia/jetson-gpio/lib/python") -sys.path.append("/opt/nvidia/jetson-gpio/lib/python/Jetson/GPIO") import Jetson.GPIO as GPIO GPIO.setmode(GPIO.TEGRA_SOC) GPIO.setwarnings(False) # shh! @@ -98,3 +96,6 @@ J05 = Pin('GPIO_AUD0') i2cPorts = ( (1, SCL, SDA), (0, SCL_1, SDA_1), ) + +# ordered as spiId, sckId, mosiId, misoId +spiPorts = ((3, N03, N05, N04), ) diff --git a/src/adafruit_blinka/microcontroller/tegra/t194/pin.py b/src/adafruit_blinka/microcontroller/tegra/t194/pin.py index 2598c51..971474e 100644 --- a/src/adafruit_blinka/microcontroller/tegra/t194/pin.py +++ b/src/adafruit_blinka/microcontroller/tegra/t194/pin.py @@ -1,7 +1,5 @@ import sys import atexit -sys.path.append("/opt/nvidia/jetson-gpio/lib/python") -sys.path.append("/opt/nvidia/jetson-gpio/lib/python/Jetson/GPIO") import Jetson.GPIO as GPIO GPIO.setmode(GPIO.TEGRA_SOC) GPIO.setwarnings(False) # shh! @@ -99,3 +97,6 @@ R00 = Pin('SOC_GPIO44') i2cPorts = ( (8, SCL, SDA), (1, SCL_1, SDA_1), ) + +# ordered as spiId, sckId, mosiId, misoId +spiPorts = ((0, Z03, Z05, Z04), ) diff --git a/src/adafruit_blinka/microcontroller/tegra/t210/pin.py b/src/adafruit_blinka/microcontroller/tegra/t210/pin.py index c6d4b6e..50e2daa 100644 --- a/src/adafruit_blinka/microcontroller/tegra/t210/pin.py +++ b/src/adafruit_blinka/microcontroller/tegra/t210/pin.py @@ -1,7 +1,5 @@ import sys import atexit -sys.path.append("/opt/nvidia/jetson-gpio/lib/python") -sys.path.append("/opt/nvidia/jetson-gpio/lib/python/Jetson/GPIO") import Jetson.GPIO as GPIO GPIO.setmode(GPIO.TEGRA_SOC) GPIO.setwarnings(False) # shh! @@ -119,3 +117,6 @@ E06 = Pin('GPIO_PE6') i2cPorts = ( (0, SCL, SDA), (1, SCL_1, SDA_1), ) + +# ordered as spiId, sckId, mosiId, misoId +spiPorts = ((0, C02, C00, C01), (1, B06, B04, B05)) diff --git a/src/analogio.py b/src/analogio.py new file mode 100644 index 0000000..229495d --- /dev/null +++ b/src/analogio.py @@ -0,0 +1,52 @@ +""" +`analogio` - Analog input and output control +================================================= +See `CircuitPython:analogio` in CircuitPython for more details. +* Author(s): Carter Nelson +""" + +from adafruit_blinka.agnostic import board_id, detector + +# pylint: disable=ungrouped-imports,wrong-import-position + +if detector.board.microchip_mcp2221: + from adafruit_blinka.microcontroller.mcp2221.pin import Pin +else: + raise NotImplementedError("analogio not supported for this board.") + +from adafruit_blinka import ContextManaged + +class AnalogIn(ContextManaged): + + def __init__(self, pin): + self._pin = Pin(pin.id) + self._pin.init(mode=Pin.ADC) + + @property + def value(self): + return self._pin.value() + + @value.setter + def value(self, value): + # emulate what CircuitPython does + raise AttributeError("'AnalogIn' object has no attribute 'value'") + + def deinit(self): + del self._pin + +class AnalogOut(ContextManaged): + def __init__(self, pin): + self._pin = Pin(pin.id) + self._pin.init(mode=Pin.DAC) + + @property + def value(self): + # emulate what CircuitPython does + raise AttributeError("unreadable attribute") + + @value.setter + def value(self, value): + self._pin.value(value) + + def deinit(self): + del self._pin \ No newline at end of file diff --git a/src/board.py b/src/board.py index 30e526c..d2852ba 100755 --- a/src/board.py +++ b/src/board.py @@ -49,7 +49,7 @@ elif detector.board.any_raspberry_pi_40_pin: elif detector.board.any_raspberry_pi_cm: from adafruit_blinka.board.raspi_cm import * -elif detector.board.RASPBERRY_PI_B_REV1: +elif detector.board.RASPBERRY_PI_A or detector.board.RASPBERRY_PI_B_REV1: from adafruit_blinka.board.raspi_1b_rev1 import * elif detector.board.RASPBERRY_PI_B_REV2: @@ -58,6 +58,12 @@ elif detector.board.RASPBERRY_PI_B_REV2: elif board_id == ap_board.BEAGLEBONE_BLACK: from adafruit_blinka.board.beaglebone_black import * +elif board_id == ap_board.BEAGLEBONE_BLACK_INDUSTRIAL: + from adafruit_blinka.board.beaglebone_black import * + +elif board_id == ap_board.BEAGLEBONE_GREEN_WIRELESS: + from adafruit_blinka.board.beaglebone_black import * + elif board_id == ap_board.BEAGLEBONE_POCKETBEAGLE: from adafruit_blinka.board.beaglebone_pocketbeagle import * @@ -67,6 +73,9 @@ elif board_id == ap_board.ORANGE_PI_PC: elif board_id == ap_board.ORANGE_PI_R1: from adafruit_blinka.board.orangepir1 import * +elif board_id == ap_board.ORANGE_PI_ZERO: + from adafruit_blinka.board.orangepizero import * + elif board_id == ap_board.GIANT_BOARD: from adafruit_blinka.board.giantboard import * @@ -89,11 +98,20 @@ elif board_id == ap_board.ODROID_C2: from adafruit_blinka.board.odroidc2 import * elif board_id == ap_board.ODROID_N2: - from adafruit_blinka.board.odroidn2 import * + from adafruit_blinka.board.odroidn2 import * elif board_id == ap_board.DRAGONBOARD_410C: from adafruit_blinka.board.dragonboard_410c import * +elif board_id == ap_board.FTDI_FT232H: + from adafruit_blinka.board.ftdi_ft232h import * + +elif board_id == ap_board.BINHO_NOVA: + from adafruit_blinka.board.binho_nova import * + +elif board_id == ap_board.MICROCHIP_MCP2221: + from adafruit_blinka.board.microchip_mcp2221 import * + elif board_id == ap_board.SIFIVE_UNLEASHED: from adafruit_blinka.board.sifive_unleashed import * @@ -101,7 +119,7 @@ elif "sphinx" in sys.modules: pass else: - raise NotImplementedError("Board not supported") + raise NotImplementedError("Board not supported {}".format(board_id)) def I2C(): """The singleton I2C interface""" diff --git a/src/busio.py b/src/busio.py index f5991f9..d5ae7c9 100755 --- a/src/busio.py +++ b/src/busio.py @@ -7,6 +7,8 @@ See `CircuitPython:busio` in CircuitPython for more details. * Author(s): cefn """ +import threading + from adafruit_blinka import Enum, Lockable, agnostic from adafruit_blinka.agnostic import board_id, detector import adafruit_platformdetect.board as ap_board @@ -17,20 +19,37 @@ class I2C(Lockable): def init(self, scl, sda, frequency): self.deinit() - if detector.board.any_embedded_linux: + if detector.board.ftdi_ft232h: + from adafruit_blinka.microcontroller.ft232h.i2c import I2C + self._i2c = I2C(frequency=frequency) + return + elif detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.i2c import I2C + self._i2c = I2C(frequency=frequency) + return + elif detector.board.microchip_mcp2221: + from adafruit_blinka.microcontroller.mcp2221.i2c import I2C + self._i2c = I2C(frequency=frequency) + return + elif detector.board.any_embedded_linux: from adafruit_blinka.microcontroller.generic_linux.i2c import I2C as _I2C else: from machine import I2C as _I2C from microcontroller.pin import i2cPorts for portId, portScl, portSda in i2cPorts: - if scl == portScl and sda == portSda: - self._i2c = _I2C(portId, mode=_I2C.MASTER, baudrate=frequency) - break + try: + if scl == portScl and sda == portSda: + self._i2c = _I2C(portId, mode=_I2C.MASTER, baudrate=frequency) + break + except RuntimeError: + pass else: - raise NotImplementedError( - "No Hardware I2C on (scl,sda)={}\nValid UART ports: {}".format((scl, sda), i2cPorts) + raise ValueError( + "No Hardware I2C on (scl,sda)={}\nValid I2C ports: {}".format((scl, sda), i2cPorts) ) + self._lock = threading.RLock() + def deinit(self): try: del self._i2c @@ -38,9 +57,11 @@ class I2C(Lockable): pass def __enter__(self): + self._lock.acquire() return self def __exit__(self, exc_type, exc_value, traceback): + self._lock.release() self.deinit() def scan(self): @@ -72,7 +93,19 @@ class I2C(Lockable): class SPI(Lockable): def __init__(self, clock, MOSI=None, MISO=None): self.deinit() - if detector.board.any_embedded_linux: + if detector.board.ftdi_ft232h: + from adafruit_blinka.microcontroller.ft232h.spi import SPI as _SPI + from adafruit_blinka.microcontroller.ft232h.pin import SCK, MOSI, MISO + self._spi = _SPI() + self._pins = (SCK, MOSI, MISO) + return + elif detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI + from adafruit_blinka.microcontroller.nova.pin import SCK, MOSI, MISO + self._spi = _SPI(clock) + self._pins = (SCK, MOSI, MISO) + return + elif detector.board.any_embedded_linux: from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI else: from machine import SPI as _SPI @@ -85,7 +118,7 @@ class SPI(Lockable): self._pins = (portSck, portMosi, portMiso) break else: - raise NotImplementedError( + raise ValueError( "No Hardware SPI on (SCLK, MOSI, MISO)={}\nValid SPI ports:{}". format((clock, MOSI, MISO), spiPorts)) @@ -96,8 +129,8 @@ class SPI(Lockable): elif detector.board.any_beaglebone: from adafruit_blinka.microcontroller.am335x.pin import Pin from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI - elif board_id == ap_board.ORANGE_PI_PC or board_id == ap_board.ORANGE_PI_R1: - from adafruit_blinka.microcontroller.allwinner_h3.pin import Pin + elif board_id == ap_board.ORANGE_PI_PC or board_id == ap_board.ORANGE_PI_R1 or board_id == ap_board.ORANGE_PI_ZERO: + from adafruit_blinka.microcontroller.allwinner.h3.pin import Pin from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI elif board_id == ap_board.GIANT_BOARD: from adafruit_blinka.microcontroller.sama5.pin import Pin @@ -111,6 +144,24 @@ class SPI(Lockable): elif board_id == ap_board.DRAGONBOARD_410C: from adafruit_blinka.microcontroller.snapdragon.apq8016.pin import Pin from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI + elif board_id == ap_board.JETSON_NANO: + from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI + from adafruit_blinka.microcontroller.tegra.t210.pin import Pin + elif board_id == ap_board.JETSON_TX1: + from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI + from adafruit_blinka.microcontroller.tegra.t210.pin import Pin + elif board_id == ap_board.JETSON_TX2: + from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI + from adafruit_blinka.microcontroller.tegra.t186.pin import Pin + elif board_id == ap_board.JETSON_XAVIER: + from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI + from adafruit_blinka.microcontroller.tegra.t194.pin import Pin + elif detector.board.ftdi_ft232h: + from adafruit_blinka.microcontroller.ft232h.spi import SPI as _SPI + from adafruit_blinka.microcontroller.ft232h.pin import Pin + elif detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI + from adafruit_blinka.microcontroller.nova.pin import Pin else: from machine import SPI as _SPI from machine import Pin @@ -134,6 +185,13 @@ class SPI(Lockable): self._spi = None self._pinIds = None + @property + def frequency(self): + try: + return self._spi.frequency + except AttributeError: + raise NotImplementedError("Frequency attribute not implemented for this platform") + def write(self, buf, start=0, end=None): return self._spi.write(buf, start, end) @@ -163,9 +221,15 @@ class UART(Lockable): flow=None): if detector.board.any_embedded_linux: raise RuntimeError('busio.UART not supported on this platform. Please use pyserial instead.') + elif detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.uart import UART as _UART else: from machine import UART as _UART - from microcontroller.pin import uartPorts + + if detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.pin import uartPorts + else: + from microcontroller.pin import uartPorts self.baudrate = baudrate @@ -198,11 +262,13 @@ class UART(Lockable): ) break else: - raise NotImplementedError( + raise ValueError( "No Hardware UART on (tx,rx)={}\nValid UART ports: {}".format((tx, rx), uartPorts) ) def deinit(self): + if detector.board.binho_nova: + self._uart.deinit() self._uart = None def read(self, nbytes=None): diff --git a/src/digitalio.py b/src/digitalio.py index 6f6e9d1..5dc7daf 100755 --- a/src/digitalio.py +++ b/src/digitalio.py @@ -16,7 +16,7 @@ if detector.chip.BCM2XXX: elif detector.chip.AM33XX: from adafruit_blinka.microcontroller.am335x.pin import Pin elif detector.chip.SUN8I: - from adafruit_blinka.microcontroller.allwinner_h3.pin import Pin + from adafruit_blinka.microcontroller.allwinner.h3.pin import Pin elif detector.chip.SAMA5: from adafruit_blinka.microcontroller.sama5.pin import Pin elif detector.chip.T210: @@ -30,11 +30,17 @@ elif detector.chip.S905: elif detector.chip.S922X: from adafruit_blinka.microcontroller.amlogic.s922x.pin import Pin elif detector.chip.APQ8016: - from adafruit_blinka.microcontroller.snapdragon.apq8016.pin import Pin + from adafruit_blinka.microcontroller.snapdragon.apq8016.pin import Pin elif detector.chip.IMX8MX: from adafruit_blinka.microcontroller.nxp_imx8m.pin import Pin +elif detector.board.ftdi_ft232h: + from adafruit_blinka.microcontroller.ft232h.pin import Pin +elif detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.pin import Pin elif detector.chip.STM32: from machine import Pin +elif detector.board.microchip_mcp2221: + from adafruit_blinka.microcontroller.mcp2221.pin import Pin from adafruit_blinka import Enum, ContextManaged class DriveMode(Enum): diff --git a/src/microcontroller/__init__.py b/src/microcontroller/__init__.py index 5550543..5bef237 100755 --- a/src/microcontroller/__init__.py +++ b/src/microcontroller/__init__.py @@ -33,7 +33,7 @@ elif chip_id == ap_chip.BCM2XXX: elif chip_id == ap_chip.AM33XX: from adafruit_blinka.microcontroller.am335x import * elif chip_id == ap_chip.SUN8I: - from adafruit_blinka.microcontroller.allwinner_h3 import * + from adafruit_blinka.microcontroller.allwinner.h3 import * elif chip_id == ap_chip.SAMA5: from adafruit_blinka.microcontroller.sama5 import * elif chip_id == ap_chip.T210: @@ -50,5 +50,7 @@ elif chip_id == ap_chip.APQ8016: from adafruit_blinka.microcontroller.snapdragon.apq8016.pin import * elif chip_id == ap_chip.IMX8MX: from adafruit_blinka.microcontroller.nxp_imx8m import * +elif chip_id == ap_chip.BINHO: + from adafruit_blinka.microcontroller.nova import * else: raise NotImplementedError("Microcontroller not supported:", chip_id) diff --git a/src/microcontroller/pin.py b/src/microcontroller/pin.py index 5dd250c..ebe9cba 100755 --- a/src/microcontroller/pin.py +++ b/src/microcontroller/pin.py @@ -15,7 +15,7 @@ elif chip_id == ap_chip.BCM2XXX: elif chip_id == ap_chip.AM33XX: from adafruit_blinka.microcontroller.am335x.pin import * elif chip_id == ap_chip.SUN8I: - from adafruit_blinka.microcontroller.allwinner_h3.pin import * + from adafruit_blinka.microcontroller.allwinner.h3.pin import * elif chip_id == ap_chip.SAMA5: from adafruit_blinka.microcontroller.sama5.pin import * elif chip_id == ap_chip.T210: @@ -32,5 +32,11 @@ elif chip_id == ap_chip.APQ8016: from adafruit_blinka.microcontroller.snapdragon.apq8016.pin import * elif chip_id == ap_chip.IMX8MX: from adafruit_blinka.microcontroller.nxp_imx8m.pin import * +elif chip_id == ap_chip.FT232H: + from adafruit_blinka.microcontroller.ft232h.pin import * +elif chip_id == ap_chip.BINHO: + from adafruit_blinka.microcontroller.nova.pin import * +elif chip_id == ap_chip.MCP2221: + from adafruit_blinka.microcontroller.mcp2221.pin import * else: raise NotImplementedError("Microcontroller not supported: ", chip_id) diff --git a/src/micropython.py b/src/micropython.py index b5af9b3..620646f 100755 --- a/src/micropython.py +++ b/src/micropython.py @@ -1,2 +1,14 @@ def const(x): return x + + +def native(f): + return f + + +def viper(f): + raise SyntaxError("invalid micropython decorator") + + +def asm_thumb(f): + raise SyntaxError("invalid micropython decorator") \ No newline at end of file diff --git a/src/pulseio.py b/src/pulseio.py index 42524fc..239a4ba 100644 --- a/src/pulseio.py +++ b/src/pulseio.py @@ -6,3 +6,7 @@ if detector.board.any_coral_board: from adafruit_blinka.microcontroller.generic_linux.sysfs_pwmout import PWMOut if detector.board.any_giant_board: from adafruit_blinka.microcontroller.generic_linux.sysfs_pwmout import PWMOut +if detector.board.any_beaglebone: + from adafruit_blinka.microcontroller.am335x.sysfs_pwmout import PWMOut +if detector.board.binho_nova: + from adafruit_blinka.microcontroller.nova.pwmout import PWMOut