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.

CCS/TM4C123GH6PM: UDMA Ping Pong transfer with Transceiver and Receiver

Part Number: TM4C123GH6PM

Tool/software: Code Composer Studio

I´m working on a project where I transfer data with ping-pong buffers. Two buffers for transceive and two buffers for receive. I don´t know if the transceive side of the ping pong transfer is right in the "hwi_SSI_ISR()". Can anybody tell me? How can I test it, if when the ping (transceive) is full, the dma is switching to pong buffer (transceive)? And is it necessary to transfer it before in the SSIDR (SSI Data Register)?

#define TARGET_IS_TM4C123_RA1

#include <stdint.h>
#include <stdbool.h>

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
//#include "inc/hw_uart.h"
#include "inc/hw_ssi.h"

#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#include "driverlib/ssi.h"

//----------------------------------------
// BIOS header files
//----------------------------------------
#include <xdc/std.h>                        //mandatory - have to include first, for BIOS types
#include <ti/sysbios/BIOS.h>                //mandatory - if you call APIs like BIOS_start()
#include <xdc/cfg/global.h>                 //header file for statically defined objects/handles
#include <xdc/runtime/Log.h>                //used for Log_info() calls
#include <xdc/runtime/System.h>

// Buffer definitions
#define SSI_TX_BUFFER_SIZE         256
#define SSI_RX_BUFFER_SIZE         256
static uint8_t g_ui8SSITxPing[SSI_TX_BUFFER_SIZE];
static uint8_t g_ui8SSITxPong[SSI_TX_BUFFER_SIZE];
static uint8_t g_ui8SSIRxPing[SSI_RX_BUFFER_SIZE];
static uint8_t g_ui8SSIRxPong[SSI_RX_BUFFER_SIZE];


// Error counter
static uint32_t g_ui32DMAErrCount = 0;

// Transfer counters
static uint32_t g_ui32SSITxPingCount = 0;
static uint32_t g_ui32SSITxPongCount = 0;
static uint32_t g_ui32SSIRxPingCount = 0;
static uint32_t g_ui32SSIRxPongCount = 0;

int i16ToggleCount = 0;


// uDMA control table aligned to 1024-byte boundary
#pragma DATA_ALIGN(ucControlTable, 1024)
uint8_t ucControlTable[1024];

// Library error routine
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

// uDMA error handler
void hwi_uDMA_error_ISR(void)
{
    uint32_t ui32Status;

    ui32Status = ROM_uDMAErrorStatusGet();

    if(ui32Status)
    {
    	ROM_uDMAErrorStatusClear();
        g_ui32DMAErrCount++;
    }
}

// SSI interrupt handler. Called on completion of uDMA transfer
void hwi_SSI_ISR(void)
{
	i16ToggleCount += 1;                                    // keep track of #toggles

	Log_info1("LED TOGGLED [%u] TIMES",i16ToggleCount);     // send toggle count to UIA

    uint32_t ui32Status;
    uint32_t ui32Mode;

    ui32Status = ROM_SSIIntStatus(SSI0_BASE, 1);

    ROM_SSIIntClear(SSI0_BASE, ui32Status);

//    g_ui8SSITxPing[0] = g_ui32SSITxPingCount;
//    g_ui8SSITxPong[0] = g_ui32SSITxPingCount + 10;

    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT);

    if(ui32Mode == UDMA_MODE_STOP)
    {
        g_ui32SSIRxPingCount++;

        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
                                   UDMA_MODE_PINGPONG,
                                   (void *)(SSI0_BASE + SSI_O_DR),
                                   g_ui8SSIRxPing, sizeof(g_ui8SSIRxPing));

        ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    }


    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT);

    if(ui32Mode == UDMA_MODE_STOP)
    {
        g_ui32SSIRxPongCount++;

        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT,
                                   UDMA_MODE_PINGPONG,
                                   (void *)(SSI0_BASE + SSI_O_DR),
                                   g_ui8SSIRxPong, sizeof(g_ui8SSIRxPong));

        ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    }

    if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0TX))
    {

        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT);

        if(ui32Mode == UDMA_MODE_STOP)
        {
            g_ui32SSITxPingCount++;

            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
                                   UDMA_MODE_PINGPONG, g_ui8SSITxPing,
                                   (void *)(SSI0_BASE + SSI_O_DR),
                                   sizeof(g_ui8SSITxPing));

            ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
        }


        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT);

        if(ui32Mode == UDMA_MODE_STOP)
        {
            g_ui32SSITxPongCount++;

            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
                                   UDMA_MODE_PINGPONG, g_ui8SSITxPong,
                                   (void *)(SSI0_BASE + SSI_O_DR),
                                   sizeof(g_ui8SSITxPong));

            ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
        }

    }

//    if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT))
//    {
//    	g_ui32SSITxPongCount++;
//
//    	            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
//    	                                   UDMA_MODE_PINGPONG, g_ui8SSITxPong,
//    	                                   (void *)(SSI0_BASE + SSI_O_DR),
//    	                                   sizeof(g_ui8SSITxPong));
//
//    	            ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
//    }
}

