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.

TMS320F2808: SPI write of more than 16 (FIFO) words

Part Number: TMS320F2808
Other Parts Discussed in Thread: C2000WARE

I am looking for an algorithm or an example of how to write more that the 16 words with the FIFO enabled. I am going to be adding a 16MBit SPI EEPROM to our design and wish to be able to write more than 16 consecutive words. If the FIFO requires disabling to be able to achieve this, that's OK as well.

  • Hi Jeffrey,

    You cannot write more than 16 words to the FIFO as this exceeds the limit. You can keep the FIFO full by continuously writing to the it, but checking first if it is full. Below is a routine we include in our C2000ware for later generation devices, but you can create your own for the F2808.

    //*****************************************************************************
    //
    //! Waits for space in the FIFO and then puts data into the transmit buffer.
    //!
    //! \param base specifies the SPI module base address.
    //! \param data is the left-justified data to be transmitted over SPI.
    //!
    //! This function places the supplied data into the transmit buffer of the
    //! specified SPI module once space is available in the transmit FIFO. This
    //! function should only be used when the FIFO is enabled.
    //!
    //! \note The data being sent must be left-justified in \e data. The lower
    //! 16 - N bits will be discarded where N is the data width selected in
    //! SPI_setConfig(). For example, if configured for a 6-bit data width, the
    //! lower 10 bits of data will be discarded.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static inline void
    SPI_writeDataBlockingFIFO(uint32_t base, uint16_t data)
    {
        //
        // Check the arguments.
        //
        ASSERT(SPI_isBaseValid(base));
    
        //
        // Wait until space is available in the receive FIFO.
        //
        while(SPI_getTxFIFOStatus(base) == SPI_FIFO_TXFULL)
        {
        }
    
        //
        // Write data to the transmit buffer.
        //
        HWREGH(base + SPI_O_TXBUF) = data;
    }

    //*****************************************************************************
    //
    //! Get the transmit FIFO status
    //!
    //! \param base is the base address of the SPI port.
    //!
    //! This function gets the current number of words in the transmit FIFO.
    //!
    //! \return Returns the current number of words in the transmit FIFO specified
    //! as one of the following:
    //! \b SPI_FIFO_TX0, \b SPI_FIFO_TX1, \b SPI_FIFO_TX2, \b SPI_FIFO_TX3,
    //! ..., or \b SPI_FIFO_TX16
    //
    //*****************************************************************************
    static inline SPI_TxFIFOLevel
    SPI_getTxFIFOStatus(uint32_t base)
    {
        //
        // Check the arguments.
        //
        ASSERT(SPI_isBaseValid(base));
    
        //
        // Get the current FIFO status
        //
        return((SPI_TxFIFOLevel)((HWREGH(base + SPI_O_FFTX) & SPI_FFTX_TXFFST_M) >>
                                 SPI_FFTX_TXFFST_S));
    }

  • Thanks for the response Gus but I was finally able to work something out and if anyone else is interested, this is my answer.

    To be able to do > 16 words of consecutive SPI writes, use with the following algorithm:

    void _spi_write(volatile struct SPI_REGS* spir, Uint16* data, Uint16 numbytes)
    {
        // Writes to SPITXBUF must be left-justified for less than 16 bits per 'character' to send.
        // Filling the SPITXBUF auto sends the byte to SPIDAT (assuming no pending data in SPIDAT)
        //    and then onto the data out line
        Uint16 i, j = 0;
        Uint16 numFullFifo = numbytes / SPI_FIFO_SIZE;
        Uint16 numLessFifo = numbytes % SPI_FIFO_SIZE;
        // Need to be able to write consecutive words > 16 in size
        do
        {
            if (j < numFullFifo)
            {
                for (i = 0; i < SPI_FIFO_SIZE; i++)
                {
                    // spir->SPICCR.bit.SPICHAR + 1 since SPICHAR of 0 is 1 bit, 1 is 2 bits
                    //   so a SPICHAR of 7 is really 8 bits
                    spir->SPITXBUF = data[i + (j * SPI_FIFO_SIZE)] << (16 - (spir->SPICCR.bit.SPICHAR + 1));
                }
    
                // wait until bits have shifted out
                while(spir->SPIFFTX.bit.TXFFST != 0) { }
                j++;
            }
            else
            {
                if(numLessFifo > 0)
                {
                    for (i = 0; i < numLessFifo; i++)
                    {
                        // spir->SPICCR.bit.SPICHAR + 1 since SPICHAR of 0 is 1 bit, 1 is 2 bits
                        //   so a SPICHAR of 7 is really 8 bits
                        spir->SPITXBUF = data[i + (j * SPI_FIFO_SIZE)] << (16 - (spir->SPICCR.bit.SPICHAR + 1));
                    }
    
                    // wait until bits have shifted out
                    while(spir->SPIFFTX.bit.TXFFST != 0) { }
                }
                break;
            }
        } while(true);
    
        DELAY_US(SPI_INTERMSG_DELAY);
    }

    However if you need to read more than 16 words, then the above algorithm will not work for the "while(spir->SPIFFRX.bit.RXFFST != numbytes)". It will only ever read the last 16 words. To read > 16 words such as a block of EEPROM, you need to do the following:

    Uint16 Read_I2CEEPROM(Uint16 address, Uint16* data, Uint16 numbytes) {
        Uint16 i = 0;
        Uint16 fullwords = numbytes / MAX_I2C_DATA_BYTES;
        Uint16 finalbytes = numbytes % MAX_I2C_DATA_BYTES;
        Uint16 results = DATA_SUCCESS;
    
        if(results == DATA_SUCCESS)
        {
            do
            {
                if (i < fullwords)
                {
                    results |= EEPROM_Read_Memory((address + (i * MAX_I2C_DATA_BYTES)), data, MAX_I2C_DATA_BYTES);
                    if(results != DATA_SUCCESS)
                        break;
                    
                    ServiceDog();
                    i++;
                }
                else if(finalbytes > 0)
                {
                    results |= EEPROM_Read_Memory((address + (i * MAX_I2C_DATA_BYTES)), data, finalbytes);
                    if(results != DATA_SUCCESS)
                        break;
                    break;
                }
            } while(true);
        }
        return results;
    }

  • Glad you were able to come up with something that works for you. Just note that your spi_write function looks overly complicated. You can write words to the TX FIFO as long as it is not full. I would write spi_write as follows:

    for (i = 0; i < numbytes; i++)

    {

        spir->SPITXBUF = data[i] << (16 - (spir->SPICCR.bit.SPICHAR + 1));

        while(spir->SPIFFTX.bit.TXFFST == SPI_FIFO_SIZE);

    }

    The check on TXFFST will wait until there is at least one spot available in the TX FIFO.

  • Thanks - that works just as well!! :-)