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.

TM4C129ENCPDT: TM4C129ENCPDT

Part Number: TM4C129ENCPDT

Tool/software:

Hi, i am working on a project that requires communicating in quad spi in dma mode.I had referred few example codes udma_demo and ssi_quad_mode from Tiva Series board examples.I am using EK TM4C129EXL board,SSI0 to send and SSI1 to receive, the data is not being received.If anyone could suggest what am i missing it would be helpful.Thankyou in advance.

//*****************************************************************************
//
// ssi_quad_mode.c - Demonstrates configuring SSI0 and SSI1 in Quad-SSI mode.
//
// Copyright (c) 2019-2020 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.2.0.295 of the EK-TM4C129EXL Firmware Package.
//
//*****************************************************************************

#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_ssi.h"
#include "inc/hw_udma.h"
#include "inc/hw_types.h"
#include "driverlib/fpu.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#include "utils/uartstdio.h"

//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Quad-SSI Master (ssi_quad_mode)</h1>
//!
//! This example shows how to configure SSI0 as a Quad-SSI Master and SSI1 as a
//! Quad-SSI slave.  The master device will send four characters to the slave
//! device using the advanced Quad mode.  In Quad-SSI mode, four bits are sent
//! on each SSI Clock pulse.  Once the Quad-SSI slave receives the four
//! characters in its receive FIFO it will generate an interrupt.
//!
//! This example uses the following peripherals and I/O signals.  You must
//! review these and change as needed for your own board:
//! - SSI0 peripheral
//! - GPIO Port A peripheral (for SSI0 pins)
//! - SSI0Clk    - PA2
//! - SSI0Fss    - PA3
//! - SSI0XDAT0  - PA4
//! - SSI0XDAT1  - PA5
//! - SSI0XDAT2  - PA6
//! - SSI0XDAT3  - PA7
//!
//! - SSI1 peripheral
//! - GPIO Port B, D, E peripheral (for SSI1 pins)
//! - SSI1Clk    - PB5
//! - SSI1Fss    - PB4
//! - SSI1XDAT0  - PE4
//! - SSI1XDAT1  - PE5
//! - SSI1XDAT2  - PD4
//! - SSI1XDAT3  - PD5
//!
//! This example requires board level connection between SSI0 and SSI1.
//!
//! UART0, connected to the Virtual Serial Port and running at 115,200, 8-N-1,
//! is used to display messages from this application.
//
//*****************************************************************************

//****************************************************************************
//
// The variable g_ui32SysClock contains the system clock frequency in Hz.
//
//****************************************************************************
uint32_t g_ui32SysClock;

//*****************************************************************************
//
// Global flag to indicate data was received
//
//*****************************************************************************
volatile uint32_t g_bReceiveFlag = 0;

//*****************************************************************************
//
// Number of bytes to send and receive.
//
//*****************************************************************************
#define NUM_SSI_DATA            4
//
// The size of the memory transfer source and destination buffers (in words).
//
//*****************************************************************************
#define MEM_BUFFER_SIZE         1024
//*****************************************************************************
//
// The size of the UART transmit and receive buffers.  They do not need to be
// the same size.
//
//*****************************************************************************
#define UART_TXBUF_SIZE         4
#define UART_RXBUF_SIZE         4
//*****************************************************************************
//
// The count of times the uDMA interrupt occurred but the uDMA transfer was not
// complete.  This should remain 0.
//
//*****************************************************************************
static uint32_t g_ui32BadISR = 0;
//*****************************************************************************
//
// The source and destination buffers used for memory transfers.
//
//*****************************************************************************
static uint32_t g_ui32SrcBuf[MEM_BUFFER_SIZE];
static uint32_t g_ui32DstBuf[MEM_BUFFER_SIZE];
//*****************************************************************************
//
// The count of SSI buffers filled, one for each ping-pong buffer.
//
//*****************************************************************************
static uint32_t g_ui32RxBufACount = 0;
static uint32_t g_ui32RxBufBCount = 0;
//*****************************************************************************
//
// The transmit and receive buffers used for the UART transfers.  There is one
// transmit buffer and a pair of recieve ping-pong buffers.
//
//*****************************************************************************
static uint8_t g_ui8TxBuf[UART_TXBUF_SIZE];
static uint8_t g_ui8SSIRxBufA[UART_RXBUF_SIZE];
static uint8_t g_ui8SSIRxBufB[UART_RXBUF_SIZE];
//*****************************************************************************
//
// The count of memory uDMA transfer blocks.  This value is incremented by the
// uDMA interrupt handler whenever a memory block transfer is completed.
//
//*****************************************************************************
static uint32_t g_ui32MemXferCount = 0;

