SPI sharing between interrupts and main program

Yes, it is exactly ATOMIC_BLOCK, that is the entire idea. Yes, it is brute force, and that is actually the only way to make it ISR safe.

Quite a lot has happened on this SPI sharing topic over the last few weeks. The conversation has mostly been on the Arduino Developers mail list.

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

Adding a fix only in Teensyduino and then patching several dozen libraries would probably be quicker and easier than trying to work with the Arduino Team. It's always a long and slow process to get them to accept anything other than simple bug fixes, though the situation is vastly improved now that Cristian Maglie is the technical lead.

But I really do believe this needs to be fixed upstream and become part of the official SPI library. Long term, that'll make for less maintenance than asking lots of library authors to accept a Teensy-only patch.

Here's the proposal:


I'd like to propose and work on an extended API for the SPI library. Of
course, before beginning, I'm asking here for comments and feedback on
the API, and hopefully a tentative yeah/nay from Cristian.

My goal is improving compatibility between SPI-based libraries. Some
libraries work well together, like Ethernet and SD, but many others
conflict, because of different SPI settings or usage within interrupt
routines.

My hope is to define an API that allows the actual implementation inside
the SPI library to work across different platforms, which may involve
different implementations. But the API should be the same, so libraries
and sketches using SPI can use the functions with the same parameters.

So far, my plan involves 3 new functions:

SPI.beginTransaction(clockRate, bitOrder, dataMode);
SPI.endTransaction();
SPI.usingInterrupt(interruptNumber);

The beginTransaction() function is meant to be called before asserting a
chip select signal and performing a group of SPI transfers. It will
obsolete setClockDivider(), setBitOrder() and setDataMode(). The SPI
library will "know" if any SPI usage involves interrupts and take
appropriate steps to ensure this SPI transaction is atomic. Of course,
endTransaction() ends the transaction, usually right after deasserting
the chip select.

The usingInterrupt() function is how the SPI library will become
interrupt aware. If no calls have been made to SPI.usingInterrupt(),
then SPI.beginTransaction() will leave interrupts fully enabled. But if
any usage of SPI is from interrupts, SPI.beginTransaction() will disable
at least those interrupts. The specific mechanism will likely vary
across platforms, perhaps using interrupt priority levels on ARM and
simple masking or global disable on AVR. The specific implementation
inside the SPI library can be very simple or very sophisticated and can
be changed while keeping the API stable.

The interruptNumber arg is an integer, the same as used with
attachInterrupt(). SPI.usingInterrupt() might also support other
platform-specific numbers, to represent the other interrupts. If an
unknown interrupt number is given, SPI.beginTransaction() should fall
back to global interrupt disable during transactions. This behavior
will guarantee SPI-based libraries always work together. The
implementation within SPI can be improved, without any API change, to
support more selective interrupt masking.

I'd also like to add constants to SPI.h for the clockRate parameter,
based on actual frequencies. These would be automatically adapted by
#ifdefs based on F_CPU. The "DIV" parameters should be deprecated. New
SPI code should use names with actual frequencies, where the library
will use the closest available frequency that does not exceed the spec.

I realize this is a pretty substantial change to a very widely used
library. My goal is to maintain backwards compatibility. The many
libraries using SPI will gradually adopt the new API, perhaps with some
symbol like SPI_HAS_TRANSACTION to test for the new API at compile time.
 
The usingInterrupt() function is how the SPI library will become
Interrupt aware. If no calls have been made to SPI.usingInterrupt(),
then SPI.beginTransaction() will leave interrupts fully enabled. But if
any usage of SPI is from interrupts, SPI.beginTransaction() will disable
at least those interrupts. The specific mechanism will likely vary
across platforms, perhaps using interrupt priority levels on ARM and
simple masking or global disable on AVR. The specific implementation
inside the SPI library can be very simple or very sophisticated and can
be changed while keeping the API stable.

