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.

Why do I see four interrupts here?

Hi there,

I am using SSI/DMA for the first time and had some questions. I enabled two interrupts, RX/TX, so I expect two, but I saw four instead (No, it will not affect any operation):

Two before the end of the transfer, which is marked by X, two after

Could anyone be so kind to give me some pointers? Thanks!

Here is my SSI configuration:

#include "def.h"
#include "globalvar.h"

#define XFERSIZE 1024


//*****************************************************************************
//
// SSI0 Interrupt Handler
//
//*****************************************************************************
void
SSI0IntHandler(void)
{
uint32_t ui32Status;
uint32_t ui32Mode;
int ui16Idx;
ui32Status = SSIIntStatus(SSI0_BASE, 1);
SSIIntClear(SSI0_BASE, ui32Status);

GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT);
if(ui32Mode == UDMA_MODE_STOP)
{
uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
UDMA_MODE_BASIC,
(void *)(SSI0_BASE + SSI_O_DR),
g_ui8SSIRxBuf, XFERSIZE);

uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
}

if(!uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0TX))
{
uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
UDMA_MODE_BASIC, g_ui8SSITxBuf,
(void *)(SSI0_BASE + SSI_O_DR),
XFERSIZE);
uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
}
}

void ConfigureSSI0(void)
{
uint32_t trashBin[1] = {0};
//
// Enable the SSI0 Peripheral.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0);
//
// Configure GPIOA_3 as the SSI Chip Select
//
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_PIN_3);
//
// Configure GPIO Pins for SSI0 mode.
//
GPIOPinConfigure(GPIO_PA2_SSI0CLK);
GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);
SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_3,
SSI_MODE_MASTER, 12000000, 8);
SSIEnable(SSI0_BASE);
/* Clear SSI0 RX Buffer */
while (SSIDataGetNonBlocking(SSI0_BASE, &trashBin[0])) {}
}