//*****************************************************************************
//
// The count of uDMA errors.  This value is incremented by the uDMA error
// handler.
//
//*****************************************************************************
static uint32_t g_ui32uDMAErrCount = 0;
//*****************************************************************************
//
// The control table used by the uDMA controller.  This table must be aligned
// to a 1024 byte boundary.
//
//*****************************************************************************
#if defined(ewarm)
#pragma data_alignment=1024
uint8_t pui8ControlTable[1024];
#elif defined(ccs)
#pragma DATA_ALIGN(pui8ControlTable, 1024)
uint8_t pui8ControlTable[1024];
#else
uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024)));
#endif

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif


void TransmitDataSSI0(uint32_t *data, uint32_t numBytes);
void ReceiveDataSSI1(uint32_t *data, uint32_t numBytes);
void ConfigureSSI(void);
void ConfigureUART(void);

uint32_t pui32DataTx[NUM_SSI_DATA];
uint32_t pui32DataRx[NUM_SSI_DATA];
//*****************************************************************************
//
// The interrupt handler for uDMA errors.  This interrupt will occur if the
// uDMA encounters a bus error while trying to perform a transfer.  This
// handler just increments a counter if an error occurs.
//
//*****************************************************************************
void uDMAErrorHandler(void)
{
    uint32_t ui32Status;

    //
    // Check for uDMA error bit
    //
    ui32Status = uDMAErrorStatusGet();

    //
    // If there is a uDMA error, then clear the error and increment
    // the error counter.
    //
    if (ui32Status)
    {
        uDMAErrorStatusClear();
        g_ui32uDMAErrCount++;
    }
}

//*****************************************************************************
//
// The interrupt handler for uDMA interrupts from the memory channel.  This
// interrupt will increment a counter, and then restart another memory
// transfer.
//
//*****************************************************************************
void uDMAIntHandler(void)
{
    uint32_t ui32Mode;

    //
    // Check for the primary control structure to indicate complete.
    //
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SW);
    if (ui32Mode == UDMA_MODE_STOP)
    {
        //
        // Increment the count of completed transfers.
        //
        g_ui32MemXferCount++;

        //
        // Configure it for another transfer.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_SW, UDMA_MODE_AUTO, g_ui32SrcBuf,
                               g_ui32DstBuf,
                               MEM_BUFFER_SIZE);

        //
        // Initiate another transfer.
        //
        uDMAChannelEnable(UDMA_CHANNEL_SW);
        uDMAChannelRequest(UDMA_CHANNEL_SW);
    }

    //
    // If the channel is not stopped, then something is wrong.
    //
    else
    {
        g_ui32BadISR++;
    }
}