The interruptNumber arg is an integer, the same as used with
attachInterrupt(). SPI.usingInterrupt() might also support other
platform-specific numbers, to represent the other interrupts. If an
unknown interrupt number is given, SPI.beginTransaction() should fall
back to global interrupt disable during transactions. This behavior
will guarantee SPI-based libraries always work together. The
implementation within SPI can be improved, without any API change, to
support more selective interrupt masking.

I think that all interrupt based libraries could benefit from this type scheme. Now that more, at least ARM (teensy) libraries are becoming priority aware, some protocol to deal with these instead of just a global enable and disable interrupt would be beneficial. Is your goal to make each SPI transaction unique in that no other higher priority SPI transfer can preempt it, if so wouldn't you just set all SPI priority levels the same? I know i'm not dealing with AVR's but all I'm concerned about is teensy implementation at the moment.

Another thing i was wondering about is if you are in the middle of a lengthy SPI transaction and a higher priority ISR if fired and preempts the SPI transaction would that SPI transaction be moot, meaning would I have to send it again. Just trying to wrap my head around this very complex priority mechanism we have.
 
Paul, Why the complex stuff? This entire transaction begin and transaction end business is really not needed if you just do your transaction in one shot.
It is bad for performance, and prone to errors, like 'Oops, forgot to [begin/end] my transaction'.

For C, why not just treat what you are doing like a file (call it SPIopen) and get back a descriptor (a number), and then just simply do read and write to it using the descriptor like as if it was a file, using the number to index the settings? When done 'close' it.

If you dislike that and want to stay with C++, do a class with a constructor and destructor.

For a class with C++ I'd do something like this (C code would be similar, but it would just return a descriptor instead, the concept is identical):

In this example, 'xSPI' is the extended class example name, 'x' is for 'eXtra cool' :cool:

A constructor could be:
Code:
xSPI MySPI1(clockRate, bitOrder, dataMode, slaveSelectPin, &IRQCallback);

Do as many as you like, name them whatever you want.
The IRQCallback should be a function callback, and if NULL, then no IRQ is used.
If an IRQ is used, we register that fact elsewhere, and use the callback to disable it while doing a transaction, and to enable it when done. the callback can be as simple as:

Code:
MySpi1Callback(boolean enable) {
        if(enable) {
                // do whatever here to enable the ISR
        } else {
                //do whatever here to disable the ISR
        }
}
...
Then just call:
Code:
MySPI1.write(&data, uint16_t length); // for a write
MySPI1.read(&data, uint16_t length); // for a read
MySPI1.readwrite(&datain, &dataout, uint16_t length); // for a write with a read at the same time, although I personally have never used any device that does this
...
These would:

  1. disable all known ISRs
  2. set the rates
  3. assert the pin
  4. perform the data transfer
  5. un-assert the pin
  6. and finally enable all ISRs
(in that order!)
The cool part is that already knows what the slave pin is, and all the other needed details.

Now as far as single bytes of data, I have found that sending an array of bytes is better performance-wise no matter what micro-controller you are using.
This is because you reduce the total latency between each byte sent on the wire if you use something that is very high speed, and you only do one call..

So from my research, the best way is for the code to just lump the transaction data together and send it entirely in one shot... this is what spi4teensy3 does, and the speeds it can reach are proof that batch transaction is the way to go. Use an array, everything else is pretty much nonsense and a complete waste of CPU cycles.

I also I think my idea is a lot simpler, less error prone, and just makes more sense all around.

Now not to confuse anybody, I've also heard of another idea that the actual transaction could happen in a separate ISR, kind of like Serial would do, but IMHO that is overkill ;)
Worse, how would you even do a read... too much of a hassle, it would be a coding nightmare.
 
SPI.beginTransaction() would have to disable interrupts from ISR devices/means that do use the same SPI port, including those that use pin interrupts and perhaps DMA complete interrupts. This disable is to ensure that the non-ISR code in the transaction isn't interrupted and the ISR uses the SPI port.

