]> Repositories - Adafruit_Blinka-hackapet.git/commitdiff
Rebasing due to this being old
authorMelissa LeBlanc-Williams <melissa@adafruit.com>
Thu, 9 Jan 2020 17:43:01 +0000 (09:43 -0800)
committerMelissa LeBlanc-Williams <melissa@adafruit.com>
Thu, 9 Jan 2020 17:43:01 +0000 (09:43 -0800)
57 files changed:
.travis.yml
README.rst
requirements.txt
setup.py
src/adafruit_blinka/board/beaglebone_pocketbeagle.py
src/adafruit_blinka/board/binho_nova.py [new file with mode: 0644]
src/adafruit_blinka/board/ftdi_ft232h.py [new file with mode: 0644]
src/adafruit_blinka/board/jetson_nano.py
src/adafruit_blinka/board/jetson_tx1.py
src/adafruit_blinka/board/jetson_tx2.py
src/adafruit_blinka/board/jetson_xavier.py
src/adafruit_blinka/board/microchip_mcp2221.py [new file with mode: 0644]
src/adafruit_blinka/board/orangepipc.py
src/adafruit_blinka/board/orangepir1.py
src/adafruit_blinka/board/orangepizero.py [new file with mode: 0644]
src/adafruit_blinka/board/raspi_1b_rev1.py
src/adafruit_blinka/board/raspi_1b_rev2.py
src/adafruit_blinka/board/raspi_40pin.py
src/adafruit_blinka/board/raspi_cm.py
src/adafruit_blinka/board/tritium-h3.py
src/adafruit_blinka/microcontroller/allwinner/__init__.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/allwinner/a64/__init__.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/allwinner/a64/pin.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/allwinner/h3/__init__.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/allwinner/h3/pin.py [moved from src/adafruit_blinka/microcontroller/allwinner_h3/pin.py with 82% similarity]
src/adafruit_blinka/microcontroller/am335x/pin.py
src/adafruit_blinka/microcontroller/am335x/sysfs_pwmout.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/bcm283x/pin.py
src/adafruit_blinka/microcontroller/bcm283x/pulseio/PulseIn.py
src/adafruit_blinka/microcontroller/bcm283x/pulseio/libgpiod_pulsein
src/adafruit_blinka/microcontroller/ft232h/__init__.py [moved from src/adafruit_blinka/microcontroller/allwinner_h3/__init__.py with 100% similarity]
src/adafruit_blinka/microcontroller/ft232h/i2c.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/ft232h/pin.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/ft232h/spi.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/generic_linux/i2c.py
src/adafruit_blinka/microcontroller/generic_linux/spi.py
src/adafruit_blinka/microcontroller/mcp2221/__init__.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/mcp2221/i2c.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/mcp2221/pin.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/nova/__init__.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/nova/i2c.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/nova/pin.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/nova/pwmout.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/nova/spi.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/nova/uart.py [new file with mode: 0644]
src/adafruit_blinka/microcontroller/tegra/t186/pin.py
src/adafruit_blinka/microcontroller/tegra/t194/pin.py
src/adafruit_blinka/microcontroller/tegra/t210/pin.py
src/analogio.py [new file with mode: 0644]
src/board.py
src/busio.py
src/digitalio.py
src/microcontroller/__init__.py
src/microcontroller/pin.py
src/micropython.py
src/pulseio.py

index 58f60ffa7cd2eaf6e56128c2ae151823d9a4d3ea..14a1017b49b478a34f74151726a2dbe633bf6dab 100755 (executable)
@@ -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
index d33adb4e693abdfa0cc9e30d0c4af4974ce609c5..07266d737bb2b46c829c28ecb8d54f508420ea89 100755 (executable)
@@ -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
index daaff66ff22ca347f955b8c6ba0195d62ea8be12..a2cfda99ff3f6d8be659c813fb1a6804fb06d66b 100755 (executable)
@@ -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
index cb3549cb8057373c8fa75661d006e446f6decebb..0bd15601b151d6170dda6aeeed743be33a76e614 100755 (executable)
--- 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
index a56e5f7c467de6fd59ff527c70b15f3973c06f96..fc0bb3a83e4ee09cfcb9be3d81752cc6222de97e 100644 (file)
@@ -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 (file)
index 0000000..0dfe4a4
--- /dev/null
@@ -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 (file)
index 0000000..5c5b278
--- /dev/null
@@ -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
index 4da8cf504875f0a4e7220ac9b6d29015ad26ab3a..8b9b77cbb73854361cef5d816a432f423f51fb2a 100644 (file)
@@ -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
index 05fc3903092b7a41a9ab845af205f56dc1eef471..cfa70dccd74c45caf4594c5e331e9247374eb90d 100644 (file)
@@ -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
index 906fa56696a7a71815d4b83b1a6dec0fdb25abe2..47c1624b94803e6aed450c210d514ffe2b4bf253 100644 (file)
@@ -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
index 24e229f50677305d9043363bc8e3084ef0f845f8..29105822955bd1833b99b5e8b7972cfe111f022f 100644 (file)
@@ -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 (file)
index 0000000..bdb3ba2
--- /dev/null
@@ -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
index 8c6e88e18e78e521bbb725a1c5c54036949dfa1c..7f32cdfeb48e308260682f7b41c03a903bbc9246 100644 (file)
@@ -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
index 9319450b363af58875cd9c9753236f9cb534aef0..0752c514de24e3aceb6facec982f35cc31f5652a 100644 (file)
@@ -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 (file)
index 0000000..a1dd925
--- /dev/null
@@ -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
index 817e91193cb0cb691a7cdd4cbf5efe3f46cc6fde..59168dc6004b8dd0467a4c118717599e65d8c7ce 100644 (file)
@@ -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
index 05dd69d5d679175c3b2665d2781d567126ad9952..47fc39b32b3708c074166ecef1ba4b84b8f5cbce 100644 (file)
@@ -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
index 47582918d8134e01e26420e05a235c642b5e8891..91347e04a9548be453d281070be0ee494029d5d2 100644 (file)
@@ -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
index eff7f9691d5a52111349354ddd014946ae17f48c..338017875acf1b6b0540975a4d6bdc18cbff9bb0 100644 (file)
@@ -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
index 620957cd4b8346cf50514f58bcce1cfbe68ad438..516528ab1c2669ac335ccf0e0d9527b3591f3857 100644 (file)
@@ -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 (file)
index 0000000..78b6459
--- /dev/null
@@ -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 (file)
index 0000000..18e8421
--- /dev/null
@@ -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 (file)
index 0000000..0ecf2f2
--- /dev/null
@@ -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 (file)
index 0000000..e6b08ac
--- /dev/null
@@ -0,0 +1 @@
+"""Definition for the AllWinner H3 chip"""
\ No newline at end of file
similarity index 82%
rename from src/adafruit_blinka/microcontroller/allwinner_h3/pin.py
rename to src/adafruit_blinka/microcontroller/allwinner/h3/pin.py
index f2ed8c085525d9faee61b6f8a6cec5a1773cf4f7..7ddf86c8b35228a5c7f308dbf76646b1d62196f6 100644 (file)
@@ -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),
+)
index e73457d6d529fff5f10484a1251eef5c6b90b52e..ca9d027e4f18770fccb66a0ff10e0a90a69dd9e7 100644 (file)
@@ -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 (file)
index 0000000..70bab33
--- /dev/null
@@ -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,)
index 10835dc05741c66f5e0f9d7110770d7b29ea81ec..3db76dfec133425357f34ada784f2c8d0f2a676e 100644 (file)
@@ -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!
 )