//*****************************************************************************
//
// SSI0 Interrupt Handler
//
//*****************************************************************************
void SSI0IntHandler(void)
{

    uint32_t ui32Status;
    uint32_t ui32Mode;

    //READ INTERRUPT STATUS OF SSI
    ui32Status = SSIIntStatus(SSI1_BASE, 1);
    // Clear any pending status
    SSIIntClear(SSI1_BASE, ui32Status);
    //
    // Check the DMA control table to see if the ping-pong "A" transfer is
    // complete.  The "A" transfer uses receive buffer "A", and the primary
    // control structure.
    //
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI1RX | UDMA_PRI_SELECT);
    //
    // If the primary control structure indicates stop, that means the "A"
    // receive buffer is done.  The uDMA controller should still be receiving
    // data into the "B" buffer.
    //
    if (ui32Mode == UDMA_MODE_STOP)
    {
        //
        // Increment a counter to indicate data was received into buffer A.  In
        // a real application this would be used to signal the main thread that
        // data was received so the main thread can process the data.
        //
        g_ui32RxBufACount++;
        //
        // Set up the next transfer for the "A" buffer, using the primary
        // control structure.  When the ongoing receive into the "B" buffer is
        // done, the uDMA controller will switch back to this one.  This
        // example re-uses buffer A, but a more sophisticated application could
        // use a rotating set of buffers to increase the amount of time that
        // the main thread has to process the data in the buffer before it is
        // reused.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
        UDMA_MODE_PINGPONG,
                               (void*) (SSI1_BASE + SSI_O_DR), g_ui8SSIRxBufA,
                               sizeof(g_ui8SSIRxBufA));
    }
    //
    // Check the DMA control table to see if the ping-pong "B" transfer is
    // complete.  The "B" transfer uses receive buffer "B", and the alternate
    // control structure.
    //
    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT);
    //
    // If the alternate control structure indicates stop, that means the "B"
    // receive buffer is done.  The uDMA controller should still be receiving
    // data into the "A" buffer.
    //
    if (ui32Mode == UDMA_MODE_STOP)
    {
        //
        // Increment a counter to indicate data was received into buffer A.  In
        // a real application this would be used to signal the main thread that
        // data was received so the main thread can process the data.
        //
        g_ui32RxBufBCount++;

        //
        // Set up the next transfer for the "B" buffer, using the alternate
        // control structure.  When the ongoing receive into the "A" buffer is
        // done, the uDMA controller will switch back to this one.  This
        // example re-uses buffer B, but a more sophisticated application could
        // use a rotating set of buffers to increase the amount of time that
        // the main thread has to process the data in the buffer before it is
        // reused.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT,
        UDMA_MODE_PINGPONG,
                               (void*) (SSI1_BASE + SSI_O_DR), g_ui8SSIRxBufB,
                               sizeof(g_ui8SSIRxBufB));
    }
    //
    // If the UART1 DMA TX channel is disabled, that means the TX DMA transfer
    // is done.
    //
    if (!uDMAChannelIsEnabled(UDMA_CHANNEL_SSI1RX))
    {
        //
        // Start another DMA transfer to UART1 TX.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
        UDMA_MODE_BASIC,
                               g_ui8TxBuf, (void*) (SSI1_BASE + SSI_O_DR),
                               sizeof(g_ui8TxBuf));

        //
        // The uDMA TX channel must be re-enabled.
        //
        uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
    }
}

