Faster digital I/O for soft SPI?

Status
Not open for further replies.

Bill Greiman

Well-known member
I am adding software SPI support for SD cards in a new FAT12/FAT16/FAT32 library.

In tests, my Teensy 3.0 version is slowest. Due and AVR Arduinos are faster.

I have not tested Teensy 3.1 since I don't have a 3.1 board.

With standard digitalRead/digitalWrite on Teensy 3.0 I get this:
Buffer size 8192 bytes
Write 58.97 KB/sec
Read 54.91 KB/sec

I tried digitalReadFast/digitalWriteFast on Teensy 3.0 and get this:
Buffer size 8192 bytes
Write 76.97 KB/sec
Read 75.72 KB/sec

Is there a faster digital read/write for Teensy 3.0?

With Due I get this:
Buffer size 8192 bytes
Write 275.08 KB/sec
Read 415.28 KB/sec

I use these functions on Due:
Code:
inline void digitalWriteDirect(int pin, boolean val){
  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

Even Uno is faster with my custom fast digital I/O functions:
Buffer size 512 bytes
Write 118.48 KB/sec
Read 155.33 KB/sec

Note, native SPI is fast on Teensy 3.0:
Buffer size 8192 bytes
Write 2200.41 KB/sec
Read 2450.77 KB/sec
 
Last edited:
At the moment I'm trying to use software SPI to make my ADC+Teensy+SD setup to work, I was wondering if there are any developments improving the speed of the software SPI on Teensy 3.0 or its implementation on ARM at all? It seems like all of the available libraries are made for AVR and don't support ARM. I came across this same problem described here: https://code.google.com/p/sdfatlib/issues/detail?id=51.
 
It seems like all of the available libraries are made for AVR and don't support ARM.

Can you provide links to these AVR-only libraries? At the very least, I'll put them on my "needs porting" list....

SdFat has extremely fast native SPI support.
 
Can you provide links to these AVR-only libraries? At the very least, I'll put them on my "needs porting" list....

Here's the DigitalIO library from Bill which has software SPI implementation (SoftSPI.h): https://code.google.com/p/rtoslibs/downloads/detail?name=DigitalIO20130221.zip&can=2&q=. It relies on DDRx, PINx and PORTx, thus compiles only on AVRs. I tried to create a pinMap[] for ARM based on this post: http://forum.pjrc.com/threads/17532...PORT-DDR-D-B-registers-vs-ARM-GPIO_PDIR-_PDOR and using the emulated DDRx, PINx and PORTx, but this hasn't worked since they are not volatile uint8_t*, thus if I were to follow this route a conversion would need to be added to avr_emulation.h, which looks a bit intimidating to me at this stage. Also there are no emulations for Ports A and E. I then tried to substitute all the custom functions in SoftSPI.h and DigitalPin.h with digitalWriteFast, digitalReadFast and pinMode, but that still didn't quite compile (although I'm pretty sure I can make it work) at this stage I decided to write a message on this thread, since as far as I can see Bill has a working version of software SPI for Teensy 3.0.

If there's a simpler way of making SoftSPI work, let me know and I'll try to implement it.

SdFat has extremely fast native SPI support.

Yes I know and that's what I've been using so far, but in the end I will need these three to work: http://forum.pjrc.com/threads/26207-Teensy-ADS129x-ADC-SD-card and based on the discussions I've seen related to multiple devices sharing the same hardware SPI bus it's not that straightforward to do and I believe there's some work being done with the core libraries related to this.
 
Yes I know and that's what I've been using so far, but in the end I will need these three to work: http://forum.pjrc.com/threads/26207-Teensy-ADS129x-ADC-SD-card and based on the discussions I've seen related to multiple devices sharing the same hardware SPI bus it's not that straightforward to do and I believe there's some work being done with the core libraries related to this.

I've been working heavily on the SPI sharing problem over the last couple weeks. Here's a new but untested SPI library which the new functions for proper SPI sharing.

Perhaps we can help each other?

SdFat is on my list of libraries to fix/update for SPI sharing. So far, I've only updated Ethernet, ILI9341 & STMPE610, and SD (not SdFat) is next on my list.

If you'll post test code, I'll do SdFat next and test it with your code. You'll of course benefit, since I'll personally verify that your test code works with these 2 devices together. I've ordered a ADC1294 chip (Digikey $25) which will be here in a few days, so I'll have the hardware needed.

What I need from you is test code, wiring details (eg, which pins to connect between ADC1294 & Teensy), and explanation of any steps necessary to run your test code (if something more complex than simply upload and open the Arduino serial monitor to view results). The test cost MUST be a complete program that definitively shows if the results were correct or not. Several small code fragments that do not make up a complete program (as on your prior messages) will not allow me to copy into Arduino and run it here on a Teensy 3.1 with the ADC1294 chip.

