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.

RTOS/EK-TM4C1294XL: QuadSPI DMA blocks

Part Number: EK-TM4C1294XL
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

Folks,

what I did, is creating a single RTOS task to send some bytes out of a tx-buffer to the SSI3 using UDMA. When I set the SSI3 to the legacy mode (=single dataline, MOSI) and use the SPI_transfer(masterSpi, &masterTransaction) it just works perfectly.

But when setting the quad SPI mode by
SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_QUAD_WRITE);

the task is blocked forever. The DMA does NOT set the semaphore      Semaphore_post(Semaphore_handle(&(objec    Semaphore_post(Semaphore_handle(&(object->transferComplete)));

t->transferComplete)));

I've checked the signals on the 4 DATx lines. They are just fine and as expected. The complete transfer is visible including the deassertion of the FSS. Why is the dma still active?

What could I examine to find out what is going wrong? There are a lot of Errata dealing with the SPI quad transfer - is it another bug? Any help appreciated...

  • Hello Claus,

    Can you post the full configuration code for the SSI and DMA?

    I am not aware of an errata item which would impact this, so I am suspicious that something isn't configured correctly.
  • Dear Ralf,
    thanks for taking care of. Please let me point out again, that everything works when using the default SPI single data line mode (=legacy mode). Here is the code I'm using:

    * ----------------------sce remarks -------------------------------------------
    * as found in the Errata the SSI1 only works in Legacy Mode
    * SSI0 and SSI2 lines are used otherwise on the EK-TM4C1294 board
    * ==> SSI3 is used for the advanced SPI quad mode 
    */
    
    // XDCtools Header files
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    // BIOS Header files
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    // TI-RTOS Header files
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/SPI.h>
    // TI-TIVAWARE Driverlib
    #include <driverlib/ssi.h>
    #include "inc/hw_memmap.h"
    // Example/Board Header files
    #include "Board.h"
    
    #define SPI_MSG_LENGTH 28
    #define TASKSTACKSIZE 768
    
    Task_Struct task0Struct;
    Char task0Stack[TASKSTACKSIZE];
    UInt8 masterTxBuffer[SPI_MSG_LENGTH];
    
    Void masterTaskFxn (UArg arg0, UArg arg1) {
    
    	SPI_Handle masterSpi;
    	SPI_Transaction masterTransaction;
    	bool transferOK;
    	UInt8 i;
    
    	for(i=0; i<28; i++) masterTxBuffer[i] = i; // fill TxBuffer
    	masterSpi = SPI_open(Board_SPI0, NULL); // Initialize SPI handle as default master
    
    	if (masterSpi == NULL) System_abort("Error initializing SPI\n");
    	else System_printf("SPI master initialized\n");
    
    	// if I comment out the line below, everything works fine!
    	SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_QUAD_WRITE); // set to quad write mode
    
    	masterTransaction.count = SPI_MSG_LENGTH; // Initialise master SPI transaction structure
    	masterTransaction.txBuf = (Ptr)masterTxBuffer;
    	masterTransaction.rxBuf = NULL;
    
    	transferOK = SPI_transfer(masterSpi, &masterTransaction); // Initiate SPI transfer
    	if(!transferOK) System_printf("Unsuccessful master SPI tx");
    
    	SPI_close(masterSpi); // Deinitialize SPI
    	System_printf("Done\n");
    	System_flush();
    }
    
    int main(void)
    {
    	Task_Params taskParams; // Construct BIOS objects
    
    	Board_initGeneral(); // Call board init functions.
    	Board_initGPIO();
    	Board_initSPI();
    
    	Task_Params_init(&taskParams); // Construct Task thread
    	taskParams.priority = 1;
    	taskParams.stackSize = TASKSTACKSIZE;
    	taskParams.stack = &task0Stack;
    	Task_construct(&task0Struct, (Task_FuncPtr)masterTaskFxn, &taskParams, NULL);
    
    	GPIO_write(Board_LED0, Board_LED_ON); // Turn on user LED
    	BIOS_start(); // Start BIOS
    	return (0);
    }
    

    and here is the SPI part of the EK_TM4C1294XL.c File:

    /*
     * =============================== SPI ===============================
     */
    /* Place into subsections to allow the TI linker to remove items properly */
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_SECTION(SPI_config, ".const:SPI_config")
    #pragma DATA_SECTION(spiTivaDMAHWAttrs, ".const:spiTivaDMAHWAttrs")
    #endif
    
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/spi/SPITivaDMA.h>
    
    SPITivaDMA_Object spiTivaDMAObjects[EK_TM4C1294XL_SPICOUNT];
    
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN(spiTivaDMAscratchBuf, 32)
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment=32
    #elif defined(__GNUC__)
    __attribute__ ((aligned (32)))
    #endif
    uint32_t spiTivaDMAscratchBuf[EK_TM4C1294XL_SPICOUNT];
    
    const SPITivaDMA_HWAttrs spiTivaDMAHWAttrs[EK_TM4C1294XL_SPICOUNT] = {
    		{
    				.baseAddr = SSI3_BASE,
    				.intNum = INT_SSI3,
    				.intPriority = (~0),
    				.scratchBufPtr = &spiTivaDMAscratchBuf[1],
    				.defaultTxBufValue = 0,
    				.rxChannelIndex = 14,
    				.txChannelIndex = 15,
    				.channelMappingFxn = uDMAChannelAssign,
    				.rxChannelMappingFxnArg = UDMA_CH14_SSI3RX,
    				.txChannelMappingFxnArg = UDMA_CH15_SSI3TX
    		}
    };
    
    const SPI_Config SPI_config[] = {
    		{
    				.fxnTablePtr = &SPITivaDMA_fxnTable,
    				.object = &spiTivaDMAObjects[0],
    				.hwAttrs = &spiTivaDMAHWAttrs[0]
    		},
    		{NULL, NULL, NULL}
    };
    
    /*
     * ======== EK_TM4C1294XL_initSPI ========
     */
    void EK_TM4C1294XL_initSPI(void)
    {
    
    	// SSI3
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
    
    	GPIOPinConfigure(GPIO_PQ0_SSI3CLK);
    	GPIOPinConfigure(GPIO_PQ1_SSI3FSS);
    	GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);
    	GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);
    	GPIOPinConfigure(GPIO_PF4_SSI3XDAT2);
    	GPIOPinConfigure(GPIO_PP1_SSI3XDAT3);
    
    	GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    	GPIOPinTypeSSI(GPIO_PORTF_BASE, GPIO_PIN_4 );
    	GPIOPinTypeSSI(GPIO_PORTP_BASE, GPIO_PIN_1 );
    
    	EK_TM4C1294XL_initDMA();
    	SPI_init();
    }
    
    in the header file EK_TM4C1294XL.h the SPI is defined as follows:
    
    /*!
     * @def EK_TM4C1294XL_SPIName
     * @brief Enum of SPI names on the EK_TM4C1294XL dev board
     */
    typedef enum EK_TM4C1294XL_SPIName {
    	EK_TM4C1294XL_SPI3 = 0,
    
    	EK_TM4C1294XL_SPICOUNT
    } EK_TM4C1294XL_SPIName;
    




    Regards Claus

  • Hello Claus,

    Thank you for sharing that, I was hoping the configuration would give me a couple pieces of info that I wanted to clarify about configuration which is if the SSI module is correctly configured per the comments from SSIAdvModeSet:

    //! When using an advanced mode of operation, the SSI module must have been
    //! configured for eight data bits and the \b SSI_FRF_MOTO_MODE_0 protocol.
    //! The advanced mode operation that is selected applies only to data newly
    //! written into the FIFO; the data that is already present in the FIFO is
    //! handled using the advanced mode of operation in effect when that data was
    //! written.

    Can you verify if that configuration requirement is met?

    By chance have you tried this without DMA to track if only the DMA semaphore causes the issue and that it wouldn't occur with just a QSSI semaphore? (Not sure how intensive of a change that would be for you)

  • Good Day Ralph,

    I've now tried out several different versions. Each time the SSI3 was correctly configured as 8bit, Mode 0. The SPIDMA transfer as offered by the RTOS driver stack still is not working with advanced quad SPI.

    To verify that the SSI3 itself works, I used a for loop to write directly into the TX-Fifo. That did the job. It also worked with and without SSIAdvFrameHoldEnable(SSI3_BASE).

    Next I tried to setup the DMA without using the RTOS drivers. After some reading in the datasheets, I managed to get the DMA working. I sent a pattern, beginning with 00,01,02,03. here is a screenshot of clock, FSS, DAT0,DAT1:

    I guess I've to use that code, instead of trying to find out, what is going on in your SPITivaDMA.c

    / * ----------------------sce remarks -------------------------------------------
     * as in the Errata the SSI1 only works at Legacy Mode (single SPI)
     * Also in quadSPI the Dat0 - Dat1 lines are exchanged
     * SSI0 and SSI2 lines are used otherwise on the EK-TM4C1294 board
     * so only SSI3 remains.
     * with UDMA
     */

    // XDCtools Header files
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Types.h>
    #include <xdc/runtime/Error.h>
    // BIOS Header files
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/hal/Hwi.h>
    // TI-RTOS Header files
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/SPI.h>
    // TI-TIVAWARE Driverlib
    #include <driverlib/ssi.h>
    #include <driverlib/udma.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_ssi.h"
    #include "inc/hw_types.h"
    #include "inc/hw_ints.h"
    // Example/Board Header files
    #include "Board.h"

    #define SSI_BUFFER_SIZE   270
    #define TASKSTACKSIZE     768
    #define MSG_LENGTH        28

    Task_Struct task0Struct;
    Char task0Stack[TASKSTACKSIZE];
    Hwi_Handle SSI3IH;

    UInt8  ui8SSITxBuf[SSI_BUFFER_SIZE];  // Tx Buffer
    UInt32 ui32uDMAErrCount = 0;


    //*****************************************************************************
    // SSI3 Interrupt Handler
    //************uDMAErrorHandler*****************************************************************
    void SSI3IntHandler(void)
    {
        UInt32 ui32Status;

        ui32Status = SSIIntStatus(SSI3_BASE, 1);
        SSIIntClear(SSI3_BASE, ui32Status);
        // signal end of transfer
        HWREG(SSI3_BASE + SSI_O_CR1) |= SSI_CR1_EOM;
        HWREG(SSI3_BASE + SSI_O_DR) = ui8SSITxBuf[MSG_LENGTH - 1];
    }


    void masterTaskFxn (UArg arg0, UArg arg1) {

        Types_FreqHz freq;
        UInt16 i;

        for(i=0; i<SSI_BUFFER_SIZE; i++) {
            ui8SSITxBuf[i] = (UInt8)i;  // fill txBuff with pattern
        }

        // configure SSI3
        BIOS_getCpuFreq(&freq);     // spi initialise 1MBaud, 8bit, master
        SSIConfigSetExpClk(SSI3_BASE, freq.lo, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 10000000, 8);
        SSIAdvModeSet(SSI3_BASE, SSI_ADV_MODE_QUAD_WRITE);  // set to quad write mode
        SSIAdvFrameHoldEnable(SSI3_BASE);   // hold FSS

        // configure UDMA
        SSIDMAEnable(SSI3_BASE, SSI_DMA_TX);    // Enable the uDMA interface for TX channel.
        //uDMA SSI3 TX
        // Clear attributes for uDMA SSI3TX channel, should already be done by default.
        uDMAChannelAttributeDisable(15, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
        // Set the USEBURST attribute for the uDMA SSI3TX channel.  This will
        // force the controller to always use a burst when transferring data from the TX buffer
        uDMAChannelAttributeEnable(15, UDMA_ATTR_USEBURST);
        // Configure the control parameters for the SSI3 TX.
        uDMAChannelControlSet(15, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);
        // Set up the transfer parameters for the uDMA SSI3 TX channel.
        uDMAChannelTransferSet(15, UDMA_MODE_BASIC, ui8SSITxBuf, (void *)(SSI3_BASE + SSI_O_DR), MSG_LENGTH-1 );
        uDMAChannelAssign(UDMA_CH15_SSI3TX);    // assign channel mapping
        uDMAChannelEnable(15);              // fill SSI3 Tx Fifo
        SSIIntEnable(SSI3_BASE, SSI_DMATX | SSI_DMARX); // Enable the SSI3 DMA TX/RX interrupts.
        SSIIntEnable(SSI3_BASE, SSI_DMATX); // Enable the SSI3 DMA TX interrupt.
        SSIEnable(SSI3_BASE);               // enable the SSI3, now all bytes in txfifo will be sent

        System_printf("Done\n");
        Hwi_delete(&SSI3IH);
        uDMAChannelDisable(15);
        SSIDisable(SSI3_BASE);               // switch off SSI3
        System_flush();
    }

    int main(void)
    {
        Task_Params taskParams;         // Construct BIOS objects
        Hwi_Params hwiParams;
        Error_Block eb;

        Board_initGeneral();        // Call board init functions.
        Board_initGPIO();
        Board_initSPI();

        Hwi_Params_init(&hwiParams);
        hwiParams.priority = -1;
        SSI3IH = Hwi_create(INT_SSI3,    (Hwi_FuncPtr)(SSI3IntHandler),   &hwiParams, &eb);

        Task_Params_init(&taskParams);    // Construct Task thread
        taskParams.priority = 1;
        taskParams.stackSize = TASKSTACKSIZE;
        taskParams.stack = &task0Stack;
        Task_construct(&task0Struct, (Task_FuncPtr)masterTaskFxn, &taskParams, NULL);

        GPIO_write(Board_LED0, Board_LED_ON);   // Turn on user LED
        BIOS_start();    // Start BIOS
        return (0);
    }

    Regards Klaus-Michael

  • Hello Klaus-Michael,

    Since you are able to get it working with TivaWare calls and not TI-RTOS calls, I am going to pass this thread to the TI-RTOS team who should be able to further help. Thank you for taking those steps to prove out that the issue is with the Semaphore on TI-RTOS. Let's see what the RTOS team comes back with before you fully move forward with using the TivaWare API's within the TI-RTOS implementation.
  • Hi Claus,

    Could you please attach your working CCS project?

    Thanks,

    Janet

  • Good Day Janet,

    please find the project attached as a zipped file....

    Regards Klaus-MichaelQuadSPI_13_EK_sce.zip

  • Hi Klaus,

    I looked into the SPI driver for Tiva some more, and I think as it is currently implemented, it cannot support quad mode.  I set up a SPI master / SPI slave example using quad mode on two MSP432E4 boards (very similar to EK-TM4C129XL).  The result was that the slave got the first message from the master, but the master was stuck in the first SPI_transfer() call.  It seems that the SPI driver is always expecting to get something back, even if you set the RX buffer in the SPI transaction to NULL.  This was causing the master to block in the first SPI_transfer() call.

    I filed a bug against the SPI driver to support this.

    Best regards,

    Janet

  • Claus,

    I'm marking this as "TI Thinks Resolved" since we don't support the quad mode in the current driver. I'm not sure if we'll address this in a future release. The work-around would for you to add the SPI code into your project and add the quad support in yourself. I realize that this is not desirable, but realistically the only thing that TI can offer with this issue now.

    We are looking at adding the quad mode support for the MSP432E4 device later this year.

    Todd