//*****************************************************************************
//
// Configure the SSI and its pins. This must be called before UARTprintf().
//
//*****************************************************************************
void ConfigureSSI(void)
{

    //
    // Run from the PLL at 120 MHz.
    // Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
    // later to better reflect the actual VCO speed due to SYSCTL#22.
    //
    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    SYSCTL_OSC_MAIN |
    SYSCTL_USE_PLL |
    SYSCTL_CFG_VCO_240),
                                        120000000);

    //
    // The SSI0 and SSI1 peripheral must be enabled for use.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    //
    // For this example SSI0 is used with PortA[7:2].  The SSI1 uses
    // PortB, PortD and PortE for the SSICLK, SSIFss and the 4 data pins.
    // GPIO ports need to be enabled so those pins can be used.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    //
    // Configure the pin muxing for SSI0 functions on PA[7:2].
    // Configure the pin muxing for SSI1 functions on PB, PD and PE.
    //
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
    GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
    GPIOPinConfigure(GPIO_PA6_SSI0XDAT2);
    GPIOPinConfigure(GPIO_PA7_SSI0XDAT3);

    GPIOPinConfigure(GPIO_PB5_SSI1CLK);
    GPIOPinConfigure(GPIO_PB4_SSI1FSS);
    GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
    GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);
    GPIOPinConfigure(GPIO_PD4_SSI1XDAT2);
    GPIOPinConfigure(GPIO_PD5_SSI1XDAT3);

    //
    // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware.  Consult the data sheet to
    // see which functions are allocated per pin.
    // The pins are assigned as follows:
    //      SSI0
    //      PA7 - SSI0XDAT3
    //      PA6 - SSI0XDAT2
    //      PA5 - SSI0XDAT1
    //      PA4 - SSI0XDAT0
    //      PA3 - SSI0Fss
    //      PA2 - SSI0CLK
    //      SSI1
    //      PD5 - SSI1XDAT3
    //      PD4 - SSI1XDAT2
    //      PE5 - SSI1XDAT1
    //      PE4 - SSI1XDAT0
    //      PB4 - SSI1Fss
    //      PB5 - SSI1CLK
    //
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 |
    GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
    GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_5 | GPIO_PIN_4);
    GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4);
    GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_5 | GPIO_PIN_4);

    //
    // Configure and enable the SSI0 port for SPI master mode.  Use SSI0,
    // system clock supply, idle clock level low and active low clock in
    // freescale SPI mode, master mode, 2MHz SSI frequency, and 8-bit data.
    // For SPI mode, you can set the polarity of the SSI clock when the SSI
    // unit is idle.  You can also configure what clock edge you want to
    // capture data on.  Please reference the device datasheet for more
    // information on the different SPI modes.
    //
    SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER,
                       2000000, 8);

    //
    // Configure and enable the SSI1 port for SPI slave mode.
    //
    SSIConfigSetExpClk(SSI1_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
    SSI_MODE_SLAVE,
                       2000000, 8);

    //
    // Enable Quad-SSI mode for both SSI0 and SSI1.
    //
    SSIAdvModeSet(SSI0_BASE, SSI_ADV_MODE_QUAD_WRITE);
    SSIAdvModeSet(SSI1_BASE, SSI_ADV_MODE_QUAD_READ);

    //
    // Hold the Fss pin low during transfers.  The Fss will be controlled
    // directly by the SSIAdvDataPutFrameEnd().  If calling
    // SSIAdvDataPutFrameEnd to write data to the FIFO, the Fss is de-asserted
    // for the corresponding data.
    //
    SSIAdvFrameHoldEnable(SSI0_BASE);
    //
    // Enable processor interrupts.
    //
    IntMasterEnable();

    //
    // Enable SSI1 interrupt on RX FIFO full.
    //
    SSIIntEnable(SSI1_BASE, SSI_RXFF);

    //
    // Enable the SSI1 interrupts on the processor (NVIC).
    //
    IntEnable(INT_SSI1);

    //
    // Enable the SSI0 and SSI1 modules.
    //
    SSIEnable(SSI0_BASE);
    SSIEnable(SSI1_BASE);

    //
    // Read any residual data from the SSI port.  This makes sure the receive
    // FIFOs are empty, so we don't read any unwanted junk.  This is done here
    // because the SPI SSI mode is full-duplex, which allows you to send and
    // receive at the same time.  The SSIDataGetNonBlocking function returns
    // "true" when data was returned, and "false" when no data was returned.
    // The "non-blocking" function checks if there is any data in the receive
    // FIFO and does not "hang" if there isn't.
    //
    while (SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0]))
    {
    }
    while (SSIDataGetNonBlocking(SSI1_BASE, &pui32DataRx[0]))
    {
    }
}
//*****************************************************************************
//
// Configure the UART and its pins. This must be called before UARTprintf().
//
//*****************************************************************************
void ConfigureUART(void)
{
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, g_ui32SysClock);
}

//*****************************************************************************
//
// When the received FIFO is half-full, an interrupt will be generated.
//
//*****************************************************************************
void SSI1IntHandler(void)
{
    uint32_t ui32Status;

    //
    // Read the SSI Masked Interrupt Status.
    //
    ui32Status = SSIIntStatus(SSI1_BASE, true);

    //
    // Clear the SSI interrupt.
    //
    SSIIntClear(SSI1_BASE, ui32Status);

    //
    // Turn off the RX FIFO interrupt.
    //
    SSIIntDisable(SSI1_BASE, SSI_RXFF);

    //
    // Toggle flag to indicate that data has been received.
    //
    g_bReceiveFlag = 1;
}
void InitSSI0Transfer(void)
{

    uint_fast16_t ui16Idx;

    //
    // Fill the TX buffer with a simple data pattern.
    //
    for (ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++)
    {
        g_ui8TxBuf[ui16Idx] = ui16Idx;
    }

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);

//    SSIDisable(SSI0_BASE);
    SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
    SSI_MODE_MASTER,2000000, 8);
    SSIConfigSetExpClk(SSI1_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_0,
        SSI_MODE_MASTER,2000000, 8);
    SSIEnable(SSI0_BASE);

    SSIDMAEnable(SSI0_BASE,SSI_DMA_TX);
    SSIDMAEnable(SSI1_BASE, SSI_DMA_RX);

    ROM_uDMAChannelAssign(UDMA_CH11_SSI0TX);
    ROM_uDMAChannelAssign(UDMA_CH24_SSI1RX);

    //
    // Put the attributes in a known state for the uDMA UART1RX channel.  These
    // should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI1RX,
          UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
          UDMA_ATTR_HIGH_PRIORITY |
          UDMA_ATTR_REQMASK);

    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);


