mirror of
https://github.com/micropython/micropython.git
synced 2025-09-07 18:30:27 +02:00
156 lines
4.3 KiB
Python
156 lines
4.3 KiB
Python
# 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:
|
|
impl = str(sys.implementation)
|
|
if "ESP32C3" in impl or "ESP32C6" in impl:
|
|
spi_instances = ((1, Pin(4), Pin(5), Pin(6)),)
|
|
else:
|
|
spi_instances = ((1, Pin(18), Pin(19), Pin(21)), (2, Pin(18), Pin(19), Pin(21)))
|
|
elif "esp8266" in sys.platform:
|
|
MAX_DELTA_MS = 50 # port requires much looser timing requirements
|
|
spi_instances = ((1, None, None, None),) # explicit pin choice not allowed
|
|
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()
|