Transactional SPI

Nantonos

Well-known member
Does this look like a reasonable (non-interrupt) example of using two SPI devices with different speeds, mode etc using the transactional SPI?

Code:
#include <[color=#CC6600]SPI[/color].h>  [color=#7E7E7E]// include the new SPI library:[/color]

[color=#7E7E7E]// using two incompatible SPI devices, A and B[/color]
[color=#CC6600]const[/color] [color=#CC6600]int[/color] slaveAPin = 20;
[color=#CC6600]const[/color] [color=#CC6600]int[/color] slaveBPin = 21;

[color=#7E7E7E]// set up the speed, mode and endianness of each device[/color]
[color=#CC6600]SPISettings[/color] settingsA(2000000, [color=#006699]MSBFIRST[/color], [color=#006699]SPI_MODE1[/color]); 
[color=#CC6600]SPISettings[/color] settingsB(16000000, [color=#006699]LSBFIRST[/color], [color=#006699]SPI_MODE3[/color]); 

[color=#CC6600]void[/color] [color=#CC6600][b]setup[/b][/color]() {
  [color=#7E7E7E]// set the Slave Select Pins as outputs:[/color]
  [color=#CC6600]pinMode[/color] (slaveAPin, [color=#006699]OUTPUT[/color]);
  [color=#CC6600]pinMode[/color] (slaveBPin, [color=#006699]OUTPUT[/color]);
  [color=#7E7E7E]// initialize SPI:[/color]
  [color=#CC6600]SPI[/color].[color=#CC6600]begin[/color](); 
}

[color=#CC6600]uint8_t[/color] stat, val1, val2, result;

[color=#CC6600]void[/color] [color=#CC6600][b]loop[/b][/color]() {
  [color=#7E7E7E]// read three bytes from device A[/color]
  [color=#CC6600]SPI[/color].[color=#CC6600]beginTransaction[/color](settingsA);
  [color=#CC6600]digitalWrite[/color] (slaveAPin, [color=#006699]LOW[/color]);
  [color=#7E7E7E]// reading only, so data sent does not matter[/color]
  stat = [color=#CC6600]SPI[/color].[color=#CC6600]transfer[/color](0);
  val1 = [color=#CC6600]SPI[/color].[color=#CC6600]transfer[/color](0);
  val2 = [color=#CC6600]SPI[/color].[color=#CC6600]transfer[/color](0);
  [color=#CC6600]digitalWrite[/color] (slaveAPin, [color=#006699]HIGH[/color]);
  [color=#CC6600]SPI[/color].[color=#CC6600]endTransaction[/color]();
  [color=#7E7E7E]// if stat is 1 or 2, send val1 or val2 else zero[/color]
  [color=#CC6600]if[/color] (stat == 1) { 
   result = val1;
  } [color=#CC6600]else[/color] [color=#CC6600]if[/color] (stat == 2) { 
   result = val2;
  } [color=#CC6600]else[/color] {
   result = 0;
  }
  [color=#7E7E7E]// send result to device B[/color]
  [color=#CC6600]SPI[/color].[color=#CC6600]beginTransaction[/color](settingsB);
  [color=#CC6600]digitalWrite[/color] (slaveBPin, [color=#006699]LOW[/color]);
  [color=#CC6600]SPI[/color].[color=#CC6600]transfer[/color](result);
  [color=#CC6600]digitalWrite[/color] (slaveBPin, [color=#006699]HIGH[/color]);
  [color=#CC6600]SPI[/color].[color=#CC6600]endTransaction[/color]();
}

Edit I made a copy of Arduino 1.0.5-r2 with TeensyDuino 1.20-rc1 installed, then deleted the SPI folder in the linraries directory and added SPI from Paul's github. The above example compiles. Since it is using pretend devices A and B I can't test that it works though. This is the example in the HTML documentation (see next post).
 
Last edited:
Proposed updated documentation

Here is a drop-in replacement for the PRJC Teensyduino SPI page.

Changes:
- split configuration into what is being changed (speed, mode etc) with more explanation, and how it is changed (transactional way and deprecated way)
- added description and example of transactional method
- updated pin number table for Teensy 3.1 and for alternate pins
- added a section on setting alternate SPI pins
- moved SPI slave section to end, added link to Nick Gammon's discussion
- added more explanation generally

This is a zip as the forum doesn't allow html attachments. The existing td_libs.css and td_libs_SPI_1.jpg are used so this should be put at the same place. Its is an edited copy of the page on PJRC so if the navigation stuff on the left is inserted dynamically that will need to be removed from this static copy.
View attachment newSPI.zip
 
I wrote a blog article today about this project, with special mention for Nantonos.

My intention is to update the PJRC web page after 1.20 is published. Maybe it should be updated when 1.20-rc2 is out? Anyway, just want to let you know I haven't forgotten this. I really do appreciate it and I'm going to use it soon.
 
Last edited:
Thanks for the mention!

I see in another blog post, Display & SPI Optimization you talk about using the native CS lines rather than GPIO:
Fortunately, Teensy 3.1's SPI port can control up to 5 "chip select" lines.
...
However, controlling these signals does come with a cost in software complexity.

I guess the SPI page should add a section on that, too. But it can always be added later.
 
Paul, will the updated SPI page appear on PJRC at some point? I'm willing to update other pages (each of which involves a deep trawl through the whole forum) but, like you, I get discouraged if my contributions don't seem to get incorporated.

Speaking of which, I see a pull request from Cristian Maglie backporting transactional SPI from Arduino 1.5.x to 1.0.x and he says
I've just prepared a pull request to backport SPI Transactions on (soon
to be released) Arduino IDE 1.0.7
.
 
I put the new SPI page in place. I added a few minor edits, mostly to put the new functions in the usage section.

http://www.pjrc.com/teensy/td_libs_SPI.html

Thanks for working on that. It's a huge help!

Sorry for the delay. So much stuff got pushed aside while I was cramming to get the audio lib released. I'm still not caught up, but at least I'm making some progress....
 
hi there... i have just noticed this update to the library last night and i am trying to learn about how to use it so i can implement it into my code very soon. i like the idea of how the new transactions work as i am mainly using interrupts/external in my projects. i have been setting spi up manually using gammons spi as a reference and using the datasheet (i am still newish to arduino). i have two questions however...

1. the new usinginterrupts function - do i declare only that other librarys will be using spi from inside different interrupts or do i declare that there is any other interrupts happening in any situation whether the interrupt is using SPI or not (say external zero cross detector)? as on one project i have a zero cross detector on INT0 and i dont know if i should tell the SPI lib to disable that or if this usinginterrupts is just for other libs for spi like ethernet (i have never used another lib that conflicts with spi so i have not run into these problems YET)

2. the old SPI.attachinterrupt is said not to be used... i currently use this on the salve (SPIE) from gammons webpage and use the spi_anything_ISR to send an int over... this grabs SPDR first which the new (and old) spi lib does not do... so apart from modifying the lib to be able to take transactions on the slave side from inside the SPIE interrupt (so make it grab SPDR first when an interrupt occurs and then load the slave SPDR for return transaction OR for loop to get the next byte) other than this is there anything else i should be aware of using SPIE? is it that i should just not use this on the master? or is the reason for stating it should not be used because the SPI lib does not take into account that the SPDR will have the first byte when SPIE interrupt is first run so the first byte would be lost? can some one please give a broader explanation on this please as i dont want to miss something as i have spent days and days on getting spi working already.

any information would be greatly appreciated... i understand most of the code in the new lib but i dont (fully) understand the two points i am asking about (confusion i think mainly from comments)
 
Back
Top