Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: teensy 3.1 SD/SPI clock rates 'n such

  1. #1
    Junior Member
    Join Date
    Aug 2015
    Location
    AZ
    Posts
    8

    teensy 3.1 SD/SPI clock rates 'n such

    Hi folks:

    First-time post. New teensy user. Just picked up a 3.1 to play with. Pretty cool, and a lot of power for twenty bucks. I love that the teensy lets me easily fire off interrupts and has oodles of other great features cleanly integrated into the Arduino IDE.

    I am generally off in the custom ARM/gcc world but want to make something open-source that lets folks tweak it easily (without needing to build a toolchain and get a jtag pod), so I am interested in the Arduino IDE interface to the teensy. Later, it would be cool to try some bare-metal teensy programming as well. As approachable as the standard arduino is for most folks, you need a mega/due... for any decent code space -- that was before I discovered the smaller/cheaper/more-powerful teensy. But enough preamble.

    My first tests included the simple CardInfo SD example prog -- don't really need to post the code -- it's the generic arduino example from Limor, just pointing to a teensy 3.1 at a clock freq of X. The arduino IDE is 1.6.5, teensyduino is 1.24. The only change to the example is to fix the well-known bug where it screws up the size of cards over 2GB (github.com/arduino/Arduino/issues/1194). I hooked up a teensy 3.1 and an adafruit SD breakout on a breadboard and ran across the following:

    Sheesh, that SPI bus is fast -- CardInfo would always init the card, since the spi bus is slowed way down for init, however, the volume init did not work. Hmm. I had the teesny set to 96MHz. I hooked up a scope and found spi clocks about 25 MHz. Sure enough, with a bit of poking through the arduino area, I found, just a few lines down, in \Program Files (x86)\Arduino\hardware\teensy\avr\libraries\SD\SD_ t3.h
    #define SD_SPI_SPEED SPISettings(25000000, MSBFIRST, SPI_MODE0)
    which sets spi bus speed to a blazing 25MHz. Pretty fast for wires-in-air breadboarding and even for expansion pcbs/shields without a decent groundplane (which is many of them). Now my final pcb will be emi clean, but I had just patched this together on a breadboard. Perhaps I should have twisted each signal wire with a ground, but it was just a quick test. Much like most folks would do with a quick breadboard and expect to get examples running. However, I don't think it was an issue of crosstalk, or inductive undershoot, or whatever, but simply the spi bus speed. I was initially going to edit the SD_t3.h file to lower the spi clock, but I kinda hate changing libraries. I would rather define system stuff in my code.

    So I started throttling back the cpu clock and found cases where CardInfo would work, and those when it would not:
    - CardInfo volume fail: at 96MHz-OC: saw spi clock of about 25 MHz, delay between bytes of about 0.6 us.
    - CardInfo volume pass: at 72MHz: saw spi clock of about 19 MHz, delay between bytes of about 1 us.
    - CardInfo volume fail: at 48MHz: saw spi clock of about 25 MHz, delay between bytes of about 1 us.
    - CardInfo volume pass: at 24MHz: saw spi clock of about 12 MHz, delay between bytes of about 2 us.
    - These clocks were all "optimized"

    This leads me to think that the spi rate of 25MHz is too fast for an SD card, but at about 19 MHz or so it begins to work. The delay between bytes may not be an issue, but I noted it since it differed. I realize that Paul has sped spi up on the teensy, much to the delight of folks driving big displays 'n such, but I would like to set the spi bus to something modest in the 4 to 10 MHz range, which has worked well for me for years for SD as well as other spi peripherals. As a simple fix, I just chose 24 MHz for my cpu clock.

    I tried this with several different SD cards with differing capacities and different vendors -- same result.

    Which leads me to a few questions:
    - can I define teensy cpu clock in my program, or can it only be changed via the ide tools menu?
    - can I define my spi clock (or divider) in my program, or is it just a function of the hard-coded SD_t3.h and cpu clock?
    - what is an "optimized" cpu clock vs. a regular-joe clock of the same speed?
    - when does arduino ide know to look for a lib (SD, SPI...) in \Program Files (x86)\Arduino\hardware\teensy\avr\libraries\... as opposed to the regular lib directory?

    thx, Gil

  2. #2
    Senior Member
    Join Date
    Dec 2013
    Location
    East Stroudsburg PA.
    Posts
    320
    Hi Gil

    I don't believe throttling back the cpu clock is the answer here.
    I'm running multiple spi devices (3) on Teensy 3.0 with no problems, With the new SPI library with transaction.
    More info here:http://pjrc.com/teensy/td_libs_SPI.html

    To write code for a new SPI device you need to note a few things:
    What is the maximum SPI speed your device can use? This is controlled by the first parameter in SPISettings.
    If you are using a chip rated at 15 MHz, use 15000000.
    Teensy/Arduino will automatically use the best speed that is equal to or less than the number you use with SPISettings.

    Multiple SPI devices use the same SPI SCK, MISO and MOSI signals but each device will need it's own SS pin.
    Signal-----Function---------Teensy 2.0-------Teensy++ 2.0-------Teensy3.0/3.1-------Teensy 3.0/3.1Alternate
    SS -------Select Device------0----------------20-------------------10/Any---------------Any---------------
    SCK------Clock---------------1----------------21-------------------13-------------------14----------------
    MOSI-----Data Output--------2----------------22-------------------11--------------------7----------------
    MISO-----Data Input---------3-----------------23------------------12--------------------8-----------------

    Transactional SPI configuration.

    A common problem used to be that different SPI devices needed different, incompatible settings.
    Your sketch had to take care of saving and restoring the SPI settings before communicating with each SPI device.
    If any SPI device was accessed from an interrupt, this could result in data corruption if another SPI device was communicating at the time.

    With the new SPI library, configure each SPI device once as an SPISettings object.
    Also, if that device will be called from an interrupt, say so with SPI.usingInterrupt(interruptNumber).
    To communicate with a specific SPI device, use SPI.beginTransaction which automatically uses the settings you declared for that device.
    In addition, it will disable any interrupts that use SPI for the duration of the transaction.
    Once you are finished, use SPI.endTransaction() which re-enables any SPI-using interrupts.

    Example using transactions
    Code:
    #include <SPI.h>  // include the new SPI library:
    
    // using two incompatible SPI devices, A and B
    const int slaveAPin = 20;
    const int slaveBPin = 21;
    
    // set up the speed, mode and endianness of each device
    // Teensy 3.x can only generate 30 MHz SPI when running at 120 MHz (overclock)
    // At all other speeds, SPI.beginTransaction() will use the fastest available clock. (24Mhz)
    // /* SPISettings settingsA(30000000, MSBFIRST, SPI_MODE1); */ //SPI_MODE0
    SPISettings settingsA(2000000, MSBFIRST, SPI_MODE1); 
    SPISettings settingsB(16000000, LSBFIRST, SPI_MODE3); 
    
    void setup() {
      // set the Slave Select Pins as outputs:
      pinMode (slaveAPin, OUTPUT);
      pinMode (slaveBPin, OUTPUT);
      // initialize SPI:
      SPI.begin(); 
    }
    
    uint8_t stat, val1, val2, result;
    
    void loop() {
      /******* read three bytes from device A ********/
      SPI.beginTransaction(settingsA);
      digitalWrite (slaveAPin, LOW);
      // reading only, so data sent does not matter
      stat = SPI.transfer(0);
      val1 = SPI.transfer(0);
      val2 = SPI.transfer(0);
      digitalWrite (slaveAPin, HIGH);
      SPI.endTransaction();
      // if stat is 1 or 2, send val1 or val2 else zero
      if (stat == 1) { 
       result = val1;
      } else if (stat == 2) { 
       result = val2;
      } else {
       result = 0;
      }
    
      /******* send result to device B ********/
      SPI.beginTransaction(settingsB);
      digitalWrite (slaveBPin, LOW);
      SPI.transfer(result);
      digitalWrite (slaveBPin, HIGH);
      SPI.endTransaction();
    }

  3. #3
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,753
    Quote Originally Posted by teletypeguy View Post
    This leads me to think that the spi rate of 25MHz is too fast for an SD card, but at about 19 MHz or so it begins to work.

    No, SD is specified for 25 MHZ, all cards can work with 25MHz.
    There is a problem with your hardware. Maybe too long connections - the should be as short as possible ? Which adapter do you use ? Some are for 5 Volt, these do not work. Are there any levelshifters ?

  4. #4
    Junior Member
    Join Date
    Aug 2015
    Location
    AZ
    Posts
    8
    Hi Chris:

    This transactional spi is very interesting. Thanks Paul. Nice feature.

    I can definitely envision a system with an accelerometer, spi flash, adc, all on the spi bus with different max clock rates and different spi modes. Very nice to be able to define and access them cleanly. Just being able to define the params for each (once) is nice, but making them interrupt-safe is awesome.

    I need to read up more on this new spi lib.

    But how do I apply it to the SD library? The card is definitely one of the bus members, and it would be nice to define (lower) speed, even if just needed for a crappy breadboard test. How does transactional spi apply to the SD card?

    thx, gil

  5. #5
    Junior Member
    Join Date
    Aug 2015
    Location
    AZ
    Posts
    8
    Hi Frank:

    Well, I too thought (from a few SD spec sheets) that 25 meg was not too fast, and I looked at the pins on the spi breakout with a 300MHz scope (with a short properly-placed ground) to see how the signals looked -- decent shape, not too much undershoot. Did not think it was really HW-related.

    However, when you mentioned the breakout, I took a closer look. It is an Adafruit SD breakout, and I was powering it with the nominal 5V for its level translator, and feeding it with 3.3V signals from the teensy. That is all fine and dandy usually.

    Sadly, the translator chip is an HC4050. As much as I have loved the HC family since I started using them in the early 80s when they came out (I date myself now), they are not particularly fast. I would have at least used an LVxxA part for that. Anyway, even though the switching voltage thresholds are fine, I can see the signals at the SD card being squashed as the transition delays start to hit each other.

    I don't have a 3.3V-only breakout (like Paul's) but I have a old bare board of mine with an SD socket that I can wire up to test it (and I will add twisted grounds on all the signals as well).

    Let me try that out and I will report back.

    thx, gil

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,108
    Yup, that 4050 chip is probably adding too much signal delay. All SD cards are rated for up to 25 MHz, and all modern cards follow the newer specs that require 50 MHz timing, so it's almost certainly not a limitation of the actual SD card.

    I know the SD library works great at 24 Mbit/sec through this SD adaptor we sell for Teensy 2.0, based on a 74LCX125 chip. I have personally connected this to a Teensy 3.1 on breadboards many times, using wires a few inches long. Really long wires should be avoided, but they don't need to be kept extremely short to meet the timing requirements.

  7. #7
    Junior Member
    Join Date
    Aug 2015
    Location
    AZ
    Posts
    8
    Hi Paul:

    Thanks for closing the other thread -- I should have waited a bit longer.

    So, I wired up an SD card socket with no HC4050, and yes indeed, it works fine at a 96MHz cpu clock, which yields a 25MHz SD clock. My bad.

    The transactional spi looks great, and I have some applications where that will be very useful. I am guessing though, that if I wanted to use 96M for the cpu, yet lower SD clock (eg: to keep emi down), that I would need to edit the SD_ t3.h file (which is easy enough):
    SD_SPI_SPEED SPISettings(25000000, MSBFIRST, SPI_MODE0)

    thanks,
    gil

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,108
    Yup, you'd have to edit the code.

    There's actually 2 places to edit. That one you found is used if you've uncommented USE_TEENSY3_OPTIMIZED_CODE.

    The other one is in utility/Sd2Card.cpp. You can see Bill's SdFat code is designed to allow changing the speed, but that feature isn't exposed by the SD library wrapper.

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,108
    Could you post a link to the specific Adafruit product page? Or the Adafruit product number?

    Might come in handy, when/if anyone else tries to use it (and perhaps finds this thread by searching).

  10. #10
    Junior Member
    Join Date
    Aug 2015
    Location
    AZ
    Posts
    8
    Hey Paul:

    This is the adafruit breakout (#254), which is a nicely-laid-out pcb (emi-wise, which Limor is generally quite careful about), but the hc4050 is the choke point. To be fair, she likely never expected spi rates as fast as teensy when it was designed.
    https://www.adafruit.com/product/254

    However, it also applies to her CC3000 shield (and maybe others):
    https://www.adafruit.com/products/1534

    I also have a sparkfun sd/proto shield here (unsure of the model) which also has an HC 4050.

    So I guess the quick fwi note would be to look for that chip on an adapter, and maybe just use a cpu clock of 24 MHz (which is still darned fast).

    gil

  11. #11
    Junior Member
    Join Date
    May 2018
    Posts
    6
    I am also trying to make several of the micro SD adapters work that have the 5V translation chips (LM1117-33 and SN74LVC125A). Is the SPI speed limitation from the chips or the physical connections on the PCB? I am going to remove the chips and replace the connections with 0ohm chip resistors to see if it will work, but it would be nice to hear an opinion before i try.

    -T

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •