Skip to content

Commit 907c5e9

Browse files
projectgusdpgeorge
authored andcommitted
tests/extmod_hardware: Add basic tests for machine.Counter and Encoder.
These don't test any advanced features, just the basics. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <[email protected]>
1 parent 641ca2e commit 907c5e9

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Test machine.Counter implementation
2+
#
3+
# IMPORTANT: This test requires hardware connections: the out_pin and in_pin
4+
# must be wired together.
5+
6+
try:
7+
from machine import Counter
8+
except ImportError:
9+
print("SKIP")
10+
raise SystemExit
11+
12+
import sys
13+
from machine import Pin
14+
15+
if "esp32" in sys.platform:
16+
id = 0
17+
out_pin = 4
18+
in_pin = 5
19+
else:
20+
print("Please add support for this test on this platform.")
21+
raise SystemExit
22+
23+
import unittest
24+
25+
out_pin = Pin(out_pin, mode=Pin.OUT)
26+
in_pin = Pin(in_pin, mode=Pin.IN)
27+
28+
29+
def toggle(times):
30+
for _ in range(times):
31+
out_pin(1)
32+
out_pin(0)
33+
34+
35+
class TestCounter(unittest.TestCase):
36+
def setUp(self):
37+
out_pin(0)
38+
self.counter = Counter(id, in_pin)
39+
40+
def tearDown(self):
41+
self.counter.deinit()
42+
43+
def assertCounter(self, value):
44+
self.assertEqual(self.counter.value(), value)
45+
46+
def test_connections(self):
47+
# Test the hardware connections are correct. If this test fails, all tests will fail.
48+
out_pin(1)
49+
self.assertEqual(1, in_pin())
50+
out_pin(0)
51+
self.assertEqual(0, in_pin())
52+
53+
def test_count_rising(self):
54+
self.assertCounter(0)
55+
toggle(100)
56+
self.assertCounter(100)
57+
out_pin(1)
58+
self.assertEqual(self.counter.value(0), 101)
59+
self.assertCounter(0) # calling value(0) resets
60+
out_pin(0)
61+
self.assertCounter(0) # no rising edge
62+
out_pin(1)
63+
self.assertCounter(1)
64+
65+
def test_change_directions(self):
66+
self.assertCounter(0)
67+
toggle(100)
68+
self.assertCounter(100)
69+
self.counter.init(in_pin, direction=Counter.DOWN)
70+
self.assertCounter(0) # calling init() zeroes the counter
71+
self.counter.value(100) # need to manually reset the value
72+
self.assertCounter(100)
73+
toggle(25)
74+
self.assertCounter(75)
75+
76+
def test_count_falling(self):
77+
self.counter.init(in_pin, direction=Counter.UP, edge=Counter.FALLING)
78+
toggle(20)
79+
self.assertCounter(20)
80+
out_pin(1)
81+
self.assertCounter(20) # no falling edge
82+
out_pin(0)
83+
self.assertCounter(21)
84+
self.counter.value(-(2**24))
85+
toggle(20)
86+
self.assertCounter(-(2**24 - 20))
87+
88+
89+
if __name__ == "__main__":
90+
unittest.main()
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Test machine.Encoder implementation
2+
#
3+
# IMPORTANT: This test requires hardware connections:
4+
# - out0_pin and in0_pin must be wired together.
5+
# - out1_pin and in1_pin must be wired together.
6+
7+
try:
8+
from machine import Encoder
9+
except ImportError:
10+
print("SKIP")
11+
raise SystemExit
12+
13+
import sys
14+
from machine import Pin
15+
16+
if "esp32" in sys.platform:
17+
id = 0
18+
out0_pin = 4
19+
in0_pin = 5
20+
out1_pin = 12
21+
in1_pin = 13
22+
else:
23+
print("Please add support for this test on this platform.")
24+
raise SystemExit
25+
26+
import unittest
27+
28+
out0_pin = Pin(out0_pin, mode=Pin.OUT)
29+
in0_pin = Pin(in0_pin, mode=Pin.IN)
30+
out1_pin = Pin(out1_pin, mode=Pin.OUT)
31+
in1_pin = Pin(in1_pin, mode=Pin.IN)
32+
33+
34+
class TestEncoder(unittest.TestCase):
35+
def setUp(self):
36+
out0_pin(0)
37+
out1_pin(0)
38+
self.enc = Encoder(id, in0_pin, in1_pin)
39+
self.pulses = 0 # track the expected encoder position in software
40+
41+
def tearDown(self):
42+
self.enc.deinit()
43+
44+
def rotate(self, pulses):
45+
for _ in range(abs(pulses)):
46+
self.pulses += 1 if (pulses > 0) else -1
47+
q = self.pulses % 4
48+
# Only one pin should change state each "step" so output won't glitch
49+
out0_pin(q in (1, 2))
50+
out1_pin(q in (2, 3))
51+
52+
def assertPosition(self, value):
53+
self.assertEqual(self.enc.value(), value)
54+
55+
def test_connections(self):
56+
# Test the hardware connections are correct. If this test fails, all tests will fail.
57+
for ch, outp, inp in ((0, out0_pin, in0_pin), (1, out1_pin, in1_pin)):
58+
print("Testing channel ", ch)
59+
outp(1)
60+
self.assertEqual(1, inp())
61+
outp(0)
62+
self.assertEqual(0, inp())
63+
64+
def test_basics(self):
65+
self.assertPosition(0)
66+
self.rotate(100)
67+
self.assertPosition(100 // 4)
68+
self.rotate(-100)
69+
self.assertPosition(0)
70+
71+
def test_partial(self):
72+
# With phase=1 (default), need 4x pulses to count a rotation
73+
self.assertPosition(0)
74+
self.rotate(1)
75+
self.assertPosition(0)
76+
self.rotate(1)
77+
self.assertPosition(0)
78+
self.rotate(1)
79+
self.assertPosition(1) # only 3 pulses to count first rotation?
80+
self.rotate(1)
81+
self.assertPosition(1)
82+
self.rotate(1)
83+
self.assertPosition(1)
84+
self.rotate(1)
85+
self.assertPosition(1)
86+
self.rotate(1)
87+
self.assertPosition(2) # 4 for next rotation
88+
self.rotate(-1)
89+
self.assertPosition(1)
90+
self.rotate(-4)
91+
self.assertPosition(0)
92+
self.rotate(-4)
93+
self.assertPosition(-1)
94+
self.rotate(-3)
95+
self.assertPosition(-1)
96+
97+
98+
if __name__ == "__main__":
99+
unittest.main()

0 commit comments

Comments
 (0)