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.

SSI Driver, Data Frame Size



TI,

I'm interfacing with a SPI device using my LM4F120 LaunchPad and the StellarisWare libraries.  This SPI device requires a minimum 24-bit frame size (transmit 24 bits during one FSS/CS assertion (low)).  Specifically, I'm using the SSIDataPut() function in \StellarisWare\driverlib\ssi.c which accepts an unsigned long parameter called ulData.  The comments in the function say the following about this parameter:


//! \param ulData is the data to be transmitted over the SSI interface.
//!
//! \note The upper 32 - N bits of \e ulData are discarded by the hardware,
//! where N is the data width as configured by SSIConfigSetExpClk(). For
//! example, if the interface is configured for 8-bit data width, the upper 24
//! bits of \e ulData are discarded.

This function works great when ulData is between 4 and 16, inclusively, but I cannot create a 24-bit data frame size using the built-in SSI peripheral since SSIConfigSetExpClk() says the following about its unsigned long parameter, ulDataWidth:


//! \param ulDataWidth specifies number of bits transferred per frame.

//! The \e ulDataWidth parameter defines the width of the data transfers and

//! can be a value between 4 and 16, inclusive.

Therefore, it looks like I am out of luck using the built-in SSI peripheral to interface with my device.  Is there a way to configure the SSI peripheral to transmit more than 16 bits per SPI transmission or will I have to use a Soft-SPI and bit-bang it?

Thanks a lot for your time!