void InitSPITransfer(void)
{
uint_fast16_t ui16Idx;
//
// Fill the TX buffer with a simple data pattern, and erase RX buffer
//
for(ui16Idx = 0; ui16Idx < SSI_BUFFER_SIZE; ui16Idx++)
{
g_ui8SSITxBuf[ui16Idx] = ui16Idx;

g_ui8SSIRxBuf[ui16Idx] = 0;
}
//
// Enable the uDMA interface for both TX and RX channels.
//
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(SSI1_BASE + SSI_O_CR1) |= SSI_CR1_LBM;
//****************************************************************************
//uDMA SSI0 RX
//****************************************************************************
//
// Put the attributes in a known state for the uDMA SSI0RX channel. These
// should already be disabled by default.
//
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.
//
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
//
uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
UDMA_MODE_BASIC,
(void *)(SSI0_BASE + SSI_O_DR),
g_ui8SSIRxBuf, XFERSIZE);
//****************************************************************************
//uDMA SSI0 TX
//****************************************************************************
//
// Put the attributes in a known state for the uDMA SSI0TX channel. These
// should already be disabled by default.
//
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.
//
uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST);
//
// Configure the control parameters for the SSI0 TX.
//
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 theUART0
// data register.
//
uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
UDMA_MODE_BASIC, g_ui8SSITxBuf,
(void *)(SSI0_BASE + SSI_O_DR),
XFERSIZE);
//
// 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.
//
uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
//
// Enable the SSI0 DMA TX/RX interrupts.
//
SSIIntEnable(SSI0_BASE, SSI_DMATX | SSI_DMARX);
//
// Enable the SSI0 peripheral interrupts.
//
IntEnable(INT_SSI0);
}

  • Hello David,

    I believe it to be the SSI DMA DONE firing multiple times when done, till it is cleared by means of reenabling the channel.If you would move the SSIntClear to the last of the interrupt handler or handling the clear operation in it's if condition then it must not occur again,

    Regards
    Amit
  • Another question regarding SSI/DMA:

    If I need to stop DMA at the end of transfer automatically (one-shot), how should I config the DMA channel? I tried a few modifications to the configuration and didn't find one that worked
  • Hello David,

    You would need to disable the DMA request from the SSI. This will prevent the SSI from generating any further DMA Requests.

    Regards
    Amit
  • I tried that before (not sure if that's what you instructed though), see modified SSI0IntHandler below

    void
    SSI0IntHandler(void)
    {
    uint32_t ui32Status;
    uint32_t ui32Mode;
    int ui16Idx;

    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);

    uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);

    ui32Status = SSIIntStatus(SSI0_BASE, 1);
    SSIIntClear(SSI0_BASE, ui32Status);
    }

    Now, it interrupts at 1Mhz rate, basically drags the main to dead


    At this point, one can use disableint to pass it, but what are these interrupts ?

  • Hello David.

    I was referring to SSIDMADisable, something like the following.

    SSI0IntHandler(void)
    {
    uint32_t ui32Status;
    uint32_t ui32Mode;
    int ui16Idx;

    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);

    ui32Status = SSIIntStatus(SSI0_BASE, 1);

    if((ui32Status & SSI_MIS_DMATXMIS) == SSI_MIS_DMATXMIS )
    {
    SSIDMADisable(SSI0_BASE,SSI_DMA_TX)
    }
    if((ui32Status & SSI_MIS_DMARXMIS) == SSI_MIS_DMARXMIS )
    {
    SSIDMADisable(SSI0_BASE,SSI_DMA_RX)
    }

    SSIIntClear(SSI0_BASE, ui32Status);
    }

    Regards
    Amit
  • Hi Amit, I tried your suggestion.

    Yes, it will terminate the DMA, but when I tried to start another one-shot transfer, the data is totally messed up (the Tx and Rx are shorted in the experiment). Could you be so kind to point out my problem?

    main()
    ...

    while(1)
    {
    if (iTemp<500){ //This gives me enough time to operate the logic analyzer and write down notes
    Delay10ms(1);
    iTemp++;
    }
    else{
    iTemp=0;
    uint_fast16_t ui16Idx;
    UARTprintf("\r\nFlag=");
    DisplayInt(g_Flag);
    UARTprintf(" ");
    for (ui16Idx=0; ui16Idx<256; ui16Idx++){
    UARTprintf(" ");
    DisplayInt(g_ui8SSIRxBuf[ui16Idx]);
    }
    InitSPITransfer();
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
    }
    }
    }

    SSI0IntHandler(void)
    {
    uint32_t ui32Status;
    uint32_t ui32Mode;
    int ui16Idx;

    g_Flag=ui32Status = SSIIntStatus(SSI0_BASE, 1);
    if ((ui32Status&SSI_MIS_DMARXMIS)==SSI_MIS_DMARXMIS){
    //Rx finished
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);

    SSIDMADisable(SSI0_BASE, SSI_DMA_RX);
    }
    if ((ui32Status&SSI_MIS_DMATXMIS)==SSI_MIS_DMATXMIS){
    //Tx finished
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
    SSIDMADisable(SSI0_BASE, SSI_DMA_TX);
    }

    SSIIntClear(SSI0_BASE, ui32Status);
    }

    void InitSPITransfer(void)
    {
    uint_fast16_t ui16Idx;
    //
    // Fill the TX buffer with a simple data pattern, and erase RX buffer
    //
    for(ui16Idx = 0; ui16Idx < SSI_BUFFER_SIZE; ui16Idx++)
    {
    g_ui8SSITxBuf[ui16Idx] = ui16Idx&0xff;

    g_ui8SSIRxBuf[ui16Idx] = 0;
    }
    //
    // Enable the uDMA interface for both TX and RX channels.
    //
    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(SSI1_BASE + SSI_O_CR1) |= SSI_CR1_LBM;
    //****************************************************************************
    //uDMA SSI0 RX
    //****************************************************************************
    //
    // Put the attributes in a known state for the uDMA SSI0RX channel. These
    // should already be disabled by default.
    //
    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.
    //
    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
    //
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC,
    (void *)(SSI0_BASE + SSI_O_DR),
    (void *)g_ui8SSIRxBuf, XFERSIZE);
    //****************************************************************************
    //uDMA SSI0 TX
    //****************************************************************************
    //
    // Put the attributes in a known state for the uDMA SSI0TX channel. These
    // should already be disabled by default.
    //
    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.
    //
    uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST);
    //
    // Configure the control parameters for the SSI0 TX.
    //
    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 theUART0
    // data register.
    //
    uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC, (void *) g_ui8SSITxBuf,
    (void *)(SSI0_BASE + SSI_O_DR),
    XFERSIZE);


    //
    // 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.
    //
    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
    //
    // Enable the SSI0 DMA TX/RX interrupts.
    //
    SSIIntClear(SSI0_BASE, SSIIntStatus(SSI0_BASE, 1));
    SSIIntEnable(SSI0_BASE, SSI_DMATX | SSI_DMARX);
    //
    // Enable the SSI0 peripheral interrupts.
    //
    IntEnable(INT_SSI0);
    }

    From the logic analyzer, I see the the interrupts can occur in the middle of a transfer and in the middle of no transfer, meaning no SSI clock nor data around the event at all

    The print out of data are shown below: where the first one (Flag=48) is when the interrupt occurs when there is no SSI clock nor data around at all, and the second one is when the interrupt occurs in the middle of a transfer and it has data misalignment (see the first 0...7 then start over again)

    Flag=48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

    Flag=16 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247

  • Hello David,

    Can you share the entirety of the uDMA and SSI Configuration Code. There is uDMA Initialization, system clock configuration and variable declaration that is missing for me to reproduce the issue and pin-point the root cause?

    Regards
    Amit
  • Thanks Amit, please allow me to clean up the project and make it smaller and more readable before showing you
  • Hello David,

    Sure. Also do check if the behavior is still reproducible

    Regards
    Amit
  • Hi Amit,


    I cleaned up the project, and the problem is still reproducible, just short PA4 and PA5 to connect the Tx and Rx of SSI and run the project on TiVa 1294 launchpad and you will see the first transfer works but the following are either all zero, or misaligned. If you use a logic analyzer, you will see the interrupt happens in middle of a transfer or in an area that no transfer around at all.


    Your time is greatly appreciated.

    ssi_dma.zip

  • Hello David,

    As I mentioned earlier. The issue was with the manner in which SSIDMAEnable function call is happening. I had to fix other parts of the code as well since GPIO Port A and N were not enabled before the function call was made to configure the GPIO's of Port A and N (I always use system reset when restarting a code).

    Attached file fixes it. Now I get 2 interrupts for every DMA Transfer.

    #include <stdbool.h>
    #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/flash.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/ssi.h"
    
    #include "utils/locator.h"
    #include "utils/lwiplib.h"
    #include "utils/ustdlib.h"
    #include "utils/uartstdio.h"
    #include "httpserver_raw/httpd.h"
    #include "drivers/pinout.h"
    #include "driverlib/timer.h"
    #include "driverlib/pwm.h"
    
    #include "driverlib/udma.h"
    
    #include "driverlib/adc.h"
    #include "inc/hw_adc.h"
    
    #include "globalvar.h"
    
    //#define XFERSIZE 256
    #define XFERSIZE sizeof(g_ui8SSITxBuf)  //1024
    
    
    //*****************************************************************************
    //
    // SSI0 Interrupt Handler
    //
    //*****************************************************************************
    void
    SSI0IntHandler(void)
    {
        uint32_t ui32Status;
        uint32_t ui32Mode;
        int ui16Idx;
    
        g_Flag=ui32Status = SSIIntStatus(SSI0_BASE, 1);
        if ((ui32Status&SSI_MIS_DMARXMIS)==SSI_MIS_DMARXMIS){
        	//Rx finished
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
        	GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
    
        	SSIDMADisable(SSI0_BASE, SSI_DMA_RX);
        }
        if ((ui32Status&SSI_MIS_DMATXMIS)==SSI_MIS_DMATXMIS){
        	//Tx finished
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
        	GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
        	GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 2);
            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0);
        	SSIDMADisable(SSI0_BASE, SSI_DMA_TX);
        }
    
    
    	SSIIntClear(SSI0_BASE, ui32Status);
    
    }
    
    void ConfigureSSI0(void)
    {
        uint32_t trashBin[1] = {0};
        //
        // Enable the SSI0 Peripheral.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
        SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0);
        //
        // Configure GPIOA_3 as the SSI Chip Select
        //
        GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
        GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_PIN_3);
        //
        // Configure GPIO Pins for SSI0 mode.
        //
        GPIOPinConfigure(GPIO_PA2_SSI0CLK);
        GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
        GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
        GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);
        SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_3,
                SSI_MODE_MASTER, 1000000, 8);
        SSIEnable(SSI0_BASE);
        /* Clear SSI0 RX Buffer */
        while (SSIDataGetNonBlocking(SSI0_BASE, &trashBin[0])) {}
    }
    
    void InitSPITransfer(void)
    {
        uint_fast16_t ui16Idx;
        //
        // Fill the TX buffer with a simple data pattern, and erase RX buffer
        //
        for(ui16Idx = 0; ui16Idx < SSI_BUFFER_SIZE; ui16Idx++)
        {
            g_ui8SSITxBuf[ui16Idx] = ui16Idx&0xff;
    
            g_ui8SSIRxBuf[ui16Idx] = 0;
        }
    
        //
        // 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(SSI1_BASE + SSI_O_CR1) |= SSI_CR1_LBM;
        //****************************************************************************
        //uDMA SSI0 RX
        //****************************************************************************
        //
        // Put the attributes in a known state for the uDMA SSI0RX channel.  These
        // should already be disabled by default.
        //
        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.
        //
        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
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC,
                                   (void *)(SSI0_BASE + SSI_O_DR),
                                   (void *)g_ui8SSIRxBuf, XFERSIZE);
        //****************************************************************************
        //uDMA SSI0 TX
        //****************************************************************************
        //
        // Put the attributes in a known state for the uDMA SSI0TX channel.  These
        // should already be disabled by default.
        //
        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.
        //
        uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST);
        //
        // Configure the control parameters for the SSI0 TX.
        //
        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 theUART0
        // data register.
        //
        uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT,
                                                       UDMA_MODE_BASIC, (void *) g_ui8SSITxBuf,
                                                       (void *)(SSI0_BASE + SSI_O_DR),
                                                       XFERSIZE);
    
    
        //
        // 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.
        //
        uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
        uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
        //
        // Enable the SSI0 DMA TX/RX interrupts.
        //
        SSIIntClear(SSI0_BASE, SSIIntStatus(SSI0_BASE, 1));
        SSIIntEnable(SSI0_BASE, SSI_DMATX | SSI_DMARX);
        //
        // Enable the SSI0 peripheral interrupts.
        //
        IntEnable(INT_SSI0);
    
        //
        // Enable the uDMA interface for both TX and RX channels.
        //
        SSIDMAEnable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX);
    
    }
    

    Regards

    Amit

  • Thank you very much!
  • Hi Amit,

    I compared your codes with dma_demo project for TiVa, and found this:

    In dma_demo, which uses DMA/UART,

    UARTDMAEnable(UART1_BASE, UART_DMA_RX | UART_DMA_TX)

    is called way before

    ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1RX);
    ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1TX);

    so I assume one has to enable the engine before using it, and that was what my first try was based on. Yet the approach failed.

    In your modification, you reversed the order, SSIDMAEnable is called immediately after the ChannelEnable,

    uDMAChannelEnable(UDMA_CHANNEL_SSI0RX);
    uDMAChannelEnable(UDMA_CHANNEL_SSI0TX);
    SSIDMAEnable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX);

    Is your modification a work-around for a SSI/DMA design bug? If so, any timing constraint? or the UART/DMA example from TI was actually wrong?

    ps. Port A and N are configured in main().

  • Hello David,

    This is the manner in which the SSI Module was designed. From a system perspective it was not the correct manner in which the SSI and DMA interaction would work. Though not a bug it is a quirk of the device. Very similar to the same is SSI#07 Errata which shows the interrupt behaves in the same manner.,

    Regards
    Amit
  • Thanks for the info!

    Anywhere I can find the documentation regarding this odd behavior?

    I don't recall seeing such info anywhere, and errata didn't mention it either

  • Hello David,

    Yes. In the QSSI Chapter, under DMA Operation.

    "If the μDMA is enabled and has completed a data transfer from the Tx FIFO, the DMATXRIS bit is
    set in the SSIRIS register and cannot be cleared by setting the DMATXIC bit in the SSI Interrupt
    Clear (SSIICR) register. In the DMA Completion Interrupt Service Routine, software must disable
    the μDMA transmit enable to the SSI by clearing the TXDMAE bit in the QSSI DMA Control
    (SSIDMACTL) register and then setting the DMATXIC bit in the SSIICR register. This clears the
    DMA completion interrupt. When the μDMA is needed to transmit more data, the TXDMAE bit must
    be set (enabled) again."

    Regards
    Amit