SPI performance

General discussion about anything related to Ultibo.
heju
Posts: 3
Joined: Tue May 01, 2018 5:11 pm

SPI performance

Postby heju » Wed Jun 13, 2018 7:54 pm

Hi all,

I did a quick test with the logic analyzer to see what spi speeds can be achieved for single transactions.
The Pi1 is connected to a MCP ADC for this test, however this obviously does not matter here.

Code as follows:
SPI init

Code: Select all

SPIDeviceStart(SPIDevice, SPI_MODE_4WIRE, 2000000, SPI_CLOCK_PHASE_LOW, SPI_CLOCK_POLARITY_LOW)


Now a infinite loop executes

Code: Select all

SPIDeviceWriteRead(SPIDevice, SPI_CS_0, SourceBuffer,DestBuffer, sizeof(send)*8, SPI_TRANSFER_NONE, count)
(count:=1)

Analyzer output for one frame: CLK is 2MHz as expected, CS low encapsulates the sequence nicely.
https://ibb.co/kdDwZd

However in between the consecutive frames we have large gaps of ~0.5ms
https://ibb.co/mYB5Sy

This limits somehow the speed for consecutive single transactions.

I never did a comparable test on the Pi running linux, is this a hard limitation or did I miss something?

Greetings!
User avatar
Ultibo
Site Admin
Posts: 2079
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: SPI performance

Postby Ultibo » Wed Jun 13, 2018 11:51 pm

heju wrote:However in between the consecutive frames we have large gaps of ~0.5ms

This limits somehow the speed for consecutive single transactions.

I never did a comparable test on the Pi running linux, is this a hard limitation or did I miss something?

What you are seeing is mostly the result of trying to create a high level API that covers the requirements of as many people as possible.

If you look at the driver level implementation of SPIDeviceWriteRead (for example BCM2709SPI0WriteRead) you will see that it does a lot of setup work for each transaction.

Determining the mode, chip select, clock rate, setting the control registers to enable the actual transaction and then performing memory barriers to ensure correct ordering etc, probably one of the biggest elements of the 0.5ms gap will be due to the use of SemaphoreWait to cause the calling thread to wait for the transaction to complete.

SemaphoreWait will place the thread onto a wait list and once the interrupt signals the completion it will be returned to the scheduling queue to await rescheduling, the scheduler interrupt only triggers every 500us so it can take up to this amount of time for the thread to be woken after the completion.

Of course if you need to send longer transactions then the SPIDeviceWriteRead function allows for that, your device also has to support receiving a larger block of data and your application needs to have the data available to send.

Multiple different approaches would be possible, one idea might be to create a custom version of the SPI0 driver which either doesn't use SemaphoreWait (perhaps using a non sleep delay instead) or going further and creating a driver that takes a circular buffer and keeps sending transactions as long as their is data available.

We are open to ideas that might make the API more useful for a wider range of tasks so if you have any thoughts please let us know.
Ultibo.org | Make something amazing
https://ultibo.org
User avatar
Ultibo
Site Admin
Posts: 2079
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: SPI performance

Postby Ultibo » Thu Jun 14, 2018 1:04 am

One thing I forgot to mention,

heju wrote:

Code: Select all

SPIDeviceWriteRead(SPIDevice, SPI_CS_0, SourceBuffer,DestBuffer, sizeof(send)*8, SPI_TRANSFER_NONE, count)
(count:=1)

I'm not sure I am reading this correctly, if you are passing the size value as sizeof(send)*8 then count should be more than 1 on return. From the code the function will only return success if the returned count equals the requested size.
Ultibo.org | Make something amazing
https://ultibo.org
rainier
Posts: 10
Joined: Mon May 28, 2018 1:47 pm

Re: SPI performance

Postby rainier » Thu Jun 14, 2018 1:19 pm

As part of my research into all things Pi and Ultibo with the view of integrating both into our products my take on the SPI is:

Do not use the provided libraries, you are inheriting too much "Linux". Simply deal with the peripheral directly. It appears simple enough. With Ultibo you can dedicate a core on the quad core chip for doing these kind of things if you like - that way you have a real time system.
If you need interrupts - consider bypassing most of Ultibo's IRQ handler at its root if you have a pending interrupt for your device. Your handler can then deal with your SPI or data management as you see fit without the considerable "built in" interrupt bloatware. Just make sure your handler does not call into any Ultibo code as that could produce some interesting effects. As long as you are just moving data buffers in and out - no issue.
I am busy designing a carrier board for the CM3 at the moment to plug into our systems (replacing a Ti AM3517 based board). Due to the limited I/O on the CM3 I am planning to use the Pi SPI0 device as fast as it will go to a STM32H7 which will then provide the actual interfaces into the system and also provide a few things that are missing on the CM3 that I need.
The CM3 in this case runs the display and the executive while the STM does the hardcore stuff and the SPI provides the data lane between the two. I considered the USB for that but decided the SPI looks fast enough so I'd rather reserve the USB for other fun things. I am considering the above approach using a dedicated core for the SPI - since that core does nothing else there is no need for DMA and I could even use a second SPI master into the STM, probably not needed...

It's an experiment at this stage - will be interesting where this goes...

Return to “Discussion”

Who is online

Users browsing this forum: No registered users and 1 guest