-
index b918c86a02e369c051eb8d069f9373f73daa7eff..289d1064ffb51d1cc21ee55d342e77226e32cb1e 100644 (file)
@@ -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))
index c58b443f52f916fe6b1b003acd84cbef81daa097..3bbb65fe39b3daa3c1388d3c7cc44860a2f8654e 100755 (executable)
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/ft232h/i2c.py b/src/adafruit_blinka/microcontroller/ft232h/i2c.py
new file mode 100644 (file)
index 0000000..7f733c1
--- /dev/null
@@ -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 (file)
index 0000000..30dbc66
--- /dev/null
@@ -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 (file)
index 0000000..a260e72
--- /dev/null
@@ -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
index e309e9ef6ac0ae3e5db041b616ca5fb2ba463105..ed8c8b8f7ed0860694d8a6e9200034b519e7e854 100644 (file)
@@ -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]
 
index 71f74c8b931577efb655c8ef42efd1f54ce5093b..f2ffa823ec6a64c70570aed4cf68ad92ea14c67a 100755 (executable)
@@ -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 (file)
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 (file)
index 0000000..9ebb5b6
--- /dev/null
@@ -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 (file)
index 0000000..aae81e5
--- /dev/null
@@ -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 (file)
index 0000000..139d8b6
--- /dev/null
@@ -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 (file)
index 0000000..12ccf0c
--- /dev/null
@@ -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 (file)
index 0000000..1919070
--- /dev/null
@@ -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 (file)
index 0000000..235e4ec
--- /dev/null
@@ -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 (file)
index 0000000..6af2de8
--- /dev/null
@@ -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 (file)
index 0000000..3926922
--- /dev/null
@@ -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 (file)
index 0000000..253d7a7
--- /dev/null
@@ -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)
index 25ec2e080fccc3d5d5b1b08cc6600f62382d787d..f033b5c4149fbbf089ade427b5894491374bdcf7 100644 (file)
@@ -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), )
index 2598c51460643165a3e91d7a3469296406d07c1d..971474e385d404f552010c176de12959ffdcc163 100644 (file)
@@ -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), )
index c6d4b6e8266fb254c00387a2c446489bfa11fc90..50e2daa45484078bf07c696f9e1dd0670e4e35de 100644 (file)
@@ -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 (file)
index 0000000..229495d
--- /dev/null
@@ -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
index 30e526ced6d34531e3f49a05d801c87259472a5d..d2852ba8ba5994fcf659879a8005c5a4e43f37aa 100755 (executable)
@@ -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"""
index f5991f9b27744d020b4b1658351e9ac9a448b035..d5ae7c970e49ef91868cca3190cda32a0b22abc4 100755 (executable)
@@ -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):
index 6f6e9d1fe180670140e1578df351f526942e59d5..5dc7dafe52022df59773b4d425038fc13291104b 100755 (executable)
@@ -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):
index 5550543d90ebd75e22b81019994f389a6b1e33b1..5bef237cde327250ae8bfd5294213e78c461765e 100755 (executable)
@@ -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)
index 5dd250c9ff02215922c53ee6df417dadd874c2f7..ebe9cbaef76b36ab857a79c9f1d8aa6b48639f63 100755 (executable)
@@ -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)
index b5af9b39a5c5627d735dfdd3ecf0dcd756907fdd..620646f85882ec03383e00cf33a6aa5a2a955488 100755 (executable)
@@ -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
index 42524fcdccee6f90419bca0def957643b2a1e2bf..239a4ba1dd6b3feb7c27dd0f1d3defcb711b10ac 100644 (file)
@@ -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