Sean

  • Hi,

    Yes ou can create/send 24 bits: use either 2x12 bits or 3x8 bits words to be sent to SSI's FIFO - but  take care to choose a continuos/back to back data transmission mode when you configure the SSI. This is the advantage to have a FIFO - the bits are chained for longer frames. And SSI start transmitting immediately it has something into the FIFO and doesn't stop until FIFO is empty.

    Petrei.

  • Petrei,

    It doesn't seem like the current StellarisWare SSI modules (integrated into ssi.c or SoftSSI) allows you to dynamically fill the FIFO while the transmission logic clocks out bits one-by-one.  The datasheet says that the SSI module is specifically designed (even in continuous modes) to de-assert then re-assert the FSS/CS between frames so that the LM4F120H5QR can latch data using the FSS (frames being a maximum of 16 bits since the 16 MSBs of the 32-bit FIFO are reserved).  To keep the FIFO filled up, will I have to use the DMA/uDMA feature?  If I do, I guess I'm not entirely sure how to keep my data contiguous.  As in, let's say I setup a DMA request to be initiated when my FIFO is less than half full (as it is clocking out data bits) and I put another 8 bits in it when it has has already clocked out 4 of the previous 8 bits, leaving 12 available bits in the XMT FIFO.  I'm imagining that, at the moment the DMA occurs and I use the SSI FIFO as a destination, I'll have my 4 remaining data bits as the MSBs, 4 random bits, then my additional 8 bits of good data to be transmitted (0x1010 XXX 1010 1010).  So my questions are:

    1. Will I have to setup a DMA with the SSI FIFO as a destination to keep the FIFO full or is there another, easier, way?

    2. If I DO need to use DMA, how do I ensure that the data stays contiguous?

    3. It seems like the current StellarisWare drivers (ssi.c and softssi.c) both limit the amount of data put into the FIFO as 16 bits then assume that no more than 16 bits will ever be clocked out during one particular frame (hard-coded).  Is this true?  I'm worried that even if I keep the FIFO filled up, once it hits 16 bits, it will end the transmission and de-assert the FSS/CS, anyway, if I continue to use the StellarisWare SSI lib (and I don't want to have to re-write any SSI drivers if I can avoid it).

    I really appreciate the help!  It seems like this could be a pretty common issue as the SPI device I'm using operates in a similar fashion to the MICROWIRE SPI protocol.  It requires the master to transmit at least 3 bytes in a SPI master write frame (during a single CS assertion): Ctrl/DevAddr Byte, SlaveRegAddr Byte, Data Byte to be written.  Reads occur by writing the Ctrl/DevAddrByte and SlaveRegAddr Byte, then the slave clocks the reg data out.  It seems more I2C-ish rather than SPI to me, but it is what it is and it is certainly not turning out as easy as I'd originally hoped.

    Thanks again and have a great night!!

    Sean

  • Hi,

    Reading your first post didn't seems to me you need a Microwire protocol, seems to be a Freescale mode with 24 bits sent - if you search this forum you will find several cases with devices using big number of bit to be sent. For those cases, there is no need to use DMA, SPI is OK. It would be better to specify from the beginning the device you need to interface with.

    Now for your case: do you need to interface to an 93LC46 EEPROM? these devices have a Microwire "compatible" protocol - if yes, then could be some problems. I used such device in an application, but with another micro brand, without SPI, and wrote some .asm routines to deal with, using GPIO.

    But what is your device?

    Petrei

  • Sean Sarniak said:
    The datasheet says that the SSI module is specifically designed (even in continuous modes) to de-assert then re-assert the FSS/CS between frames so that the LM4F120H5QR can latch data using the FSS (frames being a maximum of 16 bits since the 16 MSBs of the 32-bit FIFO are reserved).

    Is this true in every mode of operation?  If so, this is new behavior.  The SSI module in the fury class devices can definitely put out back-to-back SPI words with no gap between them,  I've done this in several projects in the past.  Note - it does not work in all 4 modes, only in 2 of them, and I can't recall off the top of my head which modes they were.

    I didn't care so much about whether chip select was de-asserted between frames, I was more interested in maximum throughput, with no delays between the words being transmitted, and a side effect was that CS was asserted throughout the transmission.

  • Petrei and Slandrum,

    I am interfacing with a MCP23S17 SPI I/O Expander and would like to use the StellarisWare lib if I can (or as much of it as I can) and I'm using Mode 0, which it appears that the MCP23S17 wants.  I have seen some other examples in these forums in which, to complete my exact needs (low CS for longer than 16 bits of consecutive data), people were able to call SSIDataPut() in quick succession enough to keep filling the FIFO and therefore keeping the FSS pin low (setup to send 8 bits per call, similar to what I think Slandrum accomplished above); however, making three immediately successive calls to SSIDataPut() still results in the CS de-asserting for a short time between words in my case, so that won't work.  I tried modifying and calling SSIDataPut() with three 8-bit values and writing to the register three successive times (within SSIDataPut()), but that results in just overwriting the LSBs in the FIFO everytime and doesn't result in placing each byte in the next FIFO location in memory, as I'd want it to do (how are you supposed to write to deeper FIFO locations, anyway?).  I also tried just using a GPIO pin to act as my CS, but can't embed it's control in the SSIDataPut() since it just fills the FIFO and returns, it doesn't have any direct relationship to the output logic timing (clock, CS, etc.), so the GPIO pin ends up out of sync with my intended CS and prematurely de-asserts, anyway.  So I guess I can't think of an easy way to control CS outside of the built-in SSI periph by still rely on the SSI periph for clock and data.

    1. If I, for example, wanted to fill deeper locations of the FIFO in order to prepare more than 16 bits of data to be clocked out, how do I write to those deeper locations?  I was hoping that a write to the (SSIbase + SSI_DR) #defined data register address would increment some pointer if necessary to not overwrite data already in the FIFO (like it seems to in other forum examples that use quick calls to SSIDataPut()), but it appears to be just overwriting the lowest bytes in my case.

    Thanks!

    Sean

  • You can use several calls to SSIDataPut() in rapid succession to put more data into the FIFO.

    How do you have your SSI configured?  If it's configured as 16 bit, then you need to write 16 bit values every time.  If it's configured as 8 bit, then you write 8 bit values every time.

    If you want to manually manipulate CS, then your code would look something like:

    1) Pull CS low

    2) Send data word

    3) if more data words to send loop back to 2

    4) wait for SSIBusy to clear (make sure the last byte has clocked out)

    5) return CS to high

    Another method that can be used, since SSI Data clocks both directions simultaneously

    1) Pull CS low

    2) Send as many words as need to be sent (assuming it's no more than the length of the hardware FIFO)

    3) Read back as many words as have been sent (call SSIDataGet(), not the non-blocking version)

    4) Return CS to high

  • Slandrum,

    As I noted in my previous reply, calling SSIDataPut() three times in a row STILL results in the CS being de-asserted for a short time between bytes.  I just re-ran the program and re-verified it on the scope again to be sure.

    Even if I fill up the FIFO many locations deep, won't the SSI logic still depend on the data size in the call below to determine frame size?

    //
    // Configure and enable the SSI port for SPI master mode. Use SSI2,
    // system clock supply, idle clock level low and active low clock in
    // freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    // The MCP23S17 is CPOL=0 & CPHA=0 == Mode=0.
    //
    SSIConfigSetExpClk(SSI2_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER, 1000000, 8);

    It just seems more and more like I will need to control my own CS, which I didn't really want to have to do, but even if just to verify that the target device works, I'll head down that route for a while.

    Thanks for the help so far.

    Sean

  • If you configure the SSI for 8 bit words, and you write 3 words to the FIFO, then the FIFO will cause 3 8-bit words to be sent out.  I guess I'm not understanding your point?

    On Fury class devices, I've been able to have the SSI keep CS selected throughout transmissions of several words, but it was dependent on the mode.  Two of the 4 modes would keep the CS asserted (and have no pauses in the clock).  Two of the modes would pause the clock for one bit time between successive words, and CS would de-assert during this pause.  I think that internally it's dependent on whether you using leading or trailing edge clocking, and the actual steps that the internal peripheral state machine is going through.

    I was fortunate enough to control the devices at both ends of the SPI, so I could select the communication mode arbitrarily.  It sounds like you don't have the luxury, so may have to resort to manually controlling the CS line.

    Every microcontroller I've used has had quirks and shortcomings and non-standard behavior somewhere in its peripherals.  I've spent a lot of time writing code to work around the issues in the peripherals.  It's unfortunate and annoying, but it is the nature of the business.