adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.09k stars 1.22k forks source link

Slow SPI transactions #3354

Closed jerryneedell closed 4 years ago

jerryneedell commented 4 years ago

I have been doing some timing tests of SPI transactions

This is on a feather_m0_rfm69 (SAMD21) but there are similar delays on SAMD51 and STM32F504. The delays are shorter on the faster boards, but still seem long.

There seem to be very long delays between the SPI transactions. This figure shows a write operation The interesting thing is how long it takes before the writes actually happen top 4 traces are MOSI/MISO/SCK/CS trace 5 is D13 -- self.led in the code trace 6 is D12 -- self.signal in the code

D13 is set High when the write function is called D12 is set High when the actual spi write starts after getting set up see the code snippet below from the rfm69 module

As you can see, there is nearly a millisecond of delay before the write actually begins.

This same delay is present every SPI transaction. Like the second picture when it is polling for a packet receipt.

There just seem to be a lot of dead time. My question is, is these delays between transactions expected and necessary?

If I run this in Arduino, the delays between transactions are in microseconds.

SPI_M0

SPI_M0_2

    def _read_into(self, address, buf, length=None):
        # Read a number of bytes from the specified address into the provided
        # buffer.  If length is not specified (the default) the entire buffer
        # will be filled.
        self.signal.value=True
        if length is None:
            length = len(buf)
        with self._device as device:
            self._BUFFER[0] = address & 0x7F  # Strip out top bit to set 0
            # value (read).
            self.led.value=True
            device.write(self._BUFFER, end=1)
            device.readinto(buf, end=length)
            self.led.value=False
        self.signal.value=False

    def _read_u8(self, address):
        # Read a single byte from the provided address and return it.
        self._read_into(address, self._BUFFER, length=1)
        return self._BUFFER[0]

    def _write_from(self, address, buf, length=None):
        # Write a number of bytes to the provided address and taken from the
        # provided buffer.  If no length is specified (the default) the entire
        # buffer is written.
        self.signal.value=True
        if length is None:
            length = len(buf)
        with self._device as device:
            self._BUFFER[0] = (address | 0x80) & 0xFF  # Set top bit to 1 to
            # indicate a write.
            self.led.value=True
            device.write(self._BUFFER, end=1)
            device.write(buf, end=length)  # send data
            self.led.value=False
        self.signal.value=False

    def _write_u8(self, address, val):
        # Write a byte register to the chip.  Specify the 7-bit address and the
        # 8-bit value to write to that address.
        self.signal.value=True
        with self._device as device:
            self._BUFFER[0] = (address | 0x80) & 0xFF  # Set top bit to 1 to
            # indicate a write.
            self._BUFFER[1] = val & 0xFF
            self.led.value=True
            device.write(self._BUFFER, end=2)
            self.led.value=False
        self.signal.value=False
tannewt commented 4 years ago

We discussed this in today's weekly meeting: https://youtu.be/CqDPd4dVNaI?t=3530

The conclusion was that this is expected Python slowness setting up the transaction. The gap between 4 bytes transmitting is due to manually providing bytes to the peripheral rather than using DMA.

hierophect commented 4 years ago

@tannewt is having a more streamlined DMA process something you'd like to eventually explore?

tannewt commented 4 years ago

@hierophect Not really. The SPI delays are very minor compared to the setup cost in Python.

hierophect commented 4 years ago

@tannewt would you recommend closing this, in that case? Or are there other performance improvements you'd envision long term?

tannewt commented 4 years ago

Nothing concrete. Will close.