diff --git a/src/adafruit_blinka/board/horizon/rdkx3.py b/src/adafruit_blinka/board/horizon/rdkx3.py new file mode 100644 index 00000000..e132cb17 --- /dev/null +++ b/src/adafruit_blinka/board/horizon/rdkx3.py @@ -0,0 +1,54 @@ +# SPDX-FileCopyrightText: 2024 Hajime Fujimoto +# +# SPDX-License-Identifier: MIT +"""Pin definitions for RDK-X3.""" + +from adafruit_blinka.microcontroller.horizon.sunrise_x3 import pin + +D0 = pin.D0 +D1 = pin.D1 + +D2 = pin.D2 +SDA = pin.SDA +D3 = pin.D3 +SCL = pin.SCL + +D4 = pin.D4 +D5 = pin.D5 +D6 = pin.D6 + +D7 = pin.D7 +CE1 = pin.D7 +D8 = pin.D8 +CE0 = pin.D8 +D9 = pin.D9 +MISO = pin.D9 +D10 = pin.D10 +MOSI = pin.D10 +D11 = pin.D11 +SCLK = pin.D11 +SCK = pin.D11 + +D12 = pin.D12 +D13 = pin.D13 + +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 +D18 = pin.D18 +D19 = pin.D19 +D20 = pin.D20 +D21 = pin.D21 +D22 = pin.D22 +D23 = pin.D23 +D24 = pin.D24 +D25 = pin.D25 +D26 = pin.D26 +D27 = pin.D27 diff --git a/src/adafruit_blinka/microcontroller/horizon/pwmio/PWMOut.py b/src/adafruit_blinka/microcontroller/horizon/pwmio/PWMOut.py new file mode 100644 index 00000000..b940b775 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/horizon/pwmio/PWMOut.py @@ -0,0 +1,174 @@ +# SPDX-FileCopyrightText: 2024 Hajime Fujimoto +# +# SPDX-License-Identifier: MIT +"""Custom PWMOut Wrapper for Hobot.GPIO PWM Class""" +from Hobot import GPIO + +GPIO.setmode(GPIO.BCM) # Use BCM pins D4 = GPIO #4 +GPIO.setwarnings(False) # shh! +GPIO.cleanup() + + +# pylint: disable=unnecessary-pass +class PWMError(IOError): + """Base class for PWM errors.""" + + pass + + +# pylint: enable=unnecessary-pass + + +class PWMOut: + """Pulse Width Modulation Output Class""" + + def __init__(self, pin, *, frequency=48000, duty_cycle=0, variable_frequency=False): + self._pwmpin = None + self._period = 0 + 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): + if pin == (0, 25): + gpio_pin = 12 + elif pin == (0, 4): + gpio_pin = 13 + else: + raise ValueError("PWM is only available on D12 or D13.") + self._pin = gpio_pin + GPIO.setmode(GPIO.BCM) + # GPIO.setup(self._pin, GPIO.OUT) + self._pwmpin = GPIO.PWM(self._pin, freq) + + if variable_frequency: + print("Variable Frequency is not supported, continuing without it...") + + # set frequency + self.frequency = freq + # set duty + duty = 656 if duty <= 656 else duty + self.duty_cycle = duty + + self.enabled = True + + def deinit(self): + """Deinit the PWM.""" + if self._pwmpin is not None: + self._pwmpin.stop() + GPIO.cleanup(self._pin) + 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." + ) + + @property + def period(self): + """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 + """ + return 1.0 / self.frequency + + @period.setter + def period(self, period): + if not isinstance(period, (int, float)): + raise TypeError("Invalid period type, should be int or float.") + + self.frequency = 1.0 / period + + @property + def duty_cycle(self): + """Get or set the PWM's output duty cycle which is the fraction of + each pulse which is high. 16-bit + + 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 + """ + return int(self._duty_cycle * 65535) + + @duty_cycle.setter + def duty_cycle(self, duty_cycle): + if not isinstance(duty_cycle, (int, float)): + raise TypeError("Invalid duty cycle type, should be int or float.") + + if not 0 <= duty_cycle <= 65535: + raise ValueError("Invalid duty cycle value, should be between 0 and 65535") + + # convert from 16-bit + duty_cycle /= 65535.0 + + self._duty_cycle = duty_cycle + self._pwmpin.ChangeDutyCycle(round(self._duty_cycle * 100)) + + @property + def frequency(self): + """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 + """ + + return self._frequency + + @frequency.setter + def frequency(self, frequency): + if not isinstance(frequency, (int, float)): + raise TypeError("Invalid frequency type, should be int or float.") + + self._pwmpin.ChangeFrequency(round(frequency)) + self._frequency = frequency + + @property + def enabled(self): + """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 + """ + return self._enabled + + @enabled.setter + def enabled(self, value): + if not isinstance(value, bool): + raise TypeError("Invalid enabled type, should be string.") + + if value: + self._pwmpin.start(round(self._duty_cycle * 100)) + else: + self._pwmpin.stop() + + self._enabled = value + + # String representation + def __str__(self): + return "pin %s (freq=%f Hz, duty_cycle=%f%%)" % ( + self._pin, + self.frequency, + self.duty_cycle, + ) diff --git a/src/adafruit_blinka/microcontroller/horizon/sunrise_x3/pin.py b/src/adafruit_blinka/microcontroller/horizon/sunrise_x3/pin.py new file mode 100644 index 00000000..0161633a --- /dev/null +++ b/src/adafruit_blinka/microcontroller/horizon/sunrise_x3/pin.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2024 Hajime Fujimoto +# +# SPDX-License-Identifier: MIT +"""A Pin class for use with Horizon Sunrise X3.""" + +from adafruit_blinka.microcontroller.generic_linux.libgpiod_pin import Pin + +D0 = Pin((0, 15)) +D1 = Pin((0, 14)) +D2 = Pin((0, 9)) +D3 = Pin((0, 8)) +D4 = Pin((0, 101)) +D5 = Pin((0, 119)) +D6 = Pin((0, 118)) +D7 = Pin((0, 28)) +D8 = Pin((0, 5)) +D9 = Pin((0, 7)) +D10 = Pin((0, 6)) +D11 = Pin((0, 3)) +D12 = Pin((0, 25)) +D13 = Pin((0, 4)) +D14 = Pin((0, 111)) +D15 = Pin((0, 112)) +D16 = Pin((0, 20)) +D17 = Pin((0, 12)) +D18 = Pin((0, 102)) +D19 = Pin((0, 103)) +D20 = Pin((0, 104)) +D21 = Pin((0, 108)) +D22 = Pin((0, 30)) +D23 = Pin((0, 27)) +D24 = Pin((0, 22)) +D25 = Pin((0, 29)) +D26 = Pin((0, 117)) +D27 = Pin((0, 13)) + +SDA = D2 +SCL = D3 +MISO = D9 +MOSI = D10 +SCLK = D11 +SCK = D11 +TXD = D14 +RXD = D15 + +spiPorts = ((1, SCLK, MOSI, MISO),) + +uartPorts = ((0, TXD, RXD),) + +i2cPorts = ((0, SCL, SDA),) + +pwmOuts = ( + ((0, 0), D12), + ((3, 0), D13), +) diff --git a/src/board.py b/src/board.py index c0d141e9..19356388 100644 --- a/src/board.py +++ b/src/board.py @@ -440,6 +440,9 @@ elif board_id == ap_board.INDIEDROID_NOVA: from adafruit_blinka.board.ameridroid.indiedroid_nova import * +elif board_id == ap_board.RDK_X3: + from adafruit_blinka.board.horizon.rdkx3 import * + elif "sphinx" in sys.modules: pass diff --git a/src/digitalio.py b/src/digitalio.py index 6f04984c..66c0c108 100644 --- a/src/digitalio.py +++ b/src/digitalio.py @@ -121,6 +121,8 @@ from adafruit_blinka.microcontroller.thead.th1520.pin import Pin elif detector.chip.K1: from adafruit_blinka.microcontroller.spacemit.k1.pin import Pin +elif detector.chip.SUNRISE_X3: + from adafruit_blinka.microcontroller.horizon.sunrise_x3.pin import Pin # Special Case Boards elif detector.board.ftdi_ft232h: from adafruit_blinka.microcontroller.ftdi_mpsse.ft232h.pin import Pin diff --git a/src/microcontroller/__init__.py b/src/microcontroller/__init__.py index 2792e7bd..e56d4879 100644 --- a/src/microcontroller/__init__.py +++ b/src/microcontroller/__init__.py @@ -159,6 +159,8 @@ def delay_us(delay): from adafruit_blinka.microcontroller.thead.th1520 import * elif chip_id == ap_chip.K1: from adafruit_blinka.microcontroller.spacemit.k1 import * +elif chip_id == ap_chip.SUNRISE_X3: + from adafruit_blinka.microcontroller.horizon.sunrise_x3 import * elif chip_id == ap_chip.GENERIC_X86: print("WARNING: GENERIC_X86 is not fully supported. Some features may not work.") elif chip_id == ap_chip.OS_AGNOSTIC: diff --git a/src/microcontroller/pin.py b/src/microcontroller/pin.py index 3d4a560d..da211e5b 100644 --- a/src/microcontroller/pin.py +++ b/src/microcontroller/pin.py @@ -153,6 +153,8 @@ from adafruit_blinka.microcontroller.rockchip.rv1103.pin import * elif chip_id == ap_chip.RV1106: from adafruit_blinka.microcontroller.rockchip.rv1106.pin import * +elif chip_id == ap_chip.SUNRISE_X3: + from adafruit_blinka.microcontroller.horizon.sunrise_x3.pin import * elif "sphinx" in sys.modules: # pylint: disable=unused-import from adafruit_blinka.microcontroller.generic_micropython import Pin diff --git a/src/pwmio.py b/src/pwmio.py index 72ce0d89..0e029a53 100644 --- a/src/pwmio.py +++ b/src/pwmio.py @@ -50,6 +50,8 @@ from adafruit_blinka.microcontroller.generic_linux.sysfs_pwmout import PWMOut elif detector.board.any_starfive_id: from adafruit_blinka.microcontroller.starfive.JH7110.pwmio import PWMOut +elif detector.board.any_horizon_board: + from adafruit_blinka.microcontroller.horizon.pwmio.PWMOut import PWMOut elif detector.board.OS_AGNOSTIC_BOARD: from adafruit_blinka.microcontroller.generic_agnostic_board.PWMOut import PWMOut elif (