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.

TIVA - Interrupt on Transmit DMA transfer complete

Hi all,

I'm using the SSI0 like SPI Slave port with uDMA in order to have an SPI channel.

I'm not able to have an interrupt after the DMA Trasfer is completed, could you help me with the DMA and SSI0 register settings?

Regards

  • Hi,

        Provide more info on your setup, and post your code. 

             Information to provide when asking for help

    -kel

  • Markel,

    yesterday we were able to fix the problem with the IRQ, was our mistake on register settings of the TM4C1231H6PGEI.

    Now seem that we have another problem with the bit BSY on the status register SSISR. This bit (BSY) stays all the time to 0, also when we are transmitting data.

    I've attached an example code that we have developed in order to test the SSI0 port cin SPI Slave mode with uDMA.

    Thanks for your support

    FE

    //*****************************************************************************
    //
    // timers.c - Timers example.
    //
    // Copyright (c) 2011-2012 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 9453 of the EK-LM4F232 Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_ssi.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/gpio.h"
    #include "driverlib/ssi.h"
    #include "driverlib/rom.h"
    #include "driverlib/udma.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Timer (timers)</h1>
    //!
    //! This example application demonstrates the use of the timers to generate
    //! periodic interrupts.  One timer is set up to interrupt once per second and
    //! the other to interrupt twice per second; each interrupt handler will toggle
    //! its own indicator on the display.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Flags that contain the current value of the interrupt indicator as displayed
    // on the CSTN display.
    //
    //*****************************************************************************
    unsigned long g_ulFlags;
    
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif
    
    #pragma DATA_ALIGN(ucControlTable, 1024)
    unsigned char ucControlTable[512];
    
    static unsigned long uDMAErrCount = 0;
    
    static volatile unsigned long RxBufCount = 0;
    
    static char data[50];
    
    static char SomTxBuf[] = { 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x57,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E } ;
    
    void SSI0IntHandler(void);
    
    void SSI0IntHandler(void)
    {
    	volatile unsigned long i;
    	unsigned long v;
        v = ROM_uDMAIntStatus();
        ROM_uDMAIntClear(v);
        if((v&(1<<UDMA_CHANNEL_SSI0RX))!=0)
        {
    //		ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);
    		for(i=0;i<100;i++);
    	    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(SSI0_BASE + SSI_O_DR), data, 15);
    	    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, SomTxBuf, (void *)(SSI0_BASE + SSI_O_DR), 10);
    	    ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    	    ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
    //		ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);
        }
    }
    
    void uDMAErrorHandler(void);
    void uDMAErrorHandler(void)
    {
        unsigned long ulStatus;
    
        //
        // Check for uDMA error bit
        //
        ulStatus = ROM_uDMAErrorStatusGet();
    
        //
        // If there is a uDMA error, then clear the error and increment
        // the error counter.
        //
        if(ulStatus)
        {
        	ROM_uDMAErrorStatusClear();
            uDMAErrCount++;
        }
    }
    
    //*****************************************************************************
    //
    // This example application demonstrates the use of the timers to generate
    // periodic interrupts.
    //
    //*****************************************************************************
    int
    main(void)
    {
    	volatile int i;
    	uint32_t	d;
    
        //
        // Set the clocking to run directly from the crystal.
        //
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN);
    
    
        //
        // Enable processor interrupts.
        //
        ROM_IntMasterEnable();
    
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
        ROM_GPIOPinConfigure(GPIO_PA2_SSI0CLK);
        ROM_GPIOPinConfigure(GPIO_PA5_SSI0TX);
        ROM_GPIOPinConfigure(GPIO_PA4_SSI0RX);
        ROM_GPIOPinConfigure(GPIO_PA3_SSI0FSS);
        ROM_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
        ROM_SSIConfigSetExpClk(SSI0_BASE, 24576000UL, SSI_FRF_MOTO_MODE_3, SSI_MODE_SLAVE, 4096000, 8);
    
        while(ROM_SSIDataGetNonBlocking(SSI0_BASE, &d));
    
        ROM_SSIEnable(SSI0_BASE);
    
    #if 1
        // Enable the uDMA controller.
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        // Enable the uDMA controller error interrupt.  This interrupt will occur
        // if there is a bus error during a transfer.
        ROM_IntEnable(INT_UDMAERR);
    
        ROM_uDMAEnable();
        ROM_uDMAControlBaseSet(ucControlTable);
        ROM_SSIDMAEnable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX);
        ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
        ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX, UDMA_ATTR_USEBURST);
        ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);
        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(SSI0_BASE + SSI_O_DR), data, 15);
    
        ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
        ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST);
        ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);
        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, SomTxBuf, (void *)(SSI0_BASE + SSI_O_DR), 10);
    
        ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
        ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
    #endif
    
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1);
        ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1, 0);
    
        ROM_SSIIntClear(SSI0_BASE, 0x3);
    
    //    volatile unsigned long prima, dopo;
        ROM_IntEnable(INT_SSI0);
    //    HWREG(SSI0_BASE + SSI_O_IM) = 0;
    //    prima = HWREG(SSI0_BASE + SSI_O_IM);
        ROM_SSIIntDisable(SSI0_BASE, SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR);
    //    ROM_SSIIntEnable(SSI0_BASE, SSI_RXFF | SSI_RXTO);
    
    //    HWREG(SSI0_BASE + SSI_O_IM) = ~(SSI_RXFF | SSI_RXTO);
    //    dopo = HWREG(SSI0_BASE + SSI_O_IM);
    
    
        //
        // Loop forever while the timers run.
        //
        while(1)
        {
        	ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);
        	if(ROM_SSIBusy(INT_SSI0))
        		ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);
        	else
        		ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
        	ROM_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);
        }
    }