Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 50 of 50

Thread: SPISlave_T4

  1. #26

    available() has a bug?

    Hey @tonton81,

    I'm working on adding slave mode to all the Teensy's, using your libraries (TSPISlave and SPISlave_T4) as inspiration. Thank you very much for writing them!

    I noticed that your "available()" function in the SPISlave_T4 library uses the following code:

    Code:
    SPISlave_T4_FUNC bool SPISlave_T4_OPT::available() {
        SLAVE_PORT_ADDR;
        return ( (SLAVE_SR & (1UL << 8)) ) ? 1 : 0;
    }
    So basically the function returns true if bit 8 in the SR register is set. From what I can see in the reference manual, that bit is WCF (Word Complete Flag). However I think what you really want to test here is the RDF flag (Read Data Flag) in bit 1. That bit indicates whether the number of words in the FIFO buffer is greater than the RXWATER setting in FCR (which your code sets to 0).

    I must say I just got started on the Teensy 4, and I haven't tested your code yet. So I apologize if I have it wrong. But reading through the documentation I figured that RDF would be the obvious flag to test and apparently WCF simply tests if the currently arriving data frame (byte/word/longword) has been received completely. So I wonder if this could be why others reported above that it was behaving strangely.

    By the way, your code might be easier to read if you would use the symbolic names from imxrt.h instead of values. With my proposed change, the code would then change into the following (I think):

    Code:
    SPISlave_T4_FUNC bool SPISlave_T4_OPT::available() {
        // Change the following into a macro. Or better: calculate the address at construction time and keep the pointer as member variable
        volatile IMXRT_LPSPI_t *spiAddr = (volatile IMXRT_LPSPI_t*)(0x40394000 + (0x4000 * _portnum));
    
        return (spiAddr.SR & LPSPI_SR_RDF) != 0; // My change
        // Your code would be equivalent to: return (spiAddr.SR & LPSPI_SR_WCF) != 0;
    }
    Thanks!

    ===Jac
    Last edited by jac_goudsmit; 01-02-2022 at 07:19 AM. Reason: mistake

  2. #27
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    for future support of other SPIx interfaces, that won't be possible as you specified static addressing, the code was designed to take variable bus addresses into consideration since the offsets are identical but the start addressing is different per object

  3. #28
    Quote Originally Posted by tonton81 View Post
    for future support of other SPIx interfaces, that won't be possible as you specified static addressing
    ??? I'm not sure what you're referring to, but I used the same code as you did to calculate the address, based on the _portnum member variable. The only difference is that I cast the pointer to a volatile IMXRT_LPSPI_t pointer instead of a volatile uint32_t.

    Would you care to comment on my remark that the "available( )" function should test bit 1 instead of bit 8?

    Thanks!

    ===Jac

  4. #29
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    not without testing of course, it's not on my bench right now

    the pointer is still volatile but with offsets, but i am saying you are using the hardcoded SPI address which is what the code takes from the bus used, so instead of hardcoding 3 sets with conditions, only 1 check is needed with the template for that object

  5. #30
    Quote Originally Posted by tonton81 View Post
    not without testing of course, it's not on my bench right now
    Fair enough. I intend to test it myself too, probably later today.

    the pointer is still volatile but with offsets, but i am saying you are using the hardcoded SPI address which is what the code takes from the bus used, so instead of hardcoding 3 sets with conditions, only 1 check is needed with the template for that object
    The entire struct is volatile, so any operation on any field in the struct that might normally get optimized (e.g. setting a bit and then clearing it again) won't (shouldn't) get optimized away because of the volatile keyword. It doesn't matter whether you use a volatile int pointer with an offset, or a volatile struct pointer with a field name.

    The Teensyduino declares three instances of the same class and uses the base address as one of the constructor parameters. The pointer gets stored in the instance and gets used for all hardware operations as needed, via the port() function. No templates needed.

    By the way, I think the Teensyduino code has a minor problem too when it comes to volatile-ness of the struct: imxrt.h doesn't use volatile in its declaration of the location (e.g. IMXRT_LPSPI4_S), and in SPI.cpp/SPI.h the pointer gets passed around and stored as a uintptr_t, and converted back to a IMXRT_LPSPI_t * by the port() function. I think the use of the port() function avoids unwanted optimization but that could (should?) have been accomplished by declaring the pointers with the volatile keyword in imxrt.h.

    ===Jac
    Last edited by jac_goudsmit; 01-02-2022 at 09:00 PM.

  6. #31
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    Morning @tonton81

    Just ran into a problem - rather confusing. While compiling mstransfer got a strange error from the SPISlave library so as a test I compiled the example sketch (spi_slave.ino) for the T41 and sure enough got the same error message:
    Code:
    C:\Users\Merli\AppData\Local\Temp\arduino_build_430336\libraries\SPI_MSTransfer-master\SPI_MSTransfer.cpp.o: In function `lpspi4_slave_isr()':
    D:\Users\Merli\Documents\Arduino\libraries\SPISlave_T4-main/SPISlave_T4.tpp:19: multiple definition of `lpspi4_slave_isr()'
    C:\Users\Merli\AppData\Local\Temp\arduino_build_430336\sketch\spi_slave.ino.cpp.o:D:\Users\Merli\Documents\Arduino\libraries\SPISlave_T4-main/SPISlave_T4.tpp:19: first defined here
    c:/users/merli/appdata/local/arduino15/packages/teensy/tools/teensy-compile/1.56.1/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions
    collect2.exe: error: ld returned 1 exit status
    Not sure how to fix it?

  7. #32
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    Code:
    void lpspi4_slave_isr() {
      _LPSPI4->SLAVE_ISR();
    }
    
    try declaring it as static? or maybe removing the #include in the tpp file for thr .h file, the h. points to the tpp anyways

  8. #33
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    Quote Originally Posted by tonton81 View Post
    Code:
    void lpspi4_slave_isr() {
      _LPSPI4->SLAVE_ISR();
    }
    
    try declaring it as static? or maybe removing the #include in the tpp file for thr .h file, the h. points to the tpp anyways
    Thanks Tony - wanted to let you know.

    EDIT: This worked:
    Code:
    void static lpspi4_slave_isr() {
      _LPSPI4->SLAVE_ISR();
    }
    Last edited by mjs513; 02-26-2022 at 03:32 PM.

  9. #34
    Junior Member
    Join Date
    Feb 2022
    Posts
    6
    Hi, so I've always used your 3.x version of this library but now I've tried to port my already existing project to the T4 version and the problematic thing is that the library doesn't detect the active() state right. Im using a nordic as a master and am manually setting and clearing the CS pin but the program doesn't exit my ISR callback anymore.
    I also tried your example and it has the same problem.

  10. #35
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    verify the CS, SCK, and GND pins are properly secured

  11. #36
    Junior Member
    Join Date
    Feb 2022
    Posts
    6
    Quote Originally Posted by tonton81 View Post
    verify the CS, SCK, and GND pins are properly secured
    Okay done, everything is fine (I verified by running a simple script just reading out the pin status which is high when there's no data send)

    I can see the SCK running alright by just looking at the LED ON PIN 13. Basically as soon as the lines are connected, my teensy will always stay in the callback function

    all the data is coming in just fine, but also only if I enable .sniffer().. does this have to do anything with my problem?

  12. #37
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    your MISO &MOSI pins may be reversed, in sniffer mode it basically snoops on what a master is sending on that line

  13. #38
    Junior Member
    Join Date
    Feb 2022
    Posts
    6
    Quote Originally Posted by tonton81 View Post
    your MISO &MOSI pins may be reversed, in sniffer mode it basically snoops on what a master is sending on that line
    nope, that's not it. I actually get all the right data but after quitting transmission the application doesn't exit the callback.

  14. #39
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    I am stumped. Trying to get the slave code working on a T4.0 while using a T4.1 as the master. Not sure I have the master correctly set up:
    Code:
    #include <SPI.h>
    
    void setup() {
      // initialize the digital pin as an output.
      pinMode(10, OUTPUT);
      SPI.begin();
    
    }
    
    void loop() {
      for(uint8_t i = 0; i < 9; i++){
          SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
          digitalWriteFast(10, LOW);
          Serial.println(SPI.transfer(i));
          delayMicroseconds(1);
          digitalWriteFast (10, HIGH);
          SPI.endTransaction();
      }
      Serial.println("=============");
      delay(500);
    }

  15. #40
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    @tonton81

    Was digging into the code a bit more and I don't think myFunc is ever being assigned via the OnReceive call. When I run the master with this slight change in the loop:
    Code:
          SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
          digitalWriteFast(10, LOW);
          for(uint8_t i = 0; i < 9; i++){
            Serial.println(SPI.transfer(0));
          }
          delayMicroseconds(1);
          digitalWriteFast (10, HIGH);
          SPI.endTransaction();
      Serial.println("=============");
      delay(500);
    this is what I am seeing in the slave window:
    Code:
    millis: 7416
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    millis: 8416
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 
    millis: 9416
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0
    and this is in the master:
    Code:
    =============
    0
    0
    255
    0
    0
    0
    0
    0
    0
    =============
    It looks like its bypassing the function assignment:
    Code:
      if ( _spihandler ) {
        _spihandler();
        SLAVE_SR = 0x3F00;
        asm volatile ("dsb");
        return;
      }
    and printing from here:
    Code:
      while ( !(SLAVE_SR & (1UL << 9)) ) { /* FCF: Frame Complete Flag, set when PCS deasserts */
        if ( SLAVE_SR & (1UL << 11) ) { /* transmit error, clear flag, check cabling */
          SLAVE_SR = (1UL << 11);
          transmit_errors++;
        }
        if ( (SLAVE_SR & (1UL << 8)) ) { /* WCF set */
          uint32_t val = SLAVE_RDR;
          Serial.print(val); Serial.print(" ");
          SLAVE_TDR = val;
          SLAVE_SR = (1UL << 8); /* Clear WCF */
        }
      }
      Serial.println();
    only other place that the slave code prints data out. Maybe its related to this change I made: https://forum.pjrc.com/threads/66389...l=1#post301214

  16. #41
    Junior Member
    Join Date
    Feb 2022
    Posts
    6
    Quote Originally Posted by tonton81 View Post
    your MISO &MOSI pins may be reversed, in sniffer mode it basically snoops on what a master is sending on that line
    I think I found what causes the error but don't quite understand why its different here than in the 3.x version.

    if I disable the interrupt and read the spirit line in the main loop, I need to clear the line by calling mySPI.popr()which is obvious but I don't understand why it doesn't work in the interrupt as intended. I read every single available byte with popr() but still stay in the interrupt even if I stop transmission.

  17. #42
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    Ok pretty much give up. I tried the sketches from here: https://forum.pjrc.com/threads/60702...ight=tspislave, on the T4 and all it prints are 255's but on the T3s works fine. myFunc is just not firing!

  18. #43
    Junior Member
    Join Date
    Feb 2022
    Posts
    6
    Quote Originally Posted by mjs513 View Post
    Ok pretty much give up. I tried the sketches from here: https://forum.pjrc.com/threads/60702...ight=tspislave, on the T4 and all it prints are 255's but on the T3s works fine. myFunc is just not firing!
    have you added myFunc() as the handler ->

    mySPI.onReceived(myFunc); in setup()

    That's the only point where the handler is added.
    In the 3.x library you didnt have to do the mySPI.begin() bit though

  19. #44
    Junior Member
    Join Date
    Feb 2022
    Posts
    6
    For me, I got this working (though only in the main loop as I said) but Im dropping bytes sometimes. This also didnt happen with the 3.x version. What's different here? Its the same master sending the same packages but they are not well received.

  20. #45
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    Quote Originally Posted by julius View Post
    For me, I got this working (though only in the main loop as I said) but Im dropping bytes sometimes. This also didnt happen with the 3.x version. What's different here? Its the same master sending the same packages but they are not well received.
    Understood - for me I need it working with the interrupt mode. Yep - added in the onRecieve(myFunc) handler as well.

  21. #46
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    8,138
    Ok finally figured out what was going on after several days. Such a simple fix to make it work.

    Change this:
    Code:
      mySPI.begin();
      mySPI.onReceive(myFunc);
    to
    Code:
      mySPI.onReceive(myFunc);
      mySPI.begin();
    and it works as expected.

  22. #47
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,878
    Quote Originally Posted by mjs513 View Post
    Ok finally figured out what was going on after several days. Such a simple fix to make it work.

    Change this:
    Code:
      mySPI.begin();
      mySPI.onReceive(myFunc);
    to
    Code:
      mySPI.onReceive(myFunc);
      mySPI.begin();
    and it works as expected.
    Good but painful find Mike.

  23. #48
    Junior Member
    Join Date
    May 2022
    Posts
    2

    Compiling error...

    Hi !

    Beginner (well, I guess...) question here.

    I'm trying to compile the SPISlave_T4 sample with Arduino IDE, but I got this error : SPISlave_T4.tpp: No such file or directory
    In which folder are the header and template files supposed to be ? I just put them in the main project location...


    Thx for your help :-)

  24. #49
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    should be the arduino/libraries folder, not the main project location

  25. #50
    Junior Member
    Join Date
    May 2022
    Posts
    2
    Great ! It works now THX !!!

Posting Permissions

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