File: test_pwm.py

package info (click to toggle)
python-periphery 2.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 424 kB
  • sloc: python: 3,496; makefile: 21
file content (207 lines) | stat: -rw-r--r-- 7,312 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import os
import sys

import periphery
from .test import ptest, pokay, passert, AssertRaises

if sys.version_info[0] == 3:
    raw_input = input


pwm_chip = None
pwm_channel = None


def test_arguments():
    ptest()

    # Invalid open types
    with AssertRaises("invalid open types", TypeError):
        periphery.PWM("foo", 0)
    with AssertRaises("invalid open types", TypeError):
        periphery.PWM(0, "foo")



def test_open_close():
    ptest()

    # Open non-existent PWM chip
    with AssertRaises("non-existent PWM chip", LookupError):
        periphery.PWM(9999, pwm_channel)

    # Open non-existent PWM channel
    with AssertRaises("non-existent PWM channel", periphery.PWMError):
        periphery.PWM(pwm_chip, 9999)

    # Open legitimate PWM chip/channel
    pwm = periphery.PWM(pwm_chip, pwm_channel)
    passert("property chip", pwm.chip == pwm_chip)
    passert("property channel", pwm.channel == pwm_channel)

    # Initialize period and duty cycle
    pwm.period = 5e-3
    pwm.duty_cycle = 0

    # Set period, check period, check period_ns, check frequency
    pwm.period = 1e-3
    passert("period is correct", abs(pwm.period - 1e-3) < 1e-4)
    passert("period_ns is correct", abs(pwm.period_ns - 1000000) < 1e5)
    passert("frequency is correct", abs(pwm.frequency - 1000) < 100)
    pwm.period = 5e-4
    passert("period is correct", abs(pwm.period - 5e-4) < 1e-5)
    passert("period_ns is correct", abs(pwm.period_ns - 500000) < 1e4)
    passert("frequency is correct", abs(pwm.frequency - 2000) < 100)

    # Set frequency, check frequency, check period, check period_ns
    pwm.frequency = 1000
    passert("frequency is correct", abs(pwm.frequency - 1000) < 100)
    passert("period is correct", abs(pwm.period - 1e-3) < 1e-4)
    passert("period_ns is correct", abs(pwm.period_ns - 1000000) < 1e5)
    pwm.frequency = 2000
    passert("frequency is correct", abs(pwm.frequency - 2000) < 100)
    passert("period is correct", abs(pwm.period - 5e-4) < 1e-5)
    passert("period_ns is correct", abs(pwm.period_ns - 500000) < 1e4)

    # Set period_ns, check period_ns, check period, check frequency
    pwm.period_ns = 1000000
    passert("period_ns is correct", abs(pwm.period_ns - 1000000) < 1e5)
    passert("period is correct", abs(pwm.period - 1e-3) < 1e-4)
    passert("frequency is correct", abs(pwm.frequency - 1000) < 100)
    pwm.period_ns = 500000
    passert("period_ns is correct", abs(pwm.period_ns - 500000) < 1e4)
    passert("period is correct", abs(pwm.period - 5e-4) < 1e-5)
    passert("frequency is correct", abs(pwm.frequency - 2000) < 100)

    pwm.period_ns = 1000000

    # Set duty cycle, check duty cycle, check duty_cycle_ns
    pwm.duty_cycle = 0.25
    passert("duty_cycle is correct", abs(pwm.duty_cycle - 0.25) < 1e-3)
    passert("duty_cycle_ns is correct", abs(pwm.duty_cycle_ns - 250000) < 1e4)
    pwm.duty_cycle = 0.50
    passert("duty_cycle is correct", abs(pwm.duty_cycle - 0.50) < 1e-3)
    passert("duty_cycle_ns is correct", abs(pwm.duty_cycle_ns - 500000) < 1e4)
    pwm.duty_cycle = 0.75
    passert("duty_cycle is correct", abs(pwm.duty_cycle - 0.75) < 1e-3)
    passert("duty_cycle_ns is correct", abs(pwm.duty_cycle_ns - 750000) < 1e4)

    # Set duty_cycle_ns, check duty_cycle_ns, check duty_cycle
    pwm.duty_cycle_ns = 250000
    passert("duty_cycle_ns is correct", abs(pwm.duty_cycle_ns - 250000) < 1e4)
    passert("duty_cycle is correct", abs(pwm.duty_cycle - 0.25) < 1e-3)
    pwm.duty_cycle_ns = 500000
    passert("duty_cycle_ns is correct", abs(pwm.duty_cycle_ns - 500000) < 1e4)
    passert("duty_cycle is correct", abs(pwm.duty_cycle - 0.50) < 1e-3)
    pwm.duty_cycle_ns = 750000
    passert("duty_cycle_ns is correct", abs(pwm.duty_cycle_ns - 750000) < 1e4)
    passert("duty_cycle is correct", abs(pwm.duty_cycle - 0.75) < 1e-3)

    # Set polarity, check polarity
    pwm.polarity = "normal"
    passert("polarity is normal", pwm.polarity == "normal")
    pwm.polarity = "inversed"
    passert("polarity is inversed", pwm.polarity == "inversed")
    # Set enabled, check enabled
    pwm.enabled = True
    passert("pwm is enabled", pwm.enabled == True)
    pwm.enabled = False
    passert("pwm is disabled", pwm.enabled == False)
    # Use enable()/disable(), check enabled
    pwm.enable()
    passert("pwm is enabled", pwm.enabled == True)
    pwm.disable()
    passert("pwm is disabled", pwm.enabled == False)

    # Set invalid polarity
    with AssertRaises("set invalid polarity", ValueError):
        pwm.polarity = "foo"

    pwm.close()


