]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/horizon/pwmio/PWMOut.py
Added support for D-Robotics RDK-X3
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / horizon / pwmio / PWMOut.py
1 # SPDX-FileCopyrightText: 2024 Hajime Fujimoto
2 #
3 # SPDX-License-Identifier: MIT
4 """Custom PWMOut Wrapper for Hobot.GPIO PWM Class"""
5 import Hobot.GPIO as GPIO
6
7 GPIO.setmode(GPIO.BCM)  # Use BCM pins D4 = GPIO #4
8 GPIO.setwarnings(False)  # shh!
9 GPIO.cleanup()
10
11 # pylint: disable=unnecessary-pass
12 class PWMError(IOError):
13     """Base class for PWM errors."""
14
15     pass
16
17
18 # pylint: enable=unnecessary-pass
19
20
21 class PWMOut:
22     """Pulse Width Modulation Output Class"""
23
24     def __init__(self, pin, *, frequency=48000, duty_cycle=0, variable_frequency=False):
25         self._pwmpin = None
26         self._period = 0
27         self._open(pin, duty_cycle, frequency, variable_frequency)
28
29     def __del__(self):
30         self.deinit()
31
32     def __enter__(self):
33         return self
34
35     def __exit__(self, t, value, traceback):
36         self.deinit()
37
38     def _open(self, pin, duty=0, freq=500, variable_frequency=False):
39         if (pin == (0, 25)):
40             gpio_pin = 12
41         elif (pin == (0, 4)):
42             gpio_pin = 13
43         else:
44             raise ValueError(
45                 "PWM is only available on D12 or D13."
46             )
47         self._pin = gpio_pin
48         GPIO.setmode(GPIO.BCM)
49 #        GPIO.setup(self._pin, GPIO.OUT)
50         self._pwmpin = GPIO.PWM(self._pin, freq)
51
52         if variable_frequency:
53             print("Variable Frequency is not supported, continuing without it...")
54
55         # set frequency
56         self.frequency = freq
57         # set duty
58         duty = 656 if duty <= 656 else duty
59         self.duty_cycle = duty
60
61         self.enabled = True
62
63     def deinit(self):
64         """Deinit the PWM."""
65         if self._pwmpin is not None:
66             self._pwmpin.stop()
67             GPIO.cleanup(self._pin)
68             self._pwmpin = None
69
70     def _is_deinited(self):
71         if self._pwmpin is None:
72             raise ValueError(
73                 "Object has been deinitialize and can no longer "
74                 "be used. Create a new object."
75             )
76
77     @property
78     def period(self):
79         """Get or set the PWM's output period in seconds.
80
81         Raises:
82             PWMError: if an I/O or OS error occurs.
83             TypeError: if value type is not int or float.
84
85         :type: int, float
86         """
87         return 1.0 / self.frequency
88
89     @period.setter
90     def period(self, period):
91         if not isinstance(period, (int, float)):
92             raise TypeError("Invalid period type, should be int or float.")
93
94         self.frequency = 1.0 / period
95
96     @property
97     def duty_cycle(self):
98         """Get or set the PWM's output duty cycle which is the fraction of
99         each pulse which is high. 16-bit
100
101         Raises:
102             PWMError: if an I/O or OS error occurs.
103             TypeError: if value type is not int or float.
104             ValueError: if value is out of bounds of 0.0 to 1.0.
105
106         :type: int, float
107         """
108         return int(self._duty_cycle * 65535)
109
110     @duty_cycle.setter
111     def duty_cycle(self, duty_cycle):
112         if not isinstance(duty_cycle, (int, float)):
113             raise TypeError("Invalid duty cycle type, should be int or float.")
114
115         if not 0 <= duty_cycle <= 65535:
116             raise ValueError("Invalid duty cycle value, should be between 0 and 65535")
117
118         # convert from 16-bit
119         duty_cycle /= 65535.0
120
121         self._duty_cycle = duty_cycle
122         self._pwmpin.ChangeDutyCycle(round(self._duty_cycle * 100))
123
124     @property
125     def frequency(self):
126         """Get or set the PWM's output frequency in Hertz.
127
128         Raises:
129             PWMError: if an I/O or OS error occurs.
130             TypeError: if value type is not int or float.
131
132         :type: int, float
133         """
134
135         return self._frequency
136
137     @frequency.setter
138     def frequency(self, frequency):
139         if not isinstance(frequency, (int, float)):
140             raise TypeError("Invalid frequency type, should be int or float.")
141
142         self._pwmpin.ChangeFrequency(round(frequency))
143         self._frequency = frequency
144
145     @property
146     def enabled(self):
147         """Get or set the PWM's output enabled state.
148
149         Raises:
150             PWMError: if an I/O or OS error occurs.
151             TypeError: if value type is not bool.
152
153         :type: bool
154         """
155         return self._enabled
156
157     @enabled.setter
158     def enabled(self, value):
159         if not isinstance(value, bool):
160             raise TypeError("Invalid enabled type, should be string.")
161
162         if value:
163             self._pwmpin.start(round(self._duty_cycle * 100))
164         else:
165             self._pwmpin.stop()
166
167         self._enabled = value
168
169     # String representation
170     def __str__(self):
171         return "pin %s (freq=%f Hz, duty_cycle=%f%%)" % (
172             self._pin,
173             self.frequency,
174             self.duty_cycle,
175         )