With 2+ devices using the same SPI port, there has to be exclusion between all non-ISR code that touches the SPI and all ISRs. An interrupt (pin or ?) may occur at any time. The begin() and end() non-ISR function has to disable the relevant pin interrupt(s) in that begin/end transaction time window. Or brute force disable all but systick, or some such. I think this is the intent. But it seems like a registry of some sort is needed so that the begin() can know which pin interrupts to disable, rather than disabling all interrupt sources, or all except the systick, etc. I suppose this is what the intent of the begin/end is. But the hard part is keeping track of what pin interrupts exist that may use the same SPI. There's also DMA-complete interrupts, where that interrupt service also needs to do SPI transfers to finish up.

Note too that though the Teensyduino and Arduino libraries are single-stack, single thread, the yield() function can (is) sometimes used to run "background" code that may want to do SPI work. This is a form of cooperative scheduling. At first blush, this is a non-issue with a solution that deals with the single-stack thread. It gets more complex of course with a stack-per-task scheduler/RTOS, but that I suppose is to be procrastinated - considering the intent of simplicity.
(Aside: As I recall, the Teensy port of FreeRTOS uses (weak override) of yield() to call the scheduler in RTOS and that may stack the registers using an ARM software interrupt, then switch tasks. This is cooperative scheduling in a stack per task setting. Preemption (in the systick ISR) is optional.)

Doesn't the C++ constructor/destructor run the risk, over time, causing too much fragmentation in the heap? This idea is disconcerting.

For (too many?) existing apps that access SPI hardware directly, and cannot be coordinated, do we just admonish: Don't Do That!
 
Last edited:
I also I think my idea is a lot simpler, less error prone, and just makes more sense all around.

The Arduino Developers mail list is the place to make proposals for any software maintained by Arduino.

However, I see at least 2 major problems with your proposal.

#1: With change to any widely used software, not just a SPI library but *ANY* program, backwards compatibility and a smooth migration path are critically important to its adoption. No matter how much better a new way is, once software is widely used, attempts to radically change it meet incredible resistance.

#2: You've vastly underestimated the complexity of many commonly used SPI devices and libraries.

For example, the SD library sends a command, then reads status bytes until one read indicates the card is ready, then transfers an entire block of data, all with a single assertion of CS. The data length isn't fixed or known in advance. The total number of bytes can vary on every command if the card needs more time to process requests (eg, media defect management, pre-erase of sectors, etc). The SD library also needs to send 10 bytes without CS asserted to initialize the card.

The color TFT displays manipulate 2 pins, CS and RS. The CS pin gets asserted for the entire transfer, but RS needs to change state mid-way, to tell the card which bytes are to be interpreted as commands and which are data.

Ethernet does many small transfers of 4 bytes, where each 4 byte group reads or writes 1 actual byte. Often a pair of these are used to read or write a 16 bit register. Technically, those 8 bytes with 2 assertions of CS don't have to be an atomic operation, but it would be far better for performance if the overhead of disabling interrupts and configuring the SPI settings was suffered only once. In fact, if you look at my patch to Ethernet, you'll see I put the begin/end transaction stuff at the socket level, so a group of many such transfers that forms one logical operation will be atomic and Ethernet's performance won't suffer (any more than it already does...)