//    HWREG(SSI0_BASE + SSI_O_CR1) |= SSI_CR1_LBM;//Loopback mode to/from the QSSI*

    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
    UDMA_ARB_4);


    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT,
      UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
      UDMA_ARB_4);



    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG,
                           (void*) (SSI0_BASE + SSI_O_DR), g_ui8SSIRxBufA,
                           sizeof(g_ui8SSIRxBufA));

    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG,
                           (void*) (SSI0_BASE + SSI_O_DR), g_ui8SSIRxBufB,
                           sizeof(g_ui8SSIRxBufB));

//    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI1RX, UDMA_ATTR_USEBURST);

    ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI1RX);
    ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);

    //
    // Enable the SSI DMA TX/RX interrupts.
    //
    ROM_SSIIntEnable(SSI0_BASE, SSI_DMA_TX);
    ROM_SSIIntEnable(SSI0_BASE, SSI_DMA_RX);


    ROM_IntEnable(INT_SSI0);
    ROM_IntEnable(INT_SSI1);

}


//*****************************************************************************
//
// Configure SSI0 in Quad-SSI master Freescale (SPI) mode and SSI1 in Quad-SSI
// slave mode.  The SSI0 will send out 4 bytes of data in advanced Quad mode
// and the SSI1 slave will receive the 4 bytes of data also in Quad mode. The
// slave will generate interrupt upon receiving the 4 bytes of data.
//
//*****************************************************************************
int main(void)
{
    uint32_t ui32Index;
    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                                SYSCTL_OSC_MAIN |
                                                SYSCTL_USE_PLL |
                                                SYSCTL_CFG_VCO_480), 120000000);
    ConfigureUART();
    ConfigureSSI();
    uDMAEnable();

    SysCtlDelay(g_ui32SysClock / 20 / 3);

    uDMAControlBaseSet(pui8ControlTable);

    InitSSI0Transfer();

    pui32DataTx[0]='Q';
    pui32DataTx[1]='S';
    pui32DataTx[2]='S';
    pui32DataTx[3]='I';

    TransmitDataSSI0(pui32DataTx, NUM_SSI_DATA);

    ReceiveDataSSI1(pui32DataRx, NUM_SSI_DATA);
    while (1)
    {

    }
    return 0;
}
void TransmitDataSSI0(uint32_t *data, uint32_t numBytes)
{
    uint32_t ui32Index;
    SSIDMAEnable(SSI0_BASE,SSI_DMA_TX);
    for (ui32Index = 0; ui32Index < NUM_SSI_DATA; ui32Index++)
    {
        //
        // Dummy write to start slave which is required for Quad-SSI
        // mode operation.
        //
        MAP_SSIDataPut(SSI1_BASE, 0);
        //
        // Check if the last data byte is queued up to be sent.
        //
        if (ui32Index == (NUM_SSI_DATA - 1))
        {
            //
            // Calling SSIAdvDataPutFrameEnd on the last data will put out the
            // data and de-assert the the Fss pin.
            //
            MAP_SSIAdvDataPutFrameEnd(SSI0_BASE, pui32DataTx[ui32Index]);
        }
        else
        {
            //
            // Send the data using the "blocking" put function.  This function
            // will wait until there is room in the send FIFO before returning.
            // This allows you to assure that all the data you send makes it
            // into the send FIFO.
            //
            MAP_SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]);
        }
    }
}
void ReceiveDataSSI1(uint32_t *data, uint32_t numBytes)
{
    uint32_t ui32Index;
    SSIDMAEnable(SSI1_BASE,SSI_DMA_RX);
    for (ui32Index = 0; ui32Index < 4; ui32Index++)
    {
//        while (!(MAP_SSIBusy(SSI1_BASE)))
//        {
//        }; // Wait until SSI1 is not busy
        //
        // Receive the data using the "blocking" Get function.  This function
        // will wait until there is data in the receive FIFO before returning.
        //
        SSIDataGetNonBlocking(SSI1_BASE, &pui32DataRx[ui32Index]);

        //
        // Since we are using 8-bit data, mask off the MSB.
        //
        pui32DataRx[ui32Index] &= 0x00FF;
        UARTprintf("'%c' ", data[ui32Index]);
    }
    g_bReceiveFlag = 0; // Clear the receive flag after receiving all data
}