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

Thread: SPI on Teensy 4

  1. #1
    Junior Member
    Join Date
    Sep 2019
    Posts
    1

    SPI on Teensy 4

    I am working on a project that requires SPI for some external chips and I am running into several issues with SPI on the Teensy 4.

    Attempting to diagnose my issues with the example programs and an oscilliscope I am noticing weird behavior. The scope plots below show the CS pin (channel 1, yellow) and SPI clock (channel 2, purple). CS pin falls low but does not remain low for the duration of the transfer. Additionally, as the code belo shows I am only sending 2 bytes of data, but the clock signal shows 24 puleses, indicating 3 bytes of data sent.

    Has anyone experienced this before? Is the SPI library not functioning correctly on Teensy 4?


    Click image for larger version. 

Name:	PNG.png 
Views:	22 
Size:	23.6 KB 
ID:	17511

    Code:
    /*
      Digital Pot Control
      
      This example controls an Analog Devices AD5206 digital potentiometer.
      The AD5206 has 6 potentiometer channels. Each channel's pins are labeled
      A - connect this to voltage
      W - this is the pot's wiper, which changes when you set it
      B - connect this to ground.
     
     The AD5206 is SPI-compatible,and to command it, you send two bytes, 
     one with the channel number (0 - 5) and one with the resistance value for the
     channel (0 - 255).  
     
     The circuit:
      * All A pins  of AD5206 connected to +5V
      * All B pins of AD5206 connected to ground
      * An LED and a 220-ohm resisor in series connected from each W pin to ground
      * CS - to digital pin 10  (SS pin)
      * SDI - to digital pin 11 (MOSI pin)
      * CLK - to digital pin 13 (SCK pin)
     
     created 10 Aug 2010 
     by Tom Igoe
     
     Thanks to Heather Dewey-Hagborg for the original tutorial, 2005
     
    */
    
    
    // include the SPI library:
    #include <SPI.h>
    
    
    // set pin 10 as the slave select for the digital pot:
    const int slaveSelectPin = 10;
    
    void setup() {
      // set the slaveSelectPin as an output:
      pinMode (slaveSelectPin, OUTPUT);
      digitalWrite (slaveSelectPin, HIGH);
      // initialize SPI:
      SPI.begin(); 
    }
    
    void loop() {
      // go through the six channels of the digital pot:
      for (int channel = 0; channel < 6; channel++) { 
        // change the resistance on this channel from min to max:
        for (int level = 0; level < 255; level++) {
          digitalPotWrite(channel, level);
          delay(10);
        }
        // wait a second at the top:
        delay(100);
        // change the resistance on this channel from max to min:
        for (int level = 0; level < 255; level++) {
          digitalPotWrite(channel, 255 - level);
          delay(10);
        }
      }
    
    }
    
    void digitalPotWrite(int address, int value) {
      // gain control of the SPI port
      // and configure settings
      SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
      // take the SS pin low to select the chip:
      digitalWrite(slaveSelectPin,LOW);
      //  send in the address and value via SPI:
      SPI.transfer(address);
      SPI.transfer(value);
      // take the SS pin high to de-select the chip:
      digitalWrite(slaveSelectPin,HIGH);
      // release control of the SPI port
      SPI.endTransaction();
    }

  2. #2
    I am also noticing issues with SPI on Teensy 4. Code written for 3.2 does not run on Teensy 4. Debugging, it seems to just hang on 'SPI.transfer(c);' with no further code execution. Any know issues??

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,740
    @KurtE has gotten it to work across many displays - it has some unique properties.

    Just looking at github.com/PaulStoffregen/SPI it was updated yesterday to adjust for pin settings. That will be released in a TD 1.48b1 soon - may install and work locally in {sketchbook}\libraries with TD 1.47.

  4. #4
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,108
    Just out of curiosity have you tried mode0 instead of mode1. Also recently when I had to add a delayNanosecond (200) after going low and before going high. Could try that as well.

    Been testing a whole range of spi displays and not had a problem. Unfortunately don't have the hardware to duplicate your problem.

  5. #5
    Curiously enough, I have resolved my issue by adding the 'SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));' and 'SPI.endTransaction();' methods in their respective locations. I have used the same code for a few years and never used these methods. Are they really needed? If so, does anyone know why? Don't worry I am going to start digging through the code to see for myself as well. I dont have an Oscope, but if I have some time I will put this on my saleae16 and see if the transactions are in fact valid, kinda scary reading over backereth's post.

  6. #6
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,424
    Also something you might try.

    I have found that switching SPI_MODES can screw up the first write or two...

    So what I have done in a few places, to make things work: For the moment assume only only device.

    So in init code I might do something like:

    Code:
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
    <Make sure your CS pin is not selected something like: digitalWriteFast(CS_PIN, HIGH);
    SPI.transfer(0);  // some bogus transfer
    SPI.endTransaction();

  7. #7
    Quote Originally Posted by KurtE View Post
    Also something you might try.

    I have found that switching SPI_MODES can screw up the first write or two...

    So what I have done in a few places, to make things work: For the moment assume only only device.

    So in init code I might do something like:

    Code:
    SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1));
    <Make sure your CS pin is not selected something like: digitalWriteFast(CS_PIN, HIGH);
    SPI.transfer(0);  // some bogus transfer
    SPI.endTransaction();
    What do you suppose this does? Or do you do this just for sanity.. I guess I have always relied on default SPISettings and the CS pin to drive the transaction, which is why my code hung. So far everything looks pretty good.

    @beckereth, could you do the same test using each SPI mode? I would like to see if they operate as expected.

    As to my previous question, I would still like to know why my code didnt work without beginTransaction and does with it. (because it used to on Teensy 3.2) As far as I can tell it diables some interrupts and end Transaction re-enables them.

  8. #8
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,108
    Working on my cell here but a good reference I found helpful: https://www.pjrc.com/teensy/td_libs_SPI.html

  9. #9
    Quote Originally Posted by mjs513 View Post
    Working on my cell here but a good reference I found helpful: https://www.pjrc.com/teensy/td_libs_SPI.html
    This was actually really helpful in answering my questions. Just goes to show what a little reading can achieve. I honestly had never read it, and I've been dealing with spi for years..

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,424
    The code I mentioned above, helps by actually sending out a byte in the new configuration. Which for example if the mode change switches the clock signal to being low inactive versus high inactive, it get the clock signal into the state that the device wants. Likewise for leading or trailing edge (although it might work without doing this in that case).

  11. #11
    I am having the same problem with Teensy 4.0 - it hangs on the first spi.transfer command that is executed.

    I am interfacing teensy 4.0 with a quadrature encoder chip (LS7366R) via SPI.
    The code is attached below. It was working with a teensy 3.6 but once I changed it to a teensy 4.0, it hangs and I debugged it to the point where it does the first spi.transfer command.
    By monitoring the CS line on a scope, I can see that it only activates once (i.e. goes high and pulled low once and stays low).
    I am using Pins 11 for MOSI, 12 for MISO and 13 for SCK as per default on 4.0. CS is Pin 10.

    The solutions by @KurtE and @thagh05t above did not work.

    Software version: arduino 1.88 and teensyduino 1.47
    "blink" and "asciiTABLE" tested to work on this particular teensy 4.0.

    Code:
    #include <SPI.h>
    
    int CS1 = 10;
    long EncoderCount1;
    char buff[4];
    
    void setup() {
      Serial.begin(115200);
      
      pinMode(CS1, OUTPUT);
      digitalWrite(CS1, HIGH);
    
      QEC_Configure(); // QEC = Quadrature Encoder Counter
    }
    
    void loop() {
      ReadEncoder();
      
      Serial.print("Encoder1 = ");
      Serial.print(EncoderCount1);
      
      Serial.println();
      
      delay(10);
    }
    
    void ReadEncoder(void){
      long buff[4];
      digitalWrite(CS1,LOW);
      SPI.transfer(0x60); // Request count
      buff[0] = SPI.transfer(0x00); // most significant byte
      buff[1] = SPI.transfer(0x00);
      buff[2] = SPI.transfer(0x00);
      buff[3] = SPI.transfer(0x00); // least significant byte
      digitalWrite(CS1,HIGH); 
      EncoderCount1 = (long)(buff[0]<<24) + (long)(buff[1]<<16) + (long)(buff[2]<<8) + (long)buff[3];
      }
    
    void QEC_Configure(void)
    {
      SPI.begin();
      delay(5);
       
      digitalWrite(CS1,LOW);
      SPI.transfer(0x88); 
      SPI.transfer(0x03);
      digitalWrite(CS1,HIGH);
    }

  12. #12
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,424
    @connectivity - Confirmed it dies, will debug.

    In the mean time you can get it up and running, if you add a couple lines of code...

    Code:
    void QEC_Configure(void)
    {
      SPI.begin();
      
      delay(5);
      SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
      SPI.endTransaction();
      digitalWrite(CS1, LOW);
      SPI.transfer(0x88);
      SPI.transfer(0x03);
      digitalWrite(CS1, HIGH);
    }

  13. #13
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    5,424
    I updated the T4 support for SPI, so now
    SPI.begin internally at the end will call beginTransaction(SPISettings()); endTranaction();
    So things like the transfer data size and clock settings and... are properly initialized.

    I also put in an implementation for
    SPI.setDataMode and SPI.setClockDivider so those I believe are functional now... Still code should migrate to using beginTransaction...

    Put in PR: https://github.com/PaulStoffregen/SPI/pull/54

    Hopefully @PaulStoffregen will get a chance to pull it in before the next beta release.

  14. #14
    Quote Originally Posted by KurtE View Post
    @connectivity - Confirmed it dies, will debug.

    In the mean time you can get it up and running, if you add a couple lines of code...

    Code:
    void QEC_Configure(void)
    {
      SPI.begin();
      
      delay(5);
      SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
      SPI.endTransaction();
      digitalWrite(CS1, LOW);
      SPI.transfer(0x88);
      SPI.transfer(0x03);
      digitalWrite(CS1, HIGH);
    }

    Thanks KurtE, this works. Previously I replaced the SPI.begin() with SPI.beginTransaction(...) so it didn't work..

    cheers

Posting Permissions

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