I need you to post a (preferably small) complete program that works with the ADC1294 if SdFat isn't used, but fails when both are used. It must be a complete program I can easily run, without learning lots of details about your specific project. I can and will wiring up the ADC1294, and there too, I need some specific info about what your code expects.

The best approach in your sample program would be a global variable at the top of the program, such as "int DoSdFatStuff = 1;" which causes the SdFat operations to be used or not used, so I can easily change that one number and re-run the program to see correct results from the ADC1294 and whatever goes wrong when both are used.

If you'll post such a test program, I'll patch SdFat and your code with the new SPI functions and test throughly. You'll get both of these working together properly (at least for whatever cases your test program checks). All you have to do is post a small but complete ready-to-run test program and any specific wiring and details I need to know to run it here on a Teensy 3.1 with the ADC1294 chip which should arrive later this week.
 
I should also mention the SPI sharing problems happen in 2 cases:

#1: SPI devices use incompatible formats, like MSBFIRST vs LSBFIRST, SPI_MODE0 vs SPI_MODE2, extremely different clocks, etc. The vast majority of SPI chips use MSBFIRST and SPI_MODE0 and work up to pretty fast clock speeds, so these types of settings conflicts are relatively rare.

#2: Some SPI devices are accessed from interrupts while others are accessed from the main program. This is usually a non-issue when all SPI access is done from the main program context. Libraries like CC3000, RadioHead and nRF8001 which use attachInterrupt() are the ones known to have trouble.
 
Have you ordered the adaptor for it as well or do you have other means of connecting the TQFP-64 to Teensy?

I did not buy a special adaptor for this chip. Is there one specifically for this chip?

I already have generic SMT to through-hole adaptors for nearly all types of non-BGA chips.
 
I should also mention the SPI sharing problems happen in 2 cases:

#1: SPI devices use incompatible formats, like MSBFIRST vs LSBFIRST, SPI_MODE0 vs SPI_MODE2, extremely different clocks, etc. The vast majority of SPI chips use MSBFIRST and SPI_MODE0 and work up to pretty fast clock speeds, so these types of settings conflicts are relatively rare.

#2: Some SPI devices are accessed from interrupts while others are accessed from the main program. This is usually a non-issue when all SPI access is done from the main program context. Libraries like CC3000, RadioHead and nRF8001 which use attachInterrupt() are the ones known to have trouble.

With ADS129x whenever the new data is ready DRDY pin is asserted low, thus my plan was to attach interrupt to that pin and in this way fetch the data from the ADC storing it in the buffer. After 512 bytes are read they are to be sent to the SD card in the main program. So I think scenario #2 is relevant for my case. Though the problems I've seen so far are most likely due to this weird behaviour I observe when accessing SPI bus prior to writing to the SD card as per: http://forum.pjrc.com/threads/26242-Teensy-3-1-SD-card-test-request. We'll see if the new SD card solves the problem.

I did not buy a special adaptor for this chip. Is there one specifically for this chip?

I already have generic SMT to through-hole adaptors for nearly all types of non-BGA chips.

No there's no specific adapter required, you just need one with which you'll have access to all the pins. I'm using this one: http://www.proto-advantage.com/store/product_info.php?products_id=2200113. I'm for example not sure how something like this would work with a breadboard: http://www.ebay.co.uk/itm/like/3908...f11=ICEP3.0.0&ff12=67&ff13=80&ff14=108&ff19=0
 
Last edited:
I've got 2 more of the ADS1294 chips on order. They ought to be here later this week.

I'm considering making a breakout board, which will take a couple weeks from OSH Park, but it'll (hopefully) improve my odds of getting everything hooked up properly.

Your schematic based on SoftSPI had 9 signals. Are all of those truly necessary? For example, there seems to be little point in connecting CLKSEL, since it always need to be high for internal clock.

Are START, RESET and PWDN really needed?
 
Well it all depends what you'd like to do with the ADC...

I use START to start/stop the conversion, it can be tied HIGH to keep the converter running continuously, but to conserve power I don't do it.
I power down the ADC by pulling PWDN low when the system is waiting for the button press while being in sleep mode, once again to conserve power.
RESET is used to reset the chip as per the power-up timing diagram in the data sheet, but probably it can be just tied HIGH with no harm.

So do I understand correctly that there's not way of speeding up the digital read/write and the digitalWriteFast/ReadFast are the fastest way of doing it?
 
Status
Not open for further replies.
Back
Top