]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/am65xx/pwmout.py
i2c
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / am65xx / pwmout.py
1 # SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2 #
3 # SPDX-License-Identifier: MIT
4 # SPDX-FileCopyrightText: 2022 Martin Schnur for Siemens AG
5 #
6 # SPDX-License-Identifier: MIT
7
8 # pylint: disable=pointless-string-statement
9 # pylint: disable=ungrouped-imports,wrong-import-position,unused-import
10 # pylint: disable=import-outside-toplevel
11
12 """Custom PWMOut Wrapper for am65xx"""
13 """
14 Much code from https://github.com/vsergeev/python-periphery/blob/master/periphery/pwm.py
15 Copyright (c) 2015-2016 vsergeev / Ivan (Vanya) A. Sergeev
16 License: MIT
17 """
18
19
20 import mraa
21 from adafruit_blinka.microcontroller.am65xx.pin import Pin
22
23 # pylint: disable=unnecessary-pass
24
25
26 class PWMError(IOError):
27     """Base class for PWM errors."""
28
29     pass
30
31
32 # pylint: enable=unnecessary-pass
33
34
35 class PWMOut:
36     """Pulse Width Modulation Output Class"""
37
38     def __init__(self, pin, *, frequency=500, duty_cycle=0, variable_frequency=False):
39         self._frequency = None
40         self._duty_cycle = None
41         self._pwmpin = None
42         self._period = 0
43         self._enabled = False
44         self._varfreq = variable_frequency
45         # check pin for PWM support
46         self._pin = Pin(pin.id)
47         self._pin.init(mode=Pin.PWM)
48         # initialize pin
49         self._open(pin, duty_cycle, frequency, variable_frequency)
50
51     def __del__(self):
52         self.deinit()
53
54     def __enter__(self):
55         return self
56
57     def __exit__(self, t, value, traceback):
58         self.deinit()
59
60     def _open(self, pin, duty=0, freq=500, variable_frequency=False):
61         self._pwmpin = mraa.Pwm(pin.id)
62         self.frequency = freq
63         self.enabled = True
64         self._varfreq = variable_frequency
65         self.duty_cycle = duty
66
67     def deinit(self):
68         """Deinit the PWM."""
69         if self._pwmpin is not None:
70             self._pwmpin.enable(False)
71             self._pwmpin = None
72
73     def _is_deinited(self):
74         if self._pwmpin is None:
75             raise ValueError(
76                 "Object has been deinitialize and can no longer "
77                 "be used. Create a new object."
78             )
79
80     @property
81     def period(self):
82         """Get or set the PWM's output period in seconds.
83
84         Raises:
85             PWMError: if an I/O or OS error occurs.
86             TypeError: if value type is not int or float.
87
88         :type: int, float
89         """
90         return 1.0 / self.frequency
91
92     @period.setter
93     def period(self, period):
94         if not isinstance(period, (int, float)):
95             raise TypeError("Invalid period type, should be int or float.")
96
97         self.frequency = 1.0 / period
98
99     @property
100     def duty_cycle(self):
101         """Get or set the PWM's output duty cycle which is the fraction of
102         each pulse which is high. 16-bit
103
104         Raises:
105             PWMError: if an I/O or OS error occurs.
106             TypeError: if value type is not int or float.
107             ValueError: if value is out of bounds of 0.0 to 1.0.
108
109         :type: int, float
110         """
111         return int(self._duty_cycle * 65535)
112
113     @duty_cycle.setter
114     def duty_cycle(self, duty_cycle):
115         if not isinstance(duty_cycle, (int, float)):
116             raise TypeError("Invalid duty cycle type, should be int or float.")
117
118         if not 0 <= duty_cycle <= 65535:
119             raise ValueError("Invalid duty cycle value, should be between 0 and 65535")
120
121         # convert from 16-bit
122         duty_cycle /= 65535.0
123
124         self._duty_cycle = duty_cycle
125         # self._pwmpin.ChangeDutyCycle(round(self._duty_cycle * 100))
126         self._pwmpin.write(self._duty_cycle)  # mraa duty_cycle 0.0f - 1.0f
127
128     @property
129     def frequency(self):
130         """Get or set the PWM's output frequency in Hertz.
131
132         Raises:
133             PWMError: if an I/O or OS error occurs.
134             TypeError: if value type is not int or float.
135
136         :type: int, float
137         """
138
139         return self._frequency
140
141     @frequency.setter
142     def frequency(self, frequency):
143         if not isinstance(frequency, (int, float)):
144             raise TypeError("Invalid frequency type, should be int or float.")
145
146         if self._enabled and not self._varfreq:
147             raise TypeError(
148                 " Set variable_frequency = True to allow changing frequency "
149             )
150         # mraa has different variants in seconds,milli(_ms),micro(_us)
151         self._pwmpin.period((1 / frequency))
152         self._frequency = frequency
153
154     @property
155     def enabled(self):
156         """Get or set the PWM's output enabled state.
157
158         Raises:
159             PWMError: if an I/O or OS error occurs.
160             TypeError: if value type is not bool.
161
162         :type: bool
163         """
164         return self._enabled
165
166     @enabled.setter
167     def enabled(self, value):
168         if not isinstance(value, bool):
169             raise TypeError("Invalid enabled type, should be string.")
170
171         if value:
172             self._pwmpin.enable(True)
173             self._enabled = value
174         else:
175             self._pwmpin.enable(False)
176             self._enabled(False)
177
178     # String representation
179     def __str__(self):
180         return "pin %s (freq=%f Hz, duty_cycle=%f%%)" % (
181             self._pin,
182             self.frequency,
183             self.duty_cycle,
184         )