Skip to content

Commit dbda43b

Browse files
projectgusdpgeorge
authored andcommitted
tests/multi_pyb_can: Add multitests for pyboard CAN controller.
Currently only classic CAN, but tests run on both the stm32 classic CAN controller and the FD-CAN controller with the same results. Signed-off-by: Angus Gratton <angus@redyak.com.au>
1 parent 9db2398 commit dbda43b

File tree

4 files changed

+172
-0
lines changed

4 files changed

+172
-0
lines changed

tests/multi_pyb_can/rx_callback.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from pyb import CAN
2+
import time
3+
import errno
4+
5+
# Test the various receive IRQs, including overflow
6+
7+
rx_overflow = False
8+
9+
REASONS = ["received", "full", "overflow"]
10+
11+
# CAN IDs
12+
ID_SPAM = 0x345 # messages spammed into the receive FIFO
13+
ID_ACK_OFLOW = 0x055 # message the receiver sends after it's seen an overflow
14+
ID_AFTER = 0x100 # message the sender sends after the ACK
15+
16+
17+
def cb0(bus, reason):
18+
global rx_overflow
19+
if reason != 0 and not rx_overflow:
20+
# exact timing of 'received' callbacks depends on controller type,
21+
# so only log the other two
22+
print("rx0 reason", REASONS[reason])
23+
if reason == 2:
24+
rx_overflow = True
25+
26+
27+
# Accept all standard IDs on FIFO 0
28+
def _enable_accept_all():
29+
if hasattr(CAN, "MASK"): # FD-CAN controller
30+
can.setfilter(0, CAN.RANGE, 0, (0x0, 0x7FF), extframe=False)
31+
else:
32+
can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0), extframe=False)
33+
34+
35+
# Receiver
36+
def instance0():
37+
_enable_accept_all()
38+
can.rxcallback(0, cb0)
39+
40+
multitest.next()
41+
multitest.wait("sender ready")
42+
multitest.broadcast("receiver ready")
43+
44+
while not rx_overflow:
45+
pass # Resume ASAP after FIFO0 overflows
46+
47+
can.send(b"overflow", ID_ACK_OFLOW)
48+
49+
# drain the receive FIFO, making sure we read at least on ID_SPAM message
50+
rxed_spam = False
51+
while can.any(0):
52+
msg = can.recv(0, timeout=0)
53+
assert msg[0] == ID_SPAM
54+
rxed_spam = True
55+
print("rxed_spam", rxed_spam)
56+
57+
# This should be the one message with ID_AFTER, there may be one or two spam messages as well
58+
for _ in range(10):
59+
msg = can.recv(0, timeout=500)
60+
if msg[0] == ID_AFTER:
61+
print(msg)
62+
break
63+
64+
# RX FIFO should be empty now
65+
print("any", can.any(0))
66+
67+
68+
# Sender
69+
def instance1():
70+
_enable_accept_all()
71+
multitest.next()
72+
multitest.broadcast("sender ready")
73+
multitest.wait("receiver ready")
74+
75+
# Spam out messages until the receiver tells us its RX FIFO is full.
76+
#
77+
# The RX FIFO on the receiver can vary from 3 deep (BXCAN) to 25 deep (STM32H7),
78+
# so we keep sending to it until we see a CAN message on ID_ACK_OFLOW indicating
79+
# the receiver's FIFO has overflowed
80+
for i in range(255):
81+
can.send(bytes([i] * 8), ID_SPAM, timeout=25)
82+
if can.any(0):
83+
print(can.recv(0)) # should be ID_ACK_OFLOW
84+
break
85+
# on boards like STM32H7 the TX FIFO is really deep, so don't fill it too quickly...
86+
time.sleep_ms(1)
87+
88+
# give the receiver some time to make space in the FIFO
89+
time.sleep_ms(200)
90+
91+
# send the final message, the receiver should get this one
92+
can.send(b"aaaaa", ID_AFTER)
93+
94+
# Sender's RX FIFO should also be empty at this point
95+
print("any", can.any(0))
96+
97+
98+
can = CAN(1, CAN.NORMAL, baudrate=500_000, sample_point=75)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--- instance0 ---
2+
rx0 reason full
3+
rx0 reason overflow
4+
rxed_spam True
5+
(256, False, False, 0, b'aaaaa')
6+
any False
7+
--- instance1 ---
8+
(85, False, False, 0, b'overflow')
9+
any False

tests/multi_pyb_can/rx_filters.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from pyb import CAN
2+
import time
3+
import errno
4+
5+
# Test for the filtering capabilities for RX FIFO 0 and 1.
6+
7+
8+
# Receiver
9+
def instance0():
10+
# Configure to receive standard frames (in a range) on FIFO 0
11+
# and extended frames (in a range) on FIFO 1.
12+
if hasattr(CAN, "MASK"):
13+
# FD-CAN has independent filter banks for standard and extended IDs
14+
can.setfilter(0, CAN.MASK, 0, (0x300, 0x700), extframe=False)
15+
can.setfilter(0, CAN.MASK, 1, (0x3000, 0x7000), extframe=True)
16+
else:
17+
# pyb.CAN only supports MASK32 for extended ids
18+
can.setfilter(0, CAN.MASK16, 0, (0x300, 0x700, 0x300, 0x700), extframe=False)
19+
can.setfilter(1, CAN.MASK32, 1, (0x3000, 0x7000), extframe=True)
20+
21+
multitest.next()
22+
multitest.wait("sender ready")
23+
multitest.broadcast("receiver ready")
24+
for i in range(3):
25+
print(i)
26+
print("fifo0", can.recv(0, timeout=200))
27+
print("fifo1", can.recv(1, timeout=200))
28+
29+
try:
30+
can.recv(0, timeout=100) # should time out
31+
except OSError as e:
32+
assert e.errno == errno.ETIMEDOUT
33+
print("Timed out as expected")
34+
35+
36+
# Sender
37+
def instance1():
38+
multitest.next()
39+
multitest.broadcast("sender ready")
40+
multitest.wait("receiver ready")
41+
42+
for i in range(3):
43+
print(i)
44+
can.send(bytes([i, 3] * i), 0x345)
45+
can.send(bytes([0xEE] * i), 0x3700 + i, extframe=True)
46+
can.send(b"abcdef", 0x123) # matches no filter, expect ACKed but not received
47+
time.sleep_ms(5) # avoid flooding either our or the receiver's FIFO
48+
49+
50+
can = CAN(1, CAN.NORMAL, baudrate=500_000, sample_point=75)

tests/multi_pyb_can/rx_filters.py.exp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--- instance0 ---
2+
0
3+
fifo0 (837, False, False, 0, b'')
4+
fifo1 (14080, True, False, 0, b'')
5+
1
6+
fifo0 (837, False, False, 0, b'\x01\x03')
7+
fifo1 (14081, True, False, 0, b'\xee')
8+
2
9+
fifo0 (837, False, False, 0, b'\x02\x03\x02\x03')
10+
fifo1 (14082, True, False, 0, b'\xee\xee')
11+
Timed out as expected
12+
--- instance1 ---
13+
0
14+
1
15+
2

0 commit comments

Comments
 (0)