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/TM4C1294NCPDT: Issue with the SPI DMA Calls

Part Number: TM4C1294NCPDT

Tool/software: TI-RTOS

Hi,

I am working on SPI DMA in TI RTOS, I cant find any sample code to develop. So developed a function to work with.

I have created for ping pong mode. But the code is not working, once the SPI dma receives a data the task is terminated from its state.

I have attached you the source code.

Question:

1. Will the DMA_request call is used for pheripheral to DMA transfer or only to memory to memory transfer?

/*
 * Copyright (c) 2015, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  ======== empty.c ========
 */
/* 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/EMAC.h>
#include <ti/drivers/GPIO.h>
// #include <ti/drivers/I2C.h>
// #include <ti/drivers/SDSPI.h>
#include <ti/drivers/SPI.h>
// #include <ti/drivers/UART.h>
// #include <ti/drivers/USBMSCHFatFs.h>
// #include <ti/drivers/Watchdog.h>
// #include <ti/drivers/WiFi.h>

#include <ti/sysbios/knl/Semaphore.h>
/* Board Header file */
#include "Board.h"
#include <ti/sysbios/knl/Swi.h>
#include <xdc/runtime/Error.h>
#include <ti/sysbios/family/arm/m3/Hwi.h>

#include <stdbool.h>
#include "driverlib/sysctl.h"
#include "driverlib/ssi.h"
#include "driverlib/udma.h"
#include <inc/hw_memmap.h>
#include <inc/hw_ints.h>
#include <stdbool.h>

#define TASKSTACKSIZE   512
#define BUFFER_PAGES           2
#define BUFFER_PAGE_SZ_WORDS   	   8
#define CONTROL_WORD            0x00008043
#define SSI_O_DR				0x00000001
#define DMA_CLEAR_FLAG          0x00000400
Task_Struct task0Struct;
uint32_t DMABuffer[BUFFER_PAGES][BUFFER_PAGE_SZ_WORDS];
Char task0Stack[TASKSTACKSIZE];
bool SPI_Master;

uint8_t ActivePage;
uint8_t BgPage;
tDMAControlTable dmaControlTable;
uint32_t destEndAddress = 0x20002004;
uint32_t srcEndAddress= 0x20001004;

/*
 *  ======== heartBeatFxn ========
 *  Toggle the Board_LED0. The Task_sleep is determined by arg0 which
 *  is configured for the heartBeat Task instance.
 */

uint32_t DMAtransferCount;

void SSI0_dma_int(void)
{
  uint32_t ulMode;

  //check primary channel
  ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT);
  if(ulMode == UDMA_MODE_STOP)
  {
    // Swap active and background pages
    ActivePage = 1;
    BgPage = 0;
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), &DMABuffer[0][0], BUFFER_PAGE_SZ_WORDS);
    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    DMAtransferCount++;
  }

  //check alt channel
  ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT);
  if(ulMode == UDMA_MODE_STOP) {
    // Swap active and background pages
    ActivePage = 0;
    BgPage = 1;
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), &DMABuffer[1][0], BUFFER_PAGE_SZ_WORDS);
    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    DMAtransferCount++;
  }

  System_printf(" i am in dma init\n");
   System_flush();
}

void UserCallbackFxn(SPI_Handle handle,
        						SPI_Transaction * transaction)
{

  /*
  I have a brekpoint at below printf statement,

  Immediately after initiating transfer from MASTER, control comes to this statment and stops.
  */
  System_printf(" i am in callback function\n");
  System_flush();

  GPIO_toggle(Board_LED1);

  /*
  If I enable this SSI0_dma_int(), system crashes.
  */
  SSI0_dma_int();

}



/*
Function to configure the ping pong mode and initiate DMA transfer.
*/



