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