diff --git a/tests/extmod/machine_spi_rate.py b/tests/extmod/machine_spi_rate.py new file mode 100644 index 0000000000..df9e3fbd0d --- /dev/null +++ b/tests/extmod/machine_spi_rate.py @@ -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() diff --git a/tests/extmod/machine_spi_rate.py.exp b/tests/extmod/machine_spi_rate.py.exp new file mode 100644 index 0000000000..6102016154 --- /dev/null +++ b/tests/extmod/machine_spi_rate.py.exp @@ -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