Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proof-of-concept for async SPI #4

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

loganb
Copy link

@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
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
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