// Initialize SSI uDMA transfer
void InitSPITransfer(void)
{
    uint_fast16_t ui16Idx;

    //
    // Fill the TX buffer with a simple data pattern.
    //
    for(ui16Idx = 0; ui16Idx < SSI_TX_BUFFER_SIZE; ui16Idx++)
    {
        g_ui8SSITxPing[ui16Idx] = 2;
        g_ui8SSITxPong[ui16Idx] = 4;
    }

    //
    // Enable the uDMA interface for both TX and RX channels.
    //
    ROM_SSIDMAEnable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX);

    //
    // This register write will set the SSI0 to operate in loopback mode.  Any
    // data sent on the TX output will be received on the RX input.
    //
    HWREG(SSI0_BASE + SSI_O_CR1) |= SSI_CR1_LBM;


    //****************************************************************************
    //uDMA SSI0 RX Ping
    //****************************************************************************

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

    //
    // Configure the control parameters for the primary control structure for
    // the SSIORX channel.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
                          UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                          UDMA_ARB_4);
    //
    // Set up the transfer parameters for the SSI0RX Channel
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
                           UDMA_MODE_PINGPONG,
                           (void *)(SSI0_BASE + SSI_O_DR),
                           g_ui8SSIRxPing, sizeof(g_ui8SSIRxPing));


    //****************************************************************************
    //uDMA SSI0 RX Pong
    //****************************************************************************

    //
    // Configure the control parameters for the alternate control structure for
    // the SSIORX channel.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT,
                          UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                          UDMA_ARB_4);
    //
    // Set up the transfer parameters for the SSI0RX Channel
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT,
                           UDMA_MODE_PINGPONG,
                           (void *)(SSI0_BASE + SSI_O_DR),
                           g_ui8SSIRxPong, sizeof(g_ui8SSIRxPong));

    //****************************************************************************
    //uDMA SSI0 TX Ping
    //****************************************************************************

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


    //
    // Set the USEBURST attribute for the uDMA SSI0TX channel.  This will
    // force the controller to always use a burst when transferring data from
    // the TX buffer to the SSI0.  This is somewhat more effecient bus usage
    // than the default which allows single or burst transfers.
    //
    ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST);

    //
    // Configure the control parameters for the SSI0 TX.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
                          UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                          UDMA_ARB_4);


    //
    // Set up the transfer parameters for the uDMA SSI0 TX channel.  This will
    // configure the transfer source and destination and the transfer size.
    // Basic mode is used because the peripheral is making the uDMA transfer
    // request.  The source is the TX buffer and the destination is the SSI0
    // data register.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
                           UDMA_MODE_PINGPONG, g_ui8SSITxPing,
                           (void *)(SSI0_BASE + SSI_O_DR),
                           sizeof(g_ui8SSITxPing));

    //****************************************************************************
    //uDMA SSI0 TX Pong
    //****************************************************************************

    //
    // Configure the control parameters for the SSI0 TX.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
                          UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                          UDMA_ARB_4);


    //
    // Set up the transfer parameters for the uDMA SSI0 TX channel.  This will
    // configure the transfer source and destination and the transfer size.
    // Basic mode is used because the peripheral is making the uDMA transfer
    // request.  The source is the TX buffer and the destination is the SSI0
    // data register.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT,
                           UDMA_MODE_PINGPONG, g_ui8SSITxPong,
                           (void *)(SSI0_BASE + SSI_O_DR),
                           sizeof(g_ui8SSITxPong));


    //
    // Now both the uDMA SSI0 TX and RX channels are primed to start a
    // transfer.  As soon as the channels are enabled, the peripheral will
    // issue a transfer request and the data transfers will begin.
    //
    ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);

    //
    // Enable the SSI0 DMA TX/RX interrupts.
    //
    ROM_SSIIntEnable(SSI0_BASE, SSI_DMATX | SSI_DMARX);

    //
    // Enable the SSI0 peripheral interrupts.
    //
    ROM_IntEnable(INT_SSI0);

}

void configSSI0(void)
{
    //uint32_t trashBin[1] = {0};

    // GPIO setup for SSI
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0);
    ROM_GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    ROM_GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    ROM_GPIOPinConfigure(GPIO_PA4_SSI0RX);
    ROM_GPIOPinConfigure(GPIO_PA5_SSI0TX);
    ROM_GPIOPinTypeSSI(GPIO_PORTA_BASE,GPIO_PIN_5|GPIO_PIN_4|GPIO_PIN_3|GPIO_PIN_2);

    ROM_SSIConfigSetExpClk(SSI0_BASE, ROM_SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 100000, 8);
    ROM_SSIEnable(SSI0_BASE);

    /* Clear SSI0 RX Buffer */
    //while (SSIDataGetNonBlocking(SSI0_BASE, &trashBin[0])) {}

}

// main code
int main(void)
{

	ROM_FPULazyStackingEnable();

	ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

	ROM_SysCtlPeripheralClockGating(true);

    configSSI0();

    // Enable uDMA
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    ROM_IntEnable(INT_UDMAERR);
    ROM_uDMAEnable();
    ROM_uDMAControlBaseSet(ucControlTable);

    // Initialize the uDMA/SSI transfer
    InitSPITransfer();

    BIOS_start();

}

Thank you for your answers!