Skip to content

Proof-of-concept for async SPI#4

Open
loganb wants to merge 2 commits intoPaulStoffregen:masterfrom
loganb:async_spi
Open

Proof-of-concept for async SPI#4
loganb wants to merge 2 commits intoPaulStoffregen:masterfrom
loganb:async_spi

Conversation

@loganb
Copy link
Copy Markdown

@loganb loganb commented Dec 29, 2014

Hello,

I'm working on an extension to the SPI interface that I'd like to eventually get all the way upstream to Arduino core. It builds off your existing work to provide SPI transactions. This patch is a proof-of-concept that I can continue to flesh out. I need several things from you at this juncture:

  • Early feedback on the design/naming/etc.
  • Any flags or issues that would block you from merging the PR
  • Any guidance you can provide on how to get this into upstream core

This extension uses interrupts to transfer an entire buffer via SPI asynchronously while the main Arduino loop runs. It interacts cleanly with beginTransaction()/endTransaction(). Additionally, interrupt handlers can safely queue async transfers. This greatly simplifies working with libraries since the end user no longer needs to know what interrupts that library uses and pepper their code with usingInterrupt() calls (which can't compose across libraries anyways).

Usage

Here's an example program that kicks off three SPI transactions:

#include "SPI.h"
uint8_t buf1[] = { 0x01, 0x02 },
        buf2[] = { 0x03, 0x04 },
        buf3[] = { 0x05, 0x06 };

SPISettings theSettings = SPISettings(100000, MSBFIRST, SPI_MODE0);

SPIQueuedTransfer t1(buf1, 2, theSettings, 0, 0),
                  t2(buf2, 2, theSettings, 0, 0),
                  t3(buf3, 2, theSettings, 0, 0);

void setup() {
  pinMode(13, OUTPUT); //High while transfers are queued
  pinMode(14, OUTPUT); //High while SPI ISR is running
  pinMode(15, OUTPUT); //High while workTransferQueue

  digitalWrite(13, 0);
  SPI.begin();

  SPI.queueTransfer(&t1);
  SPI.queueTransfer(&t2);
  SPI.queueTransfer(&t3);
  digitalWrite(13, 1);

  //Do some things...

  //Hold up execution until all transfers are complete
  while(!t1.is_completed && !t2.is_completed && !t3.is_completed);
}

Here's a trace of the output from the above program running on a Teensy 2.0 at 16Mhz with an SPI bus speed of 125kBps:

screen shot 2014-12-28 at 10 46 07 pm

Implementation Notes

  • No ordering is guaranteed across queued transfers. You can see in the trace that they are processed in a LIFO order if the SPI module is busy
  • The inTransaction flag becomes mandatory in order to interoperate gracefully with begin/endTransaction()
  • Memory overhead is approximately 5-bytes + 8-bytes per queued transfer

Performance

Using the ISR consumes more cycles than polling when the SPI bus is running very fast. In the trace above, the per-queued-transfer cost is about 19µS, implying that async transfers are advantageous for transfers when the SPI bus is running slower than about 2Mbps. This may not seem very useful, but the gains should be quite marked on the Teensy 3.x and other ARM-based Arduinos where the CPU runs at 48+Mhz and the FIFO queues allow transfers up to 8 bytes between interrupts.

TODO

I have only implemented a proof-of-concept for AVR; there is no ARM implementation yet. The naming can probably also use a pass. endTransaction() still needs a few lines of code to kick off any queued transfers.

@PaulStoffregen
Copy link
Copy Markdown
Owner

To gain acceptance into upstream Arduino, this really needs to be proposed and discussed on Arduino's Developers mail list.

https://groups.google.com/a/arduino.cc/forum/#!forum/developers

Unfortunately, that list can be quite painful, but it's the only path to proposing this sort of huge API change. It's also a very slow path. SPI transactions took many months from initial discussion until the pull request was merged.

@loganb
Copy link
Copy Markdown
Author

loganb commented Dec 30, 2014

Hi Paul, I sent an email to the list that's awaiting moderation. Thanks for the heads up. I'd appreciate any feedback you have in the mean time. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants