Skip to content

SPI

Serial Peripheral Interface (SPI) is a de facto standard (with many variants) for synchronous serial communication, mainly used for short-distance wired communication between integrated circuits in embedded systems.

Preparation

  • A Rhino Pi-A1
  • A female-to-female jumper wire

Connection

No.Board SilkscreenGPIO/System MappingDescription
12SPI1_MISOSPI1_MISOSPI1 master-in slave-out, serial data receive channel
14SPI1_MOSISPI1_MOSISPI1 master-out slave-in, serial data transmit channel
16SPI1_CLKSPI1_CLKSPI1 serial clock, synchronizes bus data transmission
18SPI1_CS_NSPI1_CS_NSPI1 chip select signal, active low, selects slave device

Use a jumper wire to short-circuit pins 12 and 14 (MISO and MOSI loopback test).

Testing

  • Check the spidev devices
shell
ls /dev/spidev*
  • Open a terminal and enter the command to install the required Python library.
shell
sudo pip3 install spidev
  • Create a file named spitest.py and paste the following code into it:
python
import spidev
import time


class SPILoopbackTester:
    def __init__(self, bus=0, device=0, speed=1000000):
        """
        Initialize the SPI loopback tester
        :param bus: SPI bus number
        :param device: SPI device number
        :param speed: Communication speed (Hz)
        """
        self.spi = spidev.SpiDev()
        self.bus = bus
        self.device = device
        self.speed = speed
        self.connected = False

    def connect(self):
        """Connect to the SPI device"""
        try:
            self.spi.open(self.bus, self.device)
            self.spi.max_speed_hz = self.speed
            self.connected = True
            print(f"Successfully connected to SPI bus {self.bus}, device {self.device}, speed {self.speed}Hz")
            return True
        except Exception as e:
            print(f"SPI connection failed: {e}")
            return False

    def test_single_byte(self, test_byte):
        """Test the loopback of a single byte"""
        if not self.connected:
            print("Please connect the SPI device first")
            return False

        try:
            # Send and receive data
            rx_data = self.spi.xfer2([test_byte])
            received_byte = rx_data[0]

            # Verify the result
            if received_byte == test_byte:
                print(f"Test passed - sent: 0x{test_byte:02X}, received: 0x{received_byte:02X}")
                return True
            else:
                print(f"Test failed - sent: 0x{test_byte:02X}, received: 0x{received_byte:02X}")
                return False
        except Exception as e:
            print(f"Test error: {e}")
            return False

    def test_multiple_bytes(self, test_data):
        """Test the loopback of multiple bytes"""
        if not self.connected:
            print("Please connect the SPI device first")
            return False

        try:
            # Send and receive data
            rx_data = self.spi.xfer2(test_data)

            # Verify the result
            success = True
            print("Multi-byte test results:")
            print("Sent\tReceived\tResult")
            print("-" * 30)
            for tx, rx in zip(test_data, rx_data):
                status = "Passed" if tx == rx else "Failed"
                if tx != rx:
                    success = False
                print(f"0x{tx:02X}\t0x{rx:02X}\t{status}")

            return success
        except Exception as e:
            print(f"Test error: {e}")
            return False

    def run_complete_test(self):
        """Run the complete test suite"""
        print("\n===== Starting SPI loopback test =====")
        print(f"Test configuration: bus={self.bus}, device={self.device}, speed={self.speed}Hz")

        # Test individual special bytes
        test_bytes = [0x00, 0xFF, 0xAA, 0x55, 0x33, 0xCC]
        single_byte_result = True

        print("\n----- Single-byte test -----")
        for b in test_bytes:
            if not self.test_single_byte(b):
                single_byte_result = False

        # Test a random sequence
        print("\n----- Multi-byte sequence test -----")
        sequence = list(range(0, 256, 16))  # 0x00, 0x10, 0x20, ..., 0xF0
        multi_byte_result = self.test_multiple_bytes(sequence)

        # Test continuous data
        print("\n----- Continuous data test -----")
        continuous_data = list(range(10, 20))  # Consecutive numbers from 10 to 19
        continuous_result = self.test_multiple_bytes(continuous_data)

        # Overall result
        print("\n===== Test summary =====")
        overall_result = single_byte_result and multi_byte_result and continuous_result

        if overall_result:
            print("✅ All SPI loopback tests passed!")
        else:
            print("❌ Some SPI loopback tests failed!")

        return overall_result

    def close(self):
        """Close the SPI connection"""
        if self.connected:
            self.spi.close()
            self.connected = False
            print("\nSPI connection closed")


if __name__ == "__main__":
    # Create the tester instance (default uses SPI0, CE0)
    tester = SPILoopbackTester(bus=1, device=0, speed=1000000)

    try:
        if tester.connect():
            # Run the complete test
            tester.run_complete_test()
            time.sleep(1)
    finally:
        # Ensure resources are released properly
        tester.close()
  • After saving, enter the following command to test
shell
sudo python3 spitest.py
  • Check the output result

The result will print "All SPI loopback tests passed!"