Because of the holidays, TI E2E™ design support forum responses will be delayed from Dec. 25 through Jan. 2. Thank you for your patience.

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28379D: Reading the angle from a SSI encoder using SPI

Part Number: TMS320F28379D
Other Parts Discussed in Thread: LAUNCHXL-F28379D, C2000WARE,

Hi community!

I am using a LAUNCHXL-F28379D for the communication with a SSI absolute encoder. According to the datasheet of the encoder, I need a constant time delay (tm) between the clock cycles. Besides, the number of bits that should be received in each cycle is 13. 

For generating the mentioned delay, I have configured the SPI module in FIFO mode. I tied to provide the delay by using SPIFFCT. However,  based on the delay of the code execration, the delay varies! here you can find my code:

   for(;;)
   {
       sdata = 56;
       sdata = sdata*8;
     // Transmit data
     spi_xmit(sdata);
     // Wait until data is received
     while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
     // Check against sent data
     delay_loop();
     rdata = SpiaRegs.SPIRXBUF;
    // if(rdata != sdata) error();

   }

It sends a number (e.g. 56) and recives it back in "rdata". However, changing the "delay_loop()" length, changes the delay that has been set by SPIFFCT. Here are my configurations:

void spi_init()
{    
    SpiaRegs.SPICCR.all =0x004C;                 // Reset on, rising edge, 16-bit char bits
    SpiaRegs.SPICTL.all =0x0006;                 // Enable master mode, normal phase,
                                                 // enable talk, and SPI int disabled.
    SpiaRegs.SPIBRR.all =0x0031;
    SpiaRegs.SPICCR.all =0x00DC;                 // Relinquish SPI from Reset
    SpiaRegs.SPIPRI.bit.FREE = 1;                // Set so breakpoints don't disturb xmission
}

void spi_xmit(Uint16 a)
{
    SpiaRegs.SPITXBUF=a;
}    

void spi_fifo_init()
{
// Initialize SPI FIFO registers
    SpiaRegs.SPIFFTX.all=0xE040;
    SpiaRegs.SPIFFRX.all=0x205F;    
    SpiaRegs.SPIFFCT.all=0x7;
}  

Would anyone please help me? Is there any better way for providing the constant delay as written in the datasheet? (about 12 us).