CC3000 (WiFi) reuses its interrupt request pin as a ready indicator when transfers are initiated from the Arduino side. After asserting CS, the library must wait for the ready indication before transmitting data (the fact that it's also an interrupt signal makes the library structure terribly difficult). CC3000 also has special requirements on the first command, with a 50 us delay needed between the 4th and 5th byte.

Mikael Patel mentioned other SPI devices with special requirements for CS pulses, but not a continuous assert throughout the entire transfer, apparently some at the beginning and others at the end. He also mentioned some special case with one of the wireless chips, which I didn't fully understand. I couldn't find an Arduino library for that one to study what existing code did for it.

The idea of bringing CS assertion into the library has already been discussed at great length on that thread, now at 63 messages. Several people proposed something similar to what you've mentioned, having the SPI library assert CS automatically as one atomic transfer. Unfortunately, many important SPI devices have complex requirements.

Lots of Arduino library already exist, using today's API, and they handle all those requirements. This proposal with beginTransaction() and endTransaction() is the result of a lot of work and study of many libraries that actually use SPI. If you have a better proposal, please first do your homework, then post on the Arduino Developers mail list. That's the only place to discuss contributions to Arduino. Here, the best any proposal can get is Teensy-only patches distributed in the Teensyduino installer.
 
The Arduino Developers mail list is the place to make proposals for any software maintained by Arduino.

However, I see at least 2 major problems with your proposal.

#1: With change to any widely used software, not just a SPI library but *ANY* program, backwards compatibility and a smooth migration path are critically important to its adoption. No matter how much better a new way is, once software is widely used, attempts to radically change it meet incredible resistance.
Note I said it was a new class. Even so, you could do exactly like I did with the original xmem library-- mine is 100% compatible with all old code. I just add more goodness to it.
#2: You've vastly underestimated the complexity of many commonly used SPI devices and libraries.
Actually, I haven't... I've dealt with my own fair share of them, and even share the SPI bus with most of them. :)
For example, the SD library sends a command, then reads status bytes until one read indicates the card is ready, then transfers an entire block of data, all with a single assertion of CS. The data length isn't fixed or known in advance. The total number of bytes can vary on every command if the card needs more time to process requests (eg, media defect management, pre-erase of sectors, etc). The SD library also needs to send 10 bytes without CS asserted to initialize the card.
Yep.. so you simply address the oddities as-needed. I may have been a bit terse, but my class idea would be in addition to what you propose.
The color TFT displays manipulate 2 pins, CS and RS. The CS pin gets asserted for the entire transfer, but RS needs to change state mid-way, to tell the card which bytes are to be interpreted as commands and which are data.
The one I use needs 9bits on SPI, Believe me, I've seen some really convoluted conceptions of what SPI is..
What I do in this case is bit-pack them in an array, and burst out the data in 72byte-sized chunks. Since the last part is not fully 9 bits, the LCD controller will ignore the couple extra bits at the end. I've not used an LCD controller that doesn't ignore an incomplete transfer of a byte, and I am unaware of any that would be this broken.
Ethernet does many small transfers of 4 bytes, where each 4 byte group reads or writes 1 actual byte. Often a pair of these are used to read or write a 16 bit register. Technically, those 8 bytes with 2 assertions of CS don't have to be an atomic operation, but it would be far better for performance if the overhead of disabling interrupts and configuring the SPI settings was suffered only once. In fact, if you look at my patch to Ethernet, you'll see I put the begin/end transaction stuff at the socket level, so a group of many such transfers that forms one logical operation will be atomic and Ethernet's performance won't suffer (any more than it already does...)
USB host shield does the same thing when reading/writing registers, and we still send an array, it's just a small one. :)
The idea is that it speeds up the larger transfers, that is what is important. Some kind of tradeoff is going to happen anyway, and there are always corner cases.
CC3000 (WiFi) reuses its interrupt request pin as a ready indicator when transfers are initiated from the Arduino side. After asserting CS, the library must wait for the ready indication before transmitting data (the fact that it's also an interrupt signal makes the library structure terribly difficult). CC3000 also has special requirements on the first command, with a 50 us delay needed between the 4th and 5th byte.
Sounds like a broken design in the silicon. Personally, I'd go with something that works properly. Even so, you could still have your original begin/end stuff as I mentioned.
Mikael Patel mentioned other SPI devices with special requirements for CS pulses, but not a continuous assert throughout the entire transfer, apparently some at the beginning and others at the end. He also mentioned some special case with one of the wireless chips, which I didn't fully understand. I couldn't find an Arduino library for that one to study what existing code did for it.
Again, broken... LOL...
The idea of bringing CS assertion into the library has already been discussed at great length on that thread, now at 63 messages. Several people proposed something similar to what you've mentioned, having the SPI library assert CS automatically as one atomic transfer. Unfortunately, many important SPI devices have complex requirements.

Lots of Arduino library already exist, using today's API, and they handle all those requirements. This proposal with beginTransaction() and endTransaction() is the result of a lot of work and study of many libraries that actually use SPI. If you have a better proposal, please first do your homework, then post on the Arduino Developers mail list. That's the only place to discuss contributions to Arduino. Here, the best any proposal can get is Teensy-only patches distributed in the Teensyduino installer.
This is why you include your idea along with what I propose, but please, no sending the actual requirements every time. I think that since these variables are going to be in memory someplace anyway, just storing them ONCE, and not having to pass them each time is an improvement.

Call backs are a smarter idea too, the driver that is responsible for an ISR should be responsible for enable AND disable of its resources. This is really the only sane way. How else would you manage to track what ISR, or whatever is using SPI? Short answer is that an application dev shouldn't have to worry about those details.
 
are you guys assuming that if CS is false for some SPI device, then it will not assert its interrupt? Lots do so. But I wonder if this is universally true.

Can be a simplifying assumption.
 
Last edited:
While we're talking about it: Paul, you might think about DMA as well (see this other thread: http://forum.pjrc.com/threads/23253-teensy-3-0-SPI-with-DMA-nice-try).

Ultimately, I would love to see non-blocking versions of all those sd card/ethernet/radio libraries, using a common SPI interface.

In that light, I think that SPI::usingInterrupt(interruptNumber) might not be sufficient. Effectively, we would also need SPI::useChipSelect(pinNumber, activeHigh), SPI::useDMA(boolean) and other config options. For non-blocking transfers, something like SPI::setCallback(callBackFunction, param) is necessary.

I believe it might be more appropriate to define a struct spiConfig or even class spiConfig that holds all the configuration options for SPI transfers. Each SPI "client" (SdFat, Ethernet, radio, ...) could then define its own configuration and pass it to the common SPI code that then handles locks and (re-)configures the underlying hardware.

This surely must be coordinated with the Arduino folks. And the current libraries need to be adapted - or even rewritten.

Eventually, the approach could/should be adopted for other buses (I2C, OneWire, CAN, ...) as well. Which would then, effectively, create an Arduino Operating System.

And when it gets to that point, I'm no longer sure that this is what the Arduino folks really want. Isn't it all about SIMPLICITY? Does non-blocking (or even interrupt-based) I/O fit into the Arduino philosophy?
 
This is why you include your idea along with what I propose,

Again, this forum is only about Teensy. Nothing said here can be expect to influence the Arduino devs, or even have any chance they'll ever see it. The only place to make your case for what Arduino should or shouldn't do is on their developers mail list.

but please, no sending the actual requirements every time. I think that since these variables are going to be in memory someplace anyway, just storing them ONCE, and not having to pass them each time is an improvement.

This and many other things have already been discussed on the Arduino developers mail list, in that lengthy thread. Matthijs Kooijman proposed an alternate version more or less like this. He showed how it optimizes the non-const case. Placing all settings as compile-time constants in the args is the most optimum for const inputs.

It's not clear if they're really considering using that syntax, or both. But there's 2 points. #1: Matthijs already proposed this (and nearly everything mentioned here today has already been proposed in some form or another on that lengthy thread), and #2: to have pretty much any proposal taken seriously on that mail list takes a LOT of followup work. Again, read the thread to see...

Call backs are a smarter idea too, the driver that is responsible for an ISR should be responsible for enable AND disable of its resources.

This too has already been proposed and is the subject of much discussion. In fact, Christian wrote a benchmark program to explore the performance difference. I investigated why the masking approach measured slower (inline optimization wasn't being used - simple to fix).

You really should read that lengthy thread to come up to speed.

This is really the only sane way.

I personally don't agree. Callbacks are slower, even for the case of a single static callback pointer (see the benchmarking done recently). It's not simple to implement for more than a single callback. For callbacks to be effective where more than one library uses SPI from within interrupts, a list of every registered callback must be maintained, so they all get called before starting a transaction. So far, nobody has put forth such a proposed implementation, but if anyone were to try it, I'm confident the performance would be terrible, since the simple case is already much worse than the interrupt masking approach.

I'm skeptical that many 3rd party library authors will implement high quality callback functions that properly address issues specific to every platform. Even if callbacks were comparable in performance, I would much rather have code in the SPI library or core library which is authored by the maintainer of each platform. These are platform-wide issues. The authors of the many libraries have many different goals, but usually selling their particular peripheral hardware is the main one. Their motivation to make things work across all platforms is usually only proportional to the exact sales each platform might bring. Thankfully, Teensy is starting to become successful enough that many library authors care (if not enough to fix problems, at least they'll usually accept patches). But library authors shouldn't need to write callbacks that know the difference of how certain interrupts work on Teensy3 vs Arduino Due vs Arduino Uno vs Energia, etc. That sort of platform specific interrupt handling should be left to the SPI library or core library, published by the people who maintain each platform.

Certainly one of the strong objections to the interrupt masking proposal (the one that isn't callbacks), which has been discussed at length already, is placing interrupt handling code into the SPI library.

How else would you manage to track what ISR, or whatever is using SPI?

Currently 2 proposals are on the table (again, read the developers list thread), one using event callbacks and the other with interrupt masking code inside SPI. Preliminary work has started on a way to abstract the masking stuff and move it into the core library.

Code for all of these is on github. Significant work has already been put forth to evaluate these options and propose alternate ideas.

Short answer is that an application dev shouldn't have to worry about those details.

On this point, I absoultely agree. That's exactly what beginTransaction() and endTransaction() are meant to solve. The only inputs are the SPI settings, which are specific to that one SPI use. Those functions are meant to handle all this stuff automatically.

The most important part is libraries like USB Host Shield can simply put these 2 functions in, and if running from an interrupt, either usingInterrupt() or register callbacks to mask whatever interrupt they use, and then never need to worry again about conflicting with other libraries using SPI. Resolving conflicts becomes the SPI library's responsibility.
 
I believe it might be more appropriate to define a struct spiConfig or even class spiConfig that holds all the configuration options for SPI transfers. Each SPI "client" (SdFat, Ethernet, radio, ...) could then define its own configuration and pass it to the common SPI code that then handles locks and (re-)configures the underlying hardware.

Matthijs Kooijman proposed using a struct, rather than (or as an alternate in addition to) individual args to beginTransaction(). He posted a sample implementation with a detailed analysis of the compiled code on AVR.

This surely must be coordinated with the Arduino folks. And the current libraries need to be adapted - or even rewritten.

Yes. That's why I've been putting so much work into discussing this on the Arduino Developers mail list, rather than here.

Eventually, the approach could/should be adopted for other buses (I2C, OneWire, CAN, ...) as well.

David Mellis raised this point on the developers mail list.

Which would then, effectively, create an Arduino Operating System.

And when it gets to that point, I'm no longer sure that this is what the Arduino folks really want. Isn't it all about SIMPLICITY? Does non-blocking (or even interrupt-based) I/O fit into the Arduino philosophy?

Those are much larger questions! ;)

If you read that lengthy thread, a consistent theme is a LOT of people want a lot more stuff added. Cristian is clearly one of them. I've spent quite a lot of effort to push back against rolling other features into this work (a.k.a: "feature creep"). The reality is many SPI-based libraries exist today using incompatible settings (some have ugly code to push/pop SPI config on a per-board basis), and several new ones like RadioHead and Adafruit_nRF8001 & CC3000 are appearing with SPI usage in interrupts. They all work well alone, but fail when used together.

A solution is urgently needed, not just for Teensy, but for all Arduino and Arduino compatible boards.
 
Would this be why I am banging my head trying to figure out why I can either use the LCD (ST7735 - Current Paul's Branch) or SDFatLib(Current Release) via SPI but not both at the same time on the Teensy 3.1?

6 - SD CS
10 - LCD CS
11 - LCD SDA + SD MOSI
12 - SD MISO
13 - LCD SCLK + SD SCLK

The second I init the SDFat Lib, I can do SDFat operations, but the LCD stops. If I use them separately, no problems at all. I keep thinking this should work. I tried to fall back to using SOFTWARE_SPI in SdFat, but it appears those settings do nothing on the Teensy 3.
 
FYI - I have also playing around with the Adafrit LCD (2.8" TFT shield) in the thread: http://forum.pjrc.com/threads/25718-Adafruit-2-8-quot-TFT-Touch-Shield-for-Arduino-for-Teensy-3-1

I a have also found that the test programs did not want to talk to the default SD library, Have not tried with other libraries. I found the sd.begin calls were failing, in the sdvolume class tries to call back into the sdcard.readBlock.

Again not sure how these are related. But from my looking through, the LCD and Touch screen code use the spi library which is set up to work as compatible as possible with running it on an actual Arduino, whereas the SD stuff I looked at, looks, uses the low level hardware SD support. I also wonder if the two sets of libraries can work with each other

Kurt
 
Would this be why I am banging my head trying to figure out why I can either use the LCD (ST7735 - Current Paul's Branch) or SDFatLib(Current Release) via SPI but not both at the same time on the Teensy 3.1?

Actually, I believe it's due to a bug in SdFat.

In SdSpiMK20DX128.cpp, try changing this at line 89:

Code:
  SPI0_MCR = SPI_MCR_MSTR;

to this:

Code:
  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);

and this at line 107:

Code:
  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF;

to this:

Code:
  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);

and this at line 170:

Code:
  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF;

to this:

Code:
  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);

Please let me know if these edits make it work for you? If so, hopefully we can convince Bill to add these fixes in a future version.
 
I glazed over the posts on the thread, and the use of a handle (The one proposal uses an SS pin based one, skipping any setup if nothing has changed)
makes some sense to me. Better would be the ability to do something like this collectively... i.e. group the ones that have like-settings. Then you can even skip more init where it isn't needed or wanted. Of course I'm more for not having to change any library at all, or minimally. Teensy3 has 2 SPI, why can't you just use one for all things that agree on spec X and the other for spec Y? Just join the pins together and you get what appears as one buss, and the benefit of two sets of settings to bounce between, or even better, just keep them apart and separate.

Now, the best way is to find components that agree on the format settings to begin with, however I realize that this isn't always a possibility. This is why I use SPI as little as possible, and instead delegate these things to USB instead, which has the ability to overcome these kinds of issues in an easier way. You can even have SPI on USB via the FTDI USB dongle if you wish...
This is also why I use the UHS shield instead of SPI for storage and nearly everything else I can throw at it.

That said, there are an amazing amount of things that can be connected to USB:
Displays, keyboards, audio devices, Ethernet, serial, Bluetooth, game controllers, etc etc ad-nausuim.
What I guess I am eluding to here is my point that, if something isn't doing the job easily enough, perhaps a different and better way needs to be found. For me, this better way is to simply leverage USB and off-the-shelf USB stuff.
 
What we need is a USB/SPI with a hub port per peripheral, as cheap/easy as an FTDI USB/UART.
Host mode issues.
Maybe.
 
What we need is a USB/SPI with a hub port per peripheral, as cheap/easy as an FTDI USB/UART.
Host mode issues.
Maybe.
The USB Host Shield from Circuitsathome.com already supports hubs, and the FTDI, and much more, and even supports all the teensy versions.
 
Paul,

This also works for Teensy/audio card/ILI9341 with SD card (can be from the audio card and/or the ILI9341)?

regards
rob
 
Back
Top