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.

SPI FIFO Issues



Hi -

I'm working with a 28035 dsp and trying to set up the spi interface to work with a motor linear encoder.  The encoder sends back 18 bits of data.  It runs at 1 Mhz.  It has 3 pins - DO (dataout), CSn (chip select) and CLK (clock).

I've set the 28035 up as follows:

28035 is master, character size is 9 bits.

4 wire spi interface (with master out wire not connected - using TALK = 0)

FIFOs and FIFO interrupts enabled  - interrupt level on both tx and rx set to 2 (first question - is this right?)  With the levels set to 2 words, I'm not getting the interrups.  With the level set to 1, I get 1 interrupt but then no more interrupts. 

Question:  How do I set this up so that I can use the spi with FIFOs and FIFO interrupts enabled and get data back more than 1 data set?

Thank you for your help-

M

  • Mary,

    I need to know a few more things:

    Which interrupt are you receiving when you have FIFO set to 1?  Note that in FIFO mode, TX and RX have separate interrupts.  When not using FIFO, these would both be serviced in the same ISR.  It sounds like you are not using TX, so I would leave the interrupt disabled as a precaution if that is the case.  The TX interrupt will execute when the TX FIFO is empty, so this will execute immediately upon enabling that interrupt if you haven't loaded it with anything.

    After you receive both transmissions, what is the value of SPIFFRX[RXFFST], SPIFFRX[RXFFOVF], and SPIFFRX[RXFFIENA]?

    Here is a basic initialization of a SPI using FIFO for this device:

    void spi_fifo_init()
    {
    // Initialize SPI FIFO registers
       SpiaRegs.SPICCR.bit.SPISWRESET=0; // Reset SPI

       SpiaRegs.SPICCR.all=0x001F;       //16-bit character, Loopback mode
       SpiaRegs.SPICTL.all=0x0017;       //Interrupt enabled, Master/Slave XMIT enabled
       SpiaRegs.SPISTS.all=0x0000;
       SpiaRegs.SPIBRR=0x0063;           // Baud rate
       SpiaRegs.SPIFFTX.all=0xC022;      // Enable FIFO's, set TX FIFO level to 4
       SpiaRegs.SPIFFRX.all=0x0022;      // Set RX FIFO level to 4
       SpiaRegs.SPIFFCT.all=0x00;
       SpiaRegs.SPIPRI.all=0x0010;

       SpiaRegs.SPICCR.bit.SPISWRESET=1;  // Enable SPI

       SpiaRegs.SPIFFTX.bit.TXFIFO=1;
       SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;
    }

    Kris

     

  • Currently, I have both TX and RX FIFO interrupts set up.  Previously. I also tried it with only the RX FIFO interrupt enabled.  I have used the example code that you have included above to set up my system. 

    Here is the setup with both interrupts enabled:

    void spi_fifo_init()
    {
    // Initialize SPI FIFO registers
       SpiaRegs.SPICCR.bit.SPISWRESET=0; // Reset SPI

       SpiaRegs.SPIFFTX.all=0xC022;      // Enable FIFO's, set TX FIFO level to 4 (this comment is wrong - it looks like it's set to 2)  also have tried 0xC000
       SpiaRegs.SPIFFRX.all=0x0022;      // Set RX FIFO level to 4
       SpiaRegs.SPIFFCT.all=0x00;
       SpiaRegs.SPIPRI.all=0x0010;

       SpiaRegs.SPICCR.all=0x0048;       //9-bit character, falling edge
       SpiaRegs.SPICTL.all=0x0004;       //Master
       SpiaRegs.SPIBRR=0x0009;           // Baud rate
       SpiaRegs.SPICCR.bit.SPISWRESET=1;  // Enable SPI

       SpiaRegs.SPIFFTX.bit.TXFIFO=1;
       SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;

    }

    I'm not getting how the it works.  Here is my understanding of the process with questions:

    1) The tx fifo interrupt fires.  In the tx isr,  I write 2 words into txbuf.  These 2 words go into the tx fifo.  Do just the first 9 bits of each word go into the fifo or both whole words?  Then the bits get shifted into the spidat register. 

    2) When 2 words or 18 bits (not sure which one) get shifted into the spidat register fromt the device, the rx fifo interrupt fires.  In the isr, I read rxbuf twice.

    If the rx fifo only has 18 bits in it and is set up for an interrupt level of 2, I can see why this doesn't work.

    My ultimate goal is to read 18 bits from the device in one instance of the chip select line being low. 

    I will remove the interrupt from the tx fifo side and send more info.

  • 1) When you write to the register, the whole value is loaded into the SPIDAT register.  So if you are not sending a message equal to the number of bits in the register, you need to left align your values in order to send the proper value.  This is because the value is left shifted out of SPIDAT bit by bit until you have hit the number of bits to send.

    2) As long as you are looking for only 9 bits, it should write the value from SPIDAT to your RX FIFO each time 9 bits is received.  Going along with the previous answer, you will need to handle this in software to read only the lower 9 bits.  Since the received bits are just shifted in on the right side, those upper bits could be any value.  They are not automatically cleared.  However, to answer your question, there should be a FIFO entry for each time 9 bits are received.  The number of values in the in the FIFO is indicated in the status bits mentioned in my previous post.

  • Responses to above:

    1) The transmitted data is dummy data since TALK = 0, so I used 0xABCD and 0x1234 for the 2 values.  I'm just using the TX side to shift data out so RX data can come in on the clock signal.

    2) I can handle shifting the data in software, but I'm not getting the rx interrupt.

    BTW - what are the enhancements for SPIFFENA.  When I set this to 0, I see both words transmitted.  The last word in TXBUF is 0x1234.  If I set the enhancement bit to 1, only the first word goes to TXBUF, but never the second word.  I can't find any documentation on this bit.

    Next I tried this scenario:

    1) Setting the TXFIFO up with no interrupt, either 0, 1 or 2 for TXFFIL(none worked) and SPIRST set to 1.  Doing 2 writes to TXBUF (0xABCD, 0x1234). 

    2) Setting the RXFIFO up with an interrupt, 1 or 2 for RXFFIL. Still not getting an interrupt. 

     

    Answers to previous questions from you:  RXFFST is 0 after I pause (never get interrupt), RXFFOVE is 0 and RXFFIENA is 1.

     

  • Another question -

    Should I be using 3-wire mode instead of 4-wire mode?  I thought 4-wire mode would be OK since I set the tx side to TALK = 0. 

  • More info...

    I scoped the 3 lines and saw that my baud rate was too fast for the device.  I fixed that.  I see the following after transmitting 2 words (0xABCD and 0x1234).

    SPIFFTX:    TXFFIL=2  TXFFINT=1  SPIFFENA = 1 SPIRST = 1     the other bits = 0

    SPIFFRX:    RXFFIL = 2  RXFFIENA=1  RXFFINT= 1 RXFFST=2 (yeah)  RXFIFORESET= 1   the other bits = 0

    So now I'm seeing the RXFFINT bit set and the RX FIFO status is 2.  This is good, but still no isr is being triggered.

    This is the isr setup:

    PieVectTable.SPIRXINTA=&SpiRxFifo_ISR;

    PicCtrlRegs.PIEIER6.bit.INTx1=1;

    Any ideas?

  • Another interrupt was choking the spi rx interrupt out.  Once I disabled the other interrupt, my code ran fine.

    Thanks

  • Mary,

    I'm glad to hear you got this figured out.  I apologize for the delay in getting back to you.  I have been out of the office for the past few days.

    There is one thing I wanted to point out in your response.  You mentioned that you were loading the TX register solely for the purpose of being able to shift in the RX bits.  While this step isn't hurting anything, it is an unnecessary step to take.  When configured as a slave, the SPI will always shift out whatever is loaded in the SPIDAT register (typically the last value that was received if you are not loading it).  If you have TALK = 0 then it won't show on the GPIO, but the master still reads it as 0xFF since the pin is just held high.  So you can save yourself a little overhead by not having to worry about loading the TX register each time you want to read in a value.

    Great job figuring it out!

    Kris

  • Hi-

    The SPI is configured as a master not a slave.  The encoder is the slave.  So I need to load the tx register to get bits from the encoder.

    -Mary

  • Oops, my mistake.  You are correct then!

    Kris

  • Hello, I have a related issue in the F28069 which appears to have the same SPI implementation.  I modified the example code to try to comtrol a chip select by asserting it before loading the FIFO and deasserting it once the FIFO had emptied and generated a TX interrupt (I realize that the FIFO emptying means that there are still bits in the SPIDAT register that haven't been sent yet but I can pad the message to accommodate this, but I can also deassert CS early without ill effect as long as the device has gotten its first clock).

    The problem I am encountering is that even when I load the FIFO up with 4 words of data I get the interrupt almost immediately even though I have TXFFIL set to 0, i.e. give me the interrupt when there are 0 words left in the FIFO (I have also tried values of 1, 2, and 3).  The system seems designed to do exactly what I want, it just doesn't happen to work.  Here's the code.  Note that I read 3 to the local variable count when I set a breakpoint at the following line.  SPIFFCT is set to 0.

    Thanks very much!

    void main(void)
    {
       Uint16 i;

    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2806x_SysCtrl.c file.
       InitSysCtrl();

    // Step 2. Initalize GPIO:
    // This example function is found in the F2806x_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    // InitGpio();  // Skipped for this example
    // Setup only the GP I/O only for SPI-A functionality
       InitSpiaGpio();

    // Step 3. Initialize PIE vector table:
    // Disable and clear all CPU interrupts
       DINT;
       IER = 0x0000;
       IFR = 0x0000;

    // Initialize PIE control registers to their default state:
    // This function is found in the F2806x_PieCtrl.c file.
       InitPieCtrl();

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2806x_DefaultIsr.c.
    // This function is found in F2806x_PieVect.c.
       InitPieVectTable();

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
       EALLOW;  // This is needed to write to EALLOW protected registers
       PieVectTable.SPIRXINTA = &spiRxFifoIsr;
       PieVectTable.SPITXINTA = &spiTxFifoIsr;
       EDIS;   // This is needed to disable write to EALLOW protected registers

    // Step 4. Initialize all the Device Peripherals:
    // This function is found in F2806x_InitPeripherals.c
    // InitPeripherals(); // Not required for this example
       spi_fifo_init();   // Initialize the SPI only

    // Step 5. User specific code, enable interrupts:

    // Enable interrupts required for this example
       PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block
    //   PieCtrlRegs.PIEIER6.bit.INTx1=1;     // Enable PIE Group 6, INT 1  RX
       PieCtrlRegs.PIEIER6.bit.INTx2=1;     // Enable PIE Group 6, INT 2  TX
       IER=0x20;                            // Enable CPU INT6
       EINT;                                // Enable Global Interrupts

     GpioDataRegs.GPADAT.bit.GPIO15 = 1; // disable nCS
     GpioDataRegs.GPADAT.bit.GPIO16 = 1; // disable nCS
     GpioDataRegs.GPADAT.bit.GPIO17 = 1; // disable nCS
       EALLOW;
       GpioCtrlRegs.GPADIR.bit.GPIO15 = 1; // SPI bus SEL0
       GpioCtrlRegs.GPADIR.bit.GPIO16 = 1; // SPI bus SEL1
       GpioCtrlRegs.GPADIR.bit.GPIO17 = 1; // SPI bus SEL2
       EDIS;

    // Step 6. IDLE loop. Just sit and loop forever (optional):
        for(;;)
        {
    //      SpiaRegs.SPICCR.bit.SPISWRESET = 0;

         GpioDataRegs.GPADAT.bit.GPIO15 = 0;  // assert nCS
    //     SpiaRegs.SPIFFTX.bit.TXFIFO = 0;
         SpiaRegs.SPITXBUF= 0xA500;  // LEFT-justified 16-bit value
         SpiaRegs.SPITXBUF= 0xA500;  // LEFT-justified 16-bit value
         SpiaRegs.SPITXBUF= 0xA500;  // LEFT-justified 16-bit value
         SpiaRegs.SPITXBUF= 0xA500;  // LEFT-justified 16-bit value

         int count = SpiaRegs.SPIFFTX.bit.TXFFST;

    //     SpiaRegs.SPIFFTX.bit.TXFIFO = 1;

          SpiaRegs.SPICCR.bit.SPISWRESET = 1;
           PieCtrlRegs.PIEIER6.bit.INTx2=1;     // Enable PIE Group 6, INT 2  TX

         delay_loop();
        }

    }

    // Some Useful local functions
    void delay_loop()
    {
        long      i;
        for (i = 0; i < 1000000; i++) {}
    }

    void error(void)
    {
        asm("     ESTOP0");  //Test failed!! Stop!
        for (;;);
    }

    void spi_fifo_init()
    {
    // Initialize SPI FIFO registers
       SpiaRegs.SPICCR.bit.SPISWRESET=0; // Reset SPI

       SpiaRegs.SPICCR.all=0x000F;       //16-bit character, no Loopback mode


       SpiaRegs.SPICTL.all=0x0017;       //Interrupt enabled, Master/Slave XMIT enabled
       SpiaRegs.SPISTS.all=0x0000;
       SpiaRegs.SPIBRR=6;           // Baud rate divider
    //   SpiaRegs.SPIFFTX.all=0xC022;      // Enable FIFO's, set TX FIFO level to 4
       SpiaRegs.SPIFFTX.all=0xC020;      // Enable FIFO's, set TX FIFO level to 4
    //   SpiaRegs.SPIFFTX.all=0xC024;      // Enable FIFO's, set TX FIFO level to 4
       SpiaRegs.SPIFFCT.bit.TXDLY = 0;

       SpiaRegs.SPIFFRX.all=0x0022;      // Set RX FIFO level to 4
       SpiaRegs.SPIFFCT.all=0x00;
       SpiaRegs.SPIPRI.all=0x0010;

       SpiaRegs.SPICCR.bit.SPISWRESET=1;  // Enable SPI

       SpiaRegs.SPIFFTX.bit.TXFIFO=1;
       SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;
    }

    interrupt void spiTxFifoIsr(void)
    {
        // Disable SPI CLK
        PieCtrlRegs.PIEIER6.bit.INTx2=0;     // Disable PIE Group 6, INT 2  TX

        GpioDataRegs.GPADAT.bit.GPIO15 = 1;  // de-assert nCS

        SpiaRegs.SPIFFTX.bit.TXFFINTCLR=1;  // Clear Interrupt flag
        PieCtrlRegs.PIEACK.all|=0x20;       // Issue PIE ACK
    }

    interrupt void spiRxFifoIsr(void)
    {
        rdata[0]=SpiaRegs.SPIRXBUF;     // Read data

        SpiaRegs.SPIFFRX.bit.RXFFOVFCLR=1;  // Clear Overflow flag
        SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1;  // Clear Interrupt flag
        PieCtrlRegs.PIEACK.all|=0x20;       // Issue PIE ack
    }

    //===========================================================================
    // No more.

     

  • Hello Mary,

    Now I am working on a project with F28035 reading absolute angle data from AustriaMicrosystems' AS5145 magnetic encoder chip. This is also a 18-bits encoder similar to  what you once used. I did not encounter any isse to trigger RX isr, however the data received in RX isr does not look reasonable. Appreciated if you can share some experiences on how to align the received 18bits data.  the initialization  and RX_isr codes are as blow:-

    void spi_fifo_init()
    {
    // Initialize SPI FIFO registers
       SpiaRegs.SPICCR.bit.SPISWRESET=0; // Reset SPI

       SpiaRegs.SPICCR.all=0x0048;       //9-bit character, Loopback mode //1F
       SpiaRegs.SPICTL.all=0x0004;       //Interrupt enabled, Master/Slave XMIT enabled//17
       SpiaRegs.SPISTS.all=0x0000;
       SpiaRegs.SPIBRR=0x0009;           // Baud rate//0x0063//0x0013
       SpiaRegs.SPIFFTX.all=0xC022;      // Enable FIFO's, set TX FIFO level to 4
       SpiaRegs.SPIFFRX.all=0x0022;      // Set RX FIFO level to 2//0x0022
       SpiaRegs.SPIFFCT.all=0x00;
       SpiaRegs.SPIPRI.all=0x0010;

       SpiaRegs.SPICCR.bit.SPISWRESET=1;  // Enable SPI

       SpiaRegs.SPIFFTX.bit.TXFIFO=1;
       SpiaRegs.SPIFFRX.bit.RXFIFORESET=1;
    }

    interrupt void spiRxFifoIsr(void)
    {
             
        rdata_0=SpiaRegs.SPIRXBUF;     // Read 1st data in RXFIFO
        rdata_0 = rdata_0& 0x01FF;          // get the lower 9 bits
        rdata_0 = rdata_0<<3;           // shift to 12-4 bits
        rdata_1= SpiaRegs.SPIRXBUF;     // Read 2nd data in RXFIFO 
        rdata_1 = (rdata_1>>6)& 0x0007;  // get the lower 3 bits
        AS5145 = rdata_0 | rdata_1;
           rdata_point++;
        SpiaRegs.SPIFFRX.bit.RXFFOVFCLR=1;  // Clear Overflow flag
        SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1;  // Clear Interrupt flag
        PieCtrlRegs.PIEACK.all|=0x20;       // Issue PIE ack
    }

    Thanks!

    Harvey

  • Hi Harvey-

    I, too, had a similar problem with my data - both position and megnetic strength.  I wanted to use the TI spi interface and not do any bit banging.  So I used (2X10) 20 bits instead of 18.  Here is my macro:

     

    //-----------------------------------------------------------------------------
    // GET_SPI_ENC_DATA_MACRO
    //
    // Reads data from the SPI RX fifo.  RX data is right justified in fifo
    // buffer.
    //
    // Used to read 20 bits of data and status bitsfrom 2 FIFO registers with
    // no interrupts enabled.  The RXFFST status register must be 2 before calling
    // this function.  Returns an absolute count value between 0 and 4095 inclusive. 
    // Each 4096 counts is 2 mm on the encoder.
    //
    // The data for both position and magnet strength are returned in 2-10 bit
    // words.  The position data is as follows:
    //      x  d  d  d  d  d  d  d  d  d  d  d  d  s  s  s  s  s  s  x
    //     __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
    // Bit 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    //
    // The magnetic strength data is as follows:
    //      d  d  d  d  d  d  d  d  d  d  d  d  s  s  s  s  s  s  x  x
    //     __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
    // Bit 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    //
    // where d = data bits
    //       s = status bits
    //   x = not used
    //
    //-----------------------------------------------------------------------------
    #define GET_SPI_ENC_DATA_MACRO(rxVal)      \
    {               \
     if (SpiaRegs.SPIFFRX.bit.RXFFST >= NUM_RW)    \
     {              \
      rxVal =   (SpiaRegs.SPIRXBUF & SPI_DATA_BIT_MASK); \
      rxVal <<= BITS_PER_SPI_CHAR;      \
      rxVal +=  (SpiaRegs.SPIRXBUF & SPI_DATA_BIT_MASK); \
     }              \
    }

    NUM_RW = 2

    BITS_PER_SPI_CHAR = 10

    SPI_DATA_BIT_MASK = 0x03ff (10 right most bits)

    If you look at the trace on a scope you may see (like I did) that using (2X9) 18 bits doesn't quite cut it timing wise.

    good luck-

    Mary

     

  • Thank you Mary for your kind input! 

    I get it fixed with 10bit setting and actually it also works well when use RX ISR routine.

    Good day!

    Harvey

    .