Regards.

  • Hi Jake,

    Is there any particular reason why you have decided to use a polling approach versus interrupts? Also, why you add a delay right before reading the received data?

    Based on what you are trying to do I would suggest using interrupts. A good example of how to implement this can be found within C2000Ware,

    C:\ti\c2000\C2000Ware_version\device_support\f2837xd\examples\cpu1\spi_loopback_interrupts

    The example has loopback enabled (SpiaRegs.SPICCR.bit.SPILBK = 1;) but you can always disable this within the InitSpi() function. 

    Using the SPIFFCT register should enable you to define the delay between every transfer from FIFO transmit buffer to transmit shift register defined in number SPI serial clock cycles. 

    Best Regards,

    Marlyn

  • Hi Marlyn.

    Thanks for the reply.

    The reason why I need a delay is the SSI protocol as depicted in here : 

    I don't think my problem is due to not using interrupts. I have read many threats in e2e and can't find an approved solution.

    SSI is a simple protocol and its not good that the TI can't propose a solution to the customers that are using  TMS320F28379D or older versions.

    Now would you please let me know if I can provide the delay (Tm as shown in the picture) using the SPICLK ?

    Regards

  • Hi Jake,

    I don't believe there is a native way to add the pause time required. Please refer to this thread:  

    Best Regards,

    Marlyn

  • Hi Marlyn

    I have already seen that threat before. But what about using the delayed transform feature using the SPIFFCT register? Would you please guide me how to use this for generating the clock needed by the encoder?

    What about this idea? : connecting the MOSI instead of SPICLK to the encoder. Then generating the clock signal needed by the encoder by using the output data from DSP at the port of MOSI. 

    Regards.

  • Hi Jake,

    When you do not change the "delay_loop()" length do you see the expected delay between transfers?

    Jake Jegil said:
    Then generating the clock signal needed by the encoder by using the output data from DSP at the port of MOSI. 

    I'm not sure I follow this last part. Could you please explain again how you would like to generate the clock?

    Best Regards,

    Marlyn

  • Jake Jegil said:
    The reason why I need a delay is the SSI protocol as depicted in here

    The attached program was created for a LAUNCHXL-F28379D to test generating such a clock pulse train on SPIA. Not sure of the exact characteristics of your encoder but chose:

    1. A 1MHz clock.
    2. A 14-bit word length in the SPI. This is because for N encoder data bits, N+1 clock bits are required. E.g. for 13 encoder data bits the SPI needs to generate 14 clock pulses per word, and the software would only use the least significant 13-bits of each word.
    3. A 12 us delay between words. Not that while initially expected to program SpiaRegs.SPIFFCT.bit.TXDLY as 12, had to use 11 to get the required delay. See the comment in the spi_fifo_init function in the attached example.
    4. Set CLKPOLARITY = 1 and CLK_PHASE = 1 to match the protocol shown for the encoder. This is described as the SPICLK Scheme of "Falling edge with delay" in the TMS320F2837xD Dual-Core Microcontrollers Technical Reference Manual (Rev. I)

    The following is a LSA capture which shows a 12 us delay between 14 clock bits:

    Since I don't have an actual encoder to test, used a jumper link between the LAUNCHXL-F28379D J2 Pin 15 (SPISIMOA) and J2 Pin 14 (SPISOMIA) for the running program which checks that the transmitted test pattern is loop-back externally as the receive data.

    The main program consists of the following loop structure, which just runs a busy loop to keep the SPI occupied, such that the SpiaRegs.SPIFFCT.bit.TXDLY programmed hardware delay control the gap between each set of 14 clock pulses:

       const Uint16 data_mask = 0x3fff; /* Using 14 bit SPI words */
       sdata = 0x0000;
       expected_rdata = sdata;
       for(;;)
       {
           //
           // Transmit data
           // As are using 14-bits have to the left justify the transmitted data.
           // This keeps the TX FIFO full, so the delay between transmitted words is kept at the programmed
           // SpiaRegs.SPIFFCT.bit.TXDLY delay
           //
           while (SpiaRegs.SPIFFTX.bit.TXFFST < 16)
           {
               spi_xmit(sdata << 2);
               sdata = (sdata + 1) & data_mask;
           }
    
           //
           // Wait until data is received
           //
           while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
    
           //
           // Check against sent data
           //
           rdata = SpiaRegs.SPIRXBUF & data_mask;
           if(rdata != expected_rdata)
           {
               error();
           }
           expected_rdata = (expected_rdata + 1) & data_mask;
       }
    

    For use with an actual encoder the transmitted data would just be a dummy value, and the code would process the receive data containing the absolute encoder position.

    Note the transmit loop which fills the 16 word transmit FIFO before continuing to wait for one receive word. By keeping the transmit FIFO should keep a consistent gap between each 14-bit clock pulse stream.

    spi_loopback_delay.zip

  • Hello Chester,

    I really appreciate for your help.

    I have tested the code, and it works fine as you said. However, as I firstly mentioned, when a delay (resulting from the execution of my algorithm) happens inside the "for" loop, the clock stops producing signal. I tested this by adding a delay() function in the "for" loop as bellow:

       for(;;)
       {
           //
           // Transmit data
           // As are using 14-bits have to the left justify the transmitted data.
           // This keeps the TX FIFO full, so the delay between transmitted words is kept at the programmed
           // SpiaRegs.SPIFFCT.bit.TXDLY delay
           //
           while (SpiaRegs.SPIFFTX.bit.TXFFST < 16)
           {
               spi_xmit(sdata << 2);
               sdata = (sdata + 1) & data_mask;
           }
    
           //
           // Wait until data is received
           //
           while(SpiaRegs.SPIFFRX.bit.RXFFST !=1) { }
    
           //
           // Check against sent data
           //
           rdata = SpiaRegs.SPIRXBUF & data_mask;
          // if(rdata != expected_rdata)
          // {
          //     error();
          // }
           expected_rdata = (expected_rdata + 1) & data_mask;
           delay_loop();
       }
    }

    Why does this happen? Consider that instead of the delay() function, I need to do some post-processing on the data received from SPI. what should I do with latency of the processing? It may stop the SPI clock!

    Kind regards.

  • Jake Jegil said:
    However, as I firstly mentioned, when a delay (resulting from the execution of my algorithm) happens inside the "for" loop, the clock stops producing signal.

    Do you mean the clock completely stops, or just that the delay between clock pulse chains exceeds the 12 microsecond delay requested by the SpiaRegs.SPIFFCT.bit.TXDLY value?

  • Hello again,

    It completely stops producing signal on the pin SPICLK !

    Regards.

  • Hi Jake,

    Does the clock signal stop immediately at the start of the delay or is it some time during the delay?

    Best Regards,

    Marlyn