Browse Source
Based on machine_i2s_rate, allows testing basic SPI functionality and timings. Implemented and confirmed working for rp2, esp32, and pyboard. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>pull/15543/head
Angus Gratton
4 months ago
committed by
Damien George
2 changed files with 191 additions and 0 deletions
@ -0,0 +1,152 @@ |
|||
# Test machine.SPI data transfer rates |
|||
import sys |
|||
|
|||
|
|||
try: |
|||
import time |
|||
from machine import Pin, SPI |
|||
except ImportError: |
|||
print("SKIP") |
|||
raise SystemExit |
|||
|
|||
MAX_DELTA_MS = 8 |
|||
|
|||
# Configure pins based on the port/board details. |
|||
# Values are tuples of (spi_id, sck, mosi, miso) |
|||
if "pyboard" in sys.platform: |
|||
spi_instances = ( |
|||
(1, None, None, None), # "explicit choice of sck/mosi/miso is not implemented" |
|||
(2, None, None, None), |
|||
) |
|||
elif "rp2" in sys.platform: |
|||
spi_instances = ((0, Pin(18), Pin(19), Pin(16)),) |
|||
elif "esp32" in sys.platform: |
|||
spi_instances = [ |
|||
(1, Pin(18), Pin(19), Pin(21)), |
|||
] |
|||
if "ESP32C3" not in str(sys.implementation): |
|||
spi_instances.append((2, Pin(18), Pin(19), Pin(21))) |
|||
else: |
|||
print("Please add support for this test on this platform.") |
|||
raise SystemExit |
|||
|
|||
|
|||
def get_real_baudrate(spi): |
|||
# Return the 'real' baudrate for a SPI object, from parsing 'print' output |
|||
# i.e. |
|||
# SPI(id=1, baudrate=500000, polarity=0, phase=0, bits=8, firstbit=0, sck=14, mosi=13, miso=12) |
|||
# |
|||
# Note the 'real' rate may be quite different to the requested rate, i.e. |
|||
# on ports where the SPI hardware only supports power of 2 clock dividers. |
|||
# |
|||
# Implementation is somewhat fiddly and inefficient to avoid dependency on |
|||
# 're' module, |
|||
s = str(spi) |
|||
s = s.split("baudrate=")[1].split(",")[0] |
|||
return int(s) |
|||
|
|||
|
|||
def test_instances(): |
|||
print_results = True |
|||
for spi_id, sck, mosi, miso in spi_instances: |
|||
for baudrate in ( |
|||
100_000, |
|||
250_000, |
|||
800_000, |
|||
1_000_000, |
|||
2_000_000, |
|||
4_000_000, |
|||
8_000_000, |
|||
): |
|||
test_spi( |
|||
spi_id, |
|||
sck, |
|||
mosi, |
|||
miso, |
|||
baudrate, |
|||
0, |
|||
0, |
|||
print_results, |
|||
) |
|||
|
|||
for baudrate in (100_000, 4_000_000): |
|||
# Test the other polarity and phase settings |
|||
for polarity, phase in ((0, 1), (1, 0), (1, 1)): |
|||
test_spi( |
|||
spi_id, |
|||
sck, |
|||
mosi, |
|||
miso, |
|||
baudrate, |
|||
polarity, |
|||
phase, |
|||
print_results, |
|||
) |
|||
|
|||
# Ensure the same test output regardless of how many SPI instances are tested |
|||
print_results = False |
|||
|
|||
|
|||
wr_short = b"abcdefghijklmnop" * 10 |
|||
rd_short = bytearray(len(wr_short)) |
|||
|
|||
wr_long = wr_short * 20 |
|||
rd_long = bytearray(len(wr_long)) |
|||
|
|||
|
|||
def test_spi(spi_id, sck, mosi, miso, baudrate, polarity, phase, print_results): |
|||
if sck: |
|||
s = SPI( |
|||
spi_id, |
|||
sck=sck, |
|||
mosi=mosi, |
|||
miso=miso, |
|||
baudrate=baudrate, |
|||
polarity=polarity, |
|||
phase=phase, |
|||
) |
|||
else: |
|||
s = SPI(spi_id, baudrate=baudrate, polarity=polarity, phase=phase) |
|||
|
|||
# to keep the test runtime down, use shorter buffer for lower baud rate |
|||
wr_buf = wr_long if baudrate > 500_000 else wr_short |
|||
rd_buf = rd_long if baudrate > 500_000 else rd_short |
|||
|
|||
real_baudrate = get_real_baudrate(s) |
|||
assert real_baudrate |
|||
transfer_time_ms = len(wr_buf) * 8 * 1000 // real_baudrate |
|||
|
|||
def test_write_readinto(): |
|||
s.write_readinto(wr_buf, rd_buf) |
|||
|
|||
def test_write(): |
|||
s.write(wr_buf) |
|||
|
|||
def test_readinto(): |
|||
s.readinto(rd_buf) |
|||
|
|||
for test_func, name in ( |
|||
(test_write_readinto, "write_readinto"), |
|||
(test_write, "write"), |
|||
(test_readinto, "readinto"), |
|||
): |
|||
t0 = time.ticks_ms() |
|||
test_func() |
|||
transfer_time = time.ticks_diff(time.ticks_ms(), t0) |
|||
t_delta = abs(transfer_time - transfer_time_ms) |
|||
t_ok = t_delta < MAX_DELTA_MS |
|||
|
|||
if print_results or not t_ok: |
|||
print( |
|||
None if print_results else spi_id, |
|||
baudrate, |
|||
polarity, |
|||
phase, |
|||
name, |
|||
t_ok or t_delta, |
|||
) |
|||
|
|||
s.deinit() |
|||
|
|||
|
|||
test_instances() |
@ -0,0 +1,39 @@ |
|||
None 100000 0 0 write_readinto True |
|||
None 100000 0 0 write True |
|||
None 100000 0 0 readinto True |
|||
None 250000 0 0 write_readinto True |
|||
None 250000 0 0 write True |
|||
None 250000 0 0 readinto True |
|||
None 800000 0 0 write_readinto True |
|||
None 800000 0 0 write True |
|||
None 800000 0 0 readinto True |
|||
None 1000000 0 0 write_readinto True |
|||
None 1000000 0 0 write True |
|||
None 1000000 0 0 readinto True |
|||
None 2000000 0 0 write_readinto True |
|||
None 2000000 0 0 write True |
|||
None 2000000 0 0 readinto True |
|||
None 4000000 0 0 write_readinto True |
|||
None 4000000 0 0 write True |
|||
None 4000000 0 0 readinto True |
|||
None 8000000 0 0 write_readinto True |
|||
None 8000000 0 0 write True |
|||
None 8000000 0 0 readinto True |
|||
None 100000 0 1 write_readinto True |
|||
None 100000 0 1 write True |
|||
None 100000 0 1 readinto True |
|||
None 100000 1 0 write_readinto True |
|||
None 100000 1 0 write True |
|||
None 100000 1 0 readinto True |
|||
None 100000 1 1 write_readinto True |
|||
None 100000 1 1 write True |
|||
None 100000 1 1 readinto True |
|||
None 4000000 0 1 write_readinto True |
|||
None 4000000 0 1 write True |
|||
None 4000000 0 1 readinto True |
|||
None 4000000 1 0 write_readinto True |
|||
None 4000000 1 0 write True |
|||
None 4000000 1 0 readinto True |
|||
None 4000000 1 1 write_readinto True |
|||
None 4000000 1 1 write True |
|||
None 4000000 1 1 readinto True |
Loading…
Reference in new issue