def test_loopback():
    ptest()


def test_interactive():
    ptest()

    pwm = periphery.PWM(pwm_chip, pwm_channel)

    print("Starting interactive test. Get out your oscilloscope, buddy!")
    raw_input("Press enter to continue...")

    # Set initial parameters and enable PWM
    pwm.duty_cycle = 0.0
    pwm.frequency = 1e3
    pwm.polarity = "normal"
    pwm.enabled = True

    # Check tostring
    print("PWM description: {}".format(str(pwm)))
    passert("interactive success", raw_input("PWM description looks ok? y/n ") == "y")

    # Set 1 kHz frequency, 0.25 duty cycle
    pwm.frequency = 1e3
    pwm.duty_cycle = 0.25
    passert("interactive success", raw_input("Frequency is 1 kHz, duty cycle is 25%? y/n ") == "y")

    # Set 1 kHz frequency, 0.50 duty cycle
    pwm.frequency = 1e3
    pwm.duty_cycle = 0.50
    passert("interactive success", raw_input("Frequency is 1 kHz, duty cycle is 50%? y/n ") == "y")

    # Set 2 kHz frequency, 0.25 duty cycle
    pwm.frequency = 2e3
    pwm.duty_cycle = 0.25
    passert("interactive success", raw_input("Frequency is 2 kHz, duty cycle is 25%? y/n ") == "y")

    # Set 2 kHz frequency, 0.50 duty cycle
    pwm.frequency = 2e3
    pwm.duty_cycle = 0.50
    passert("interactive success", raw_input("Frequency is 2 kHz, duty cycle is 50%? y/n ") == "y")

    pwm.duty_cycle = 0.0
    pwm.enabled = False

    pwm.close()


if __name__ == "__main__":
    if os.environ.get("CI") == "true":
        test_arguments()
        sys.exit(0)

    if len(sys.argv) < 3:
        print("Usage: python -m tests.test_pwm <PWM chip> <PWM channel>")
        print("")
        print("[1/4] Arguments test: No requirements.")
        print("[2/4] Open/close test: PWM channel should be real.")
        print("[3/4] Loopback test: No test.")
        print("[4/4] Interactive test: PWM channel should be observed with an oscilloscope or logic analyzer.")
        print("")
        print("Hint: for Raspberry Pi 3, enable PWM0 and PWM1 with:")
        print("   $ echo \"dtoverlay=pwm-2chan,pin=18,func=2,pin2=13,func2=4\" | sudo tee -a /boot/config.txt")
        print("   $ sudo reboot")
        print("Monitor GPIO 18 (header pin 12), and run this test with:")
        print("    python -m tests.test_pwm 0 0")
        print("or, monitor GPIO 13 (header pin 33), and run this test with:")
        print("    python -m tests.test_pwm 0 1")
        print("")

        sys.exit(1)

    pwm_chip = int(sys.argv[1])
    pwm_channel = int(sys.argv[2])

    test_arguments()
    pokay("Arguments test passed.")
    test_open_close()
    pokay("Open/close test passed.")
    test_loopback()
    pokay("Loopback test passed.")
    test_interactive()
    pokay("Interactive test passed.")

    pokay("All tests passed!")