void Dma_Init()
{


	bool DMA_initialized = FALSE;
	dmaControlTable.pvDstEndAddr = &destEndAddress;
	dmaControlTable.pvSrcEndAddr = &srcEndAddress;
	dmaControlTable.ui32Control  = CONTROL_WORD;

	if(!DMA_initialized){

		SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

		uDMAEnable();

		uDMAControlBaseSet(&dmaControlTable);

		DMA_initialized = TRUE;
	}
}


void initDMA_control_table(void)
{
	dmaControlTable.pvDstEndAddr = &destEndAddress;
	dmaControlTable.pvSrcEndAddr = &srcEndAddress;
	dmaControlTable.ui32Control  = CONTROL_WORD;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

    uDMAEnable();

    uDMAControlBaseSet(&dmaControlTable);



    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX, UDMA_ATTR_HIGH_PRIORITY);
    //uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX, UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_ALTSELECT);

    // Primary Channel
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8);
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), &DMABuffer[0][0], BUFFER_PAGE_SZ_WORDS);

    // Alternate Channel
    uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8);
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), &DMABuffer[1][0], BUFFER_PAGE_SZ_WORDS);

    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);

}

void ssiInterrupt(void)
{
	uDMAIntClear(DMA_CLEAR_FLAG);
}
void run_time()
{
	SPI_Params params;
	SPI_Handle spiHandles;

    SPI_init();

    SPI_Params_init(&params);
    params.mode         = SPI_SLAVE;
    params.transferMode = SPI_MODE_CALLBACK;
    params.bitRate      = 5000000;
    params.transferCallbackFxn = UserCallbackFxn;

    spiHandles = SPI_open(Board_SPI0, &params);

    if (spiHandles == NULL) {
      System_abort("Error initializing SPI\n");
    }
    else {
      System_printf("SPI 0 initialized\n");
    }

    SSIEnable(SSI0_BASE);
    SSIDMAEnable(SSI0_BASE, SSI_DMA_RX);
    SSIIntEnable(SSI0_BASE, SSI_DMARX);
    uDMAIntRegister(UDMA_INT_SW, &ssiInterrupt);

    initDMA_control_table();

}

Void heartBeatFxn(UArg arg0, UArg arg1)
{
	uint8_t count = 0;
	Dma_Init();
	run_time();
    while (1) {
    	Task_sleep((unsigned int)arg0);
        GPIO_toggle(Board_LED0);
        count++;
        if(count == 5)
        {
        	uDMAChannelRequest(UDMA_CHANNEL_SSI0RX);
        }
    }
}

/*
 *  ======== main ========
 */
int main(void)
{
    Task_Params taskParams;
    /* Call board init functions */
    Board_initGeneral();
    // Board_initEMAC();
    Board_initGPIO();
    // Board_initI2C();
    // Board_initSDSPI();
    Board_initSPI();


    // Board_initUART();
    // Board_initUSB(Board_USBDEVICE);
    // Board_initUSBMSCHFatFs();
    // Board_initWatchdog();
    // Board_initWiFi();

    /* Construct heartBeat Task  thread */
    Task_Params_init(&taskParams);
    taskParams.arg0 = 1000;
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &task0Stack;
    Task_construct(&task0Struct, (Task_FuncPtr)heartBeatFxn, &taskParams, NULL);

     /* Turn on user LED */
    GPIO_write(Board_LED0, Board_LED_ON);

    System_printf("Starting the example\nSystem provider is set to SysMin. "
                  "Halt the target to view any SysMin contents in ROV.\n");
    /* SysMin will only print to the console when you call flush or exit */
    System_flush();

    /* Start BIOS */
    BIOS_start();

    return (0);
}

Regards,

Manohar.

  • Hello Manohar,

    The uDMAChannelRequest call can be used either for memory to memory transfer, or for software based transfers. For a software based transfer, you need to use UDMA_CHANNEL_SW.

    You can see an example which uses software based transfer that is non-RTOS for general understanding in the TivaWare examples, project name 'udma_demo'.