Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 42

Thread: Teensy 3.5 SPI Interrupt Routine on SPI Bus 1 or 2

  1. #1

    Teensy 3.5 SPI Interrupt Routine on SPI Bus 1 or 2

    For a project I would like to use the SPI bus 1 or 2 as SPI slave and accept commands from the master using the interrupt routine and answer accordingly.
    Since the SPI bus 0 of the Teensy is already occupied by an RFID reader (RC255) I have to switch to another SPI bus.

    Here is my code, which works on an Arduino UNO without any problems:
    Code:
    #include <SPI.h>
    
    volatile byte answerOne[] = {22,22,16,2,6,2,247,16,3}; //"L" answer
    volatile byte answerTwo[] = {22,22,16,2,'i',7,0,0,0,0,1,142,16,3}; // "O" answer
    //byte address[8] = {0x28, 0xFF, 0x15, 0xC6, 0x62, 0x15, 0x1, 0x71};
    volatile int state_s1 = 0;
    volatile int state_prev_s1 = 0;
    volatile int answerType = 0;
    volatile int counter = 0;
    
    void setup (void)
    {
      Serial.begin (1000000);   // debugging
      
      // turn on SPI in slave mode
      SPCR |= bit (SPE);
    
      // have to send on master in, *slave out*
      pinMode(MISO, OUTPUT);
      
      // now turn on interrupts
      SPI.attachInterrupt();
    
    }  // end of setup
    
    
    // SPI interrupt routine
    ISR (SPI_STC_vect)
    {
    byte c = SPDR;  // grab byte from SPI Data Register
    state_prev_s1 = state_s1;
    switch (state_s1){
      case 0: //START
        if(c == 22){
          state_s1 = 1;
        }
        SPDR = 0;
      break;
    
      case 1: // 2nd byte
        if(c == 22){
          state_s1 = 2;
        }else{
          state_s1 = 0;
        }
        SPDR = 0;   
      break;
    
      case 2: // 3rd byte
        if(c == 16){
          state_s1 = 3;
        }else{
          state_s1 = 0;
        }
        SPDR = 0;
      break;
    
      case 3: // 4th byte
        if(c == 2){
          state_s1 = 4;
        }else{
          state_s1 = 0;
        }
        SPDR = 0;
      break;
    
      case 4: // 5th byte
        if(c == 'L'){
          answerType = 1;
          state_s1 = 5;
        }else if(c == 'O'){
          answerType = 2;
          state_s1 = 5;
        }else{
          state_s1 = 0;
        }
        SPDR = 0;
      break;
    
      case 5: //1th end byte
        if(c == 16){
          state_s1 = 6;
        }
        SPDR = 0;
      break;
    
      case 6: // 2nd end byte
        if(c == 3){
          state_s1 = 7;
        }else{
          state_s1 = 5;
        }
        SPDR = 0;
      break;
    
      case 7: // Send Answer
        if(answerType == 1){
          if(answerOne[counter] == 3){
            SPDR = answerOne[counter];
            state_s1 = 0;
            counter = 0;
            break;
          }
          SPDR = answerOne[counter++];
        }else if(answerType == 2){
          if(answerTwo[counter] == 3){
            SPDR = answerTwo[counter];
            state_s1 = 0;
            counter = 0;
            break;
          }
           SPDR = answerTwo[counter++];
        }
        testPrint(counter);
      break;
    
    }     
    }  // end of interrupt routine SPI_STC_vect
    
    
    
    
    void testPrint(int c){
      Serial.print("Question complete! - Answer type=");
      Serial.print(answerType);
      Serial.print(" - Counter = ");
      Serial.println(c);
    }
    
    // main loop - wait for flag set in interrupt routine
    void loop (void)
    {
      if(state_prev_s1 != state_s1){
        Serial.println(state_s1);
      }
      
    
    }  // end of loop
    How can I get the interrupt routine to use the SPI bus 1 or 2 from the teensy?

  2. #2
    Does anybody have an idea, or does anybody know?

    Edit: I've been searching the internet a bit and I think I need the right interrupt number. Which is the correct interrupt number for SPI bus 1 and 2? Where is such a thing documented?
    Last edited by JSON; 06-14-2019 at 07:31 PM.

  3. #3
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,442
    ISR(Vector) works only on AVR but not on ARM processors like the Teensy. The SPI library for the Teensy does AFAIK not support attachinterrupt().

  4. #4
    Quote Originally Posted by Theremingenieur View Post
    ISR(Vector) works only on AVR but not on ARM processors like the Teensy. The SPI library for the Teensy does AFAIK not support attachinterrupt().
    That's weird. Teensy's FAQ page describes that you should use the ISR() vector: https://www.pjrc.com/teensy/interrupts.html

    Are you sure this isn't gonna work on the teensy?

    If so, how does it work?

  5. #5
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,021
    check the source files for this library for help:

    https://github.com/tonton81/TSPISlave

  6. #6
    Quote Originally Posted by tonton81 View Post
    check the source files for this library for help:

    https://github.com/tonton81/TSPISlave
    Thank you for the hint. I don't know exactly how the source code of the library will help me, however I will try your example in this thread: https://forum.pjrc.com/threads/54548-TSPISlave-Library

    Do you agree that you can't use the ISR(Vector) with a teensy?

  7. #7
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,891
    The ISR page you mentioned is for the older Teensy 2 which is also AVR based.

    Yes Teensy 3.x (and soon to be Teensy 4) also support Interrupts and have a set of interrupts...

    The SPCR, SPSR, SPDR objects that are referenced in your code are AVR specific registers. Which are for the one and only SPI hardware on things like the Arduino UNO...

    There is code in place on the Teensy to emulate some of the old AVR SPI code, although I am not sure if ever any of the interrupt processing was emulated specifically for this particular case.

    You should instead use the SPI library to access the different hardware busses, like SPI, SPI1, SPI2.

    Note I have done very little to use SPI in client mode (almost always in master mode). So not sure how much help I would be able to give. Again even if I could help some here, would never spend my time trying to horseshoe the functionality by trying to emulate an AVR board, but instead would either use existing libraries and/or look at the SPI section of the Teensy 3.x manual I was using.

    Good luck
    Kurt

  8. #8
    Quote Originally Posted by KurtE View Post
    The ISR page you mentioned is for the older Teensy 2 which is also AVR based.

    Yes Teensy 3.x (and soon to be Teensy 4) also support Interrupts and have a set of interrupts...

    The SPCR, SPSR, SPDR objects that are referenced in your code are AVR specific registers. Which are for the one and only SPI hardware on things like the Arduino UNO...

    There is code in place on the Teensy to emulate some of the old AVR SPI code, although I am not sure if ever any of the interrupt processing was emulated specifically for this particular case.

    You should instead use the SPI library to access the different hardware busses, like SPI, SPI1, SPI2.

    Note I have done very little to use SPI in client mode (almost always in master mode). So not sure how much help I would be able to give. Again even if I could help some here, would never spend my time trying to horseshoe the functionality by trying to emulate an AVR board, but instead would either use existing libraries and/or look at the SPI section of the Teensy 3.x manual I was using.

    Good luck
    Kurt
    Thank you for the detailed answer. I'd like to try the library of tonton81, but here I don't have the possibility to answer the master as I understand it...do I?!

    As described in my first post I have to send a 0 (zero) back to the master after every byte sent by the master and after the message from the master has arrived completely I have to send the answer. Either answerOne[] or answerTwo[].

    @tonton81 Does this work with your library? If so, do you have a short example or approach for me? If not, can someone recommend a suitable library?
    Last edited by JSON; 06-14-2019 at 09:30 PM.

  9. #9
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,442
    The Teensy SPI library website https://www.pjrc.com/teensy/td_libs_SPI.html states clearly that slave mode is not supported...

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,891
    As mentioned the SPI library only supports master mode. But the chips do support slave mode.

    If you do a search on google like: teensy spi slave
    You will see several thread that hit, plus a few libraries:
    Like: https://forum.pjrc.com/threads/49315...in-Teensyduino

    Here @tonton81 does give a link to another thread with zip file...

    As for slave responding, I know it can. There are always interesting things to look at like how many bytes that are received by the slave, before it can respond and the master get the response.

    A lot of this depends on things like how the Fifo queues are configured and the like. I did play around once with it, but did not take it very far... Some day maybe.

  11. #11
    Quote Originally Posted by KurtE View Post
    As mentioned the SPI library only supports master mode. But the chips do support slave mode.

    If you do a search on google like: teensy spi slave
    You will see several thread that hit, plus a few libraries:
    Like: https://forum.pjrc.com/threads/49315...in-Teensyduino

    Here @tonton81 does give a link to another thread with zip file...
    Thanks again KurtE, that has helped a lot.

    During my search I found the following library of tonton81 and defragster. It looks very promising and I will give it a try.

    https://github.com/Defragster/SPI_MSTransfer

  12. #12
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,811
    Quote Originally Posted by JSON View Post
    Thanks again KurtE, that has helped a lot.

    During my search I found the following library of tonton81 and defragster. It looks very promising and I will give it a try.

    https://github.com/Defragster/SPI_MSTransfer
    Find the github tonton81 version - what I have is certainly out of date.

  13. #13
    Quote Originally Posted by defragster View Post
    Find the github tonton81 version - what I have is certainly out of date.
    You mean that one: https://github.com/tonton81/SPI_MSTransfer ?

  14. #14
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,811
    Quote Originally Posted by JSON View Post
    Yes, that would be the place to start. tonton81 p#5 linked another above - not sure if that is the newer better version for your purpose. But SPI_MSTransfer for sure worked between two Teensy units with one being M and one S.

  15. #15
    Quote Originally Posted by defragster View Post
    tonton81 p#5 linked another above - not sure if that is the newer better version for your purpose.
    I think this is the library I need!!! I took a closer look at the example and try it out on Monday.
    “popr and pushr are used to read and write respectively the data once the available() is triggered” -> that’s exactly what I need.
    As soon as I have a result I will get back to you.

  16. #16
    I tried to set up a SPI slave with a Teensy 3.5 using the library of tonton81 (tspi_slave). But it is not working!!!
    I use the SPI Bus 1 of the Teensy 3.5 and 8 bit word length for the slave contrary to the example from the library.

    I made a Teensy 3.6 the SPI master with the following code:

    Code:
    // Written by Nick Gammon
    // February 2011
    
    
    #include <SPI.h>
    
    void setup (void)
    {
    
      digitalWrite(SS, HIGH);  // ensure SS stays high for now
    
      // Put SCK, MOSI, SS pins into output mode
      // also put SCK, MOSI into LOW state, and SS into HIGH state.
      // Then put SPI hardware into Master mode and turn SPI on
      SPI.begin ();
    
      // Slow down the master a bit
      SPI.setClockDivider(SPI_CLOCK_DIV8);
      
    }  // end of setup
    
    
    void loop (void)
    {
    
      char c;
    
      // enable Slave Select
      digitalWrite(SS, LOW);    // SS is pin 10
    
      // send test string
      for (const char * p = "Hello, world!\n" ; c = *p; p++)
        SPI.transfer (c);
    
      // disable Slave Select
      digitalWrite(SS, HIGH);
    
      delay (5000);  // 1 seconds delay 
    }  // end of loop
    That this works without problems I could proof with a Saleae Logic Analyser.


    The slave has the following code and does not react to the commands of the master:
    Code:
    #include "TSPISlave.h"
    //0,1,31,32 SPI1
    uint8_t miso = 1;
    uint8_t mosi = 0;
    uint8_t sck = 32;
    uint8_t cs = 31;
    uint8_t spimode = 8;
    
    TSPISlave mySPI = TSPISlave(SPI1, miso, mosi, sck, cs, spimode);
    
    void setup() {
      Serial.begin(115200);
      mySPI.onReceive(myFunc);
    }
    
    void loop() {
      delay(1000);
      Serial.println(millis());
    }
    
    void myFunc() {
      Serial.println("START: ");
      uint8_t arr[2] = { 0x11, 0x22 };
      uint8_t i = 0;
      while (mySPI.active()) {
        if (mySPI.available()) {
          mySPI.pushr(arr[i++]);
          Serial.print("VALUE: 0x");
          Serial.println(mySPI.popr(), HEX);
        }
      }
      Serial.println("END");
    }
    Can someone tell me what is wrong here? Best tonton81

  17. #17
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,442
    Quote Originally Posted by JSON View Post
    But it is not working!!!
    How do you expect getting help if you do not give more precise information about WHAT is not working... is it that myFunc() is not called, or is it called but no reply sent? What about the wiring? Crossed MISO and MOSI? Common GND? Did you get the unmodified example working on the default SPI, at first? etc. etc. etc.

    Nobody here, even not tonton81 can do telepathy. You really should learn on how to break down and describe a problem scientifically.

  18. #18
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,021
    yes, just be careful the example responds 2 bytes in an array, so either have master send 2 bytes or have the array pointer reset. Teensy to teensy lines are different between 3.x and LC, on one one can be miso to miso, other can be mosi to miso. I’m not exactly sure since it’s been awhile I played with SPI, be sure you have common ground between the 2 boards.

    I would also suggest using SPI transactions instead for your master.

  19. #19
    Thank you, you're right. Here comes a more detailed error description. The slave code is compiled without problems only the function myfunction() is not called. I have crosswired MISO and MOSI as in the example and tried it parallel, unfortunately without success.

  20. #20
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,021
    the isr will only fire if the CS is fired with a common ground, i dont see how it wont work the only issues we faced in the past were bad jumper cables or connections

    since the callback wont fire unless the hardware is triggered, i’d check the wiring. usually a common ground isn’t enough during tests, we had to go from GND pin next to pin0 from teensy to teensy directly

  21. #21
    Alright I have a connected the ground of the teensys directly. Pin 0 -> Pin 0
    so everything should be fine. I will check my cables again...

    Quote Originally Posted by tonton81 View Post
    the isr will only fire if the CS is fired
    What if I do have a master without CS? Can I just keep CS permanently HIGH and it will work?

  22. #22
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,021
    no, well, yes but the array will continuously run in response, at least if you toggle you can fill new data, the function callback cuts out the moment the CS is deasserted

    make sure you are using MSBFIRST mode 0 on master

  23. #23
    Thanks for all the hints and tips! I'll try again tomorrow and will report.

  24. #24
    Ok I have tried all the tips, but without success. Here is my setup:
    I connected a Teensy 3.5 via USB, this is the SPI Slave. I am using SPI Bus 1.

    The Teensy 3.6 gets its power supply from the Teensy 3.5 (PIN 3.3V to VIN and GND to GND). Here I use the standard ports for SPI. The master works according to Saleae Logic Analyser without problems.

    The code from the upper posts has not changed.

    I have measured the voltage at the CS pin and come to about 3.1 volts. Is that enough to fire the isr?

    @tonton81 Can I use the library without CS? What would the construction look like then?
    Code:
    TSPISlave mySPI = TSPISlave(SPI1, miso, mosi, sck, cs <--!!!, spimode);

  25. #25
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,442
    Without looking at the library’s source code, I’d guess that the interrupt is fired not on the absolute level on the cs pin, but on a transition from high to low, i.e. when the master de-asserts the cs pin after having send it’s stuff. But to be shure, look how it’s configured.

Posting Permissions

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