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.

DMA Interrupt goes off before DMA transfer began

I made a similar question in another thread but I thought this deserves it's own. I hope I don't anger anyone by doing this. 

My goal is to make an external source initiate DMA SPI transfer without waking the MCU up. I am using MSP432 black launchpad(soon red).

I connected my P2.6 GPIO to P7.0 DMAE0 and this is how I want it to work:

I configure the SPI and I enable it. Then I assign channel 0 source to be EUSCIB0_TX and I assign channel 6 source to be EXTERNAL_PIN.
Now I clear the SPI_TX_INTERRUPT flag so my channel 0 won't initate trasnfer as soon as I enable the channel. For both channels the destination is the SPI_TX_BUFFER. And I just tell channel 6 to write 1 byte to TX_BUFFER and when that gets sent the SPI triggers SPI_TX_INTERRUPT which initiates the channel 0 transfer. After that transef completes I want a interrupt to happen to tell me that the transfer completed.
So after I configured the transfers, I enable the interrupt and enable the channel. Now I put high on P2.6(P7.0) and thats the whole application.

The problem is that as soon as I enable the interrupt it occurs even though no transfer happened and I didn't even put high on P2.6. In the documentation it says that the interrupt happens after the DMA completes the transfer. Even if the SPI triggers the DMA interrupt, I cleared the SP_TX_BUFFER and I cleared the DMA_INTERRUPT flag. Here is the code:

//*****************************************************************************
//
// MSP432 main.c 
//
//****************************************************************************

#include "driverlib.h"
#include "IQmathLib.h"

#pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024)
static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32];

void InitMCU();

void main(void)
{
	InitMCU();

	uint8_t buffer = 0x55;

	// Clear interrupt status
	SPI_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT);

	// Activate DMA SPI transfer with external pin
	DMA_setChannelControl(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,
	UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);
	DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,
			UDMA_MODE_BASIC,
			&buffer,
			(void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),
			1);

	// Setup the TX transfer characteristics & buffers
	DMA_setChannelControl(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,
	UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
	DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,
			UDMA_MODE_BASIC,
			&buffer,
			(void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),
			1);

	MAP_DMA_clearInterruptFlag(0);
	MAP_DMA_enableInterrupt(INT_DMA_INT1);
	// Assigning/Enabling Interrupts
	MAP_Interrupt_enableInterrupt(INT_DMA_INT1);

	MAP_DMA_enableChannel(0);
	MAP_DMA_enableChannel(6);

	GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6);

	while(1);
}

// DMA INT1 ISR
void DMA_INT1_IRQHandler(void)
{
	return;
}

// SPI Master Configuration Parameter for CC1200
const eUSCI_SPI_MasterConfig spiMasterConfig =
{
	EUSCI_B_SPI_CLOCKSOURCE_SMCLK,				// SMCLK Clock Source
	6000000,									// SMCLK = HFXT/8 = 6MHz
	6000000,									// SPICLK = 6MHz
	EUSCI_B_SPI_MSB_FIRST,						// MSB First
	EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT,    // Phase
	EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW,	// Low polarity
	EUSCI_B_SPI_3PIN							// 3Wire SPI Mode
};

// Initialize the MCU
void InitMCU()
{
	// Halting the Watchdog
	WDT_A_holdTimer();

	// Enabling MASTER interrupts
	Interrupt_disableMaster();

	// Set power state of MCU
	PCM_setPowerState(PCM_AM_LDO_VCORE1);

	// Configuring pins for peripheral/crystal usage and LED for output
	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
			GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION);

	// Just in case the user wants to use the getACLK, getMCLK, etc. functions,
	// let's set the clock frequency in the code
	CS_setExternalClockSourceFrequency(32000,48000000);

	// Starting HFXT in non-bypass mode without a timeout. Before we start
	// we have to change VCORE to 1 to support the 48MHz frequency
	//PCM_setCoreVoltageLevel(PCM_VCORE1);
	FlashCtl_setWaitState(FLASH_BANK0, 2);
	FlashCtl_setWaitState(FLASH_BANK1, 2);
	CS_startHFXT(false);

	// Initializing MCLK to HFXT (effectively 48MHz)
	CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);

	// Initializing SMCLK to HFXT (effectively 6MHz)
	CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_8);

	// Selecting pins P1.5, P1.6 and P1.7 in SPI mode
	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
			GPIO_PIN7 | GPIO_PIN6 | GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION);

	GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6);
	GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);

	// Selecting pin 7.0 in DMAE0
	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0, GPIO_PRIMARY_MODULE_FUNCTION);

	// Configuring SPI in 3wire master mode for CC1200
	SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);

	// Enable SPI module for CC1200
	SPI_enableModule(EUSCI_B0_BASE);

	// Configuring DMA module
	DMA_enableModule();
	DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);

	// Assign DMA channel 0 to EUSCI_B0_TX0, channel 1 to EUSCI_B0_RX0
	DMA_assignChannel(DMA_CH0_EUSCIB0TX0);
	DMA_assignChannel(DMA_CH6_EXTERNALPIN);

	// Enable DMA interrupt
	MAP_DMA_assignInterrupt(INT_DMA_INT1, 0);
	MAP_DMA_disableInterrupt(INT_DMA_INT1);
	MAP_DMA_clearInterruptFlag(0);

	// Enabling MASTER interrupts
	Interrupt_enableMaster();
}

  • I'm pretty sure this is an artifact of erratum DMA12, which according to SLAZ610G is fixed in the production chip (Red Launchpad).

    Observed behavior is that the INT0 flag for the channel is set as soon as SRCCFG is assigned (non-zero), even if the channel isn't enabled. The workaround is to set SRCCFG as the last thing you do with the channel -- even after the ENABLESET -- and then clear (=0) it as the first thing after detecting completion.

    There may be more to it. In my application, I was polling the interrupt bit rather than using a proper ISR, and I eventually switched to a different completion check.

    I suspect the real workaround is to switch to the Red Launchpad.
  • Jasaleja,

    As Bruce above said, as well leaning towards this being an artifact of the DMA12 Errata. You can find the errata here: www.ti.com/.../slaz610

    When do you get the red launchpad? I have tried your code on the red launchpad here and I can not recreate the issue. It works as you've described. If possible, can you try it on the red launchpad and let us know what you find?
  • I have looked into the problem a lot today and I found out that this modified code now doesn't work for more then one while loop. The first time everything works fine, but then it gets buggy. As soon as I call DMA_enableInterrupt and the DMA isn't enabled, the application doesn't work.

    While snooping for the problem which is probably the one from the Errata i found another thing that should be mentioned.

    The function DMA_assignInterrupt assigns the interrupt and it enables it. This is not written in any documentation and the examples don't hint this. 


    Because of this my application didn't work till I removed assignInterrupt(luckly the default register value is what I need). 

    I know that the code doesn't work because the global counters are not equal.

    //*****************************************************************************
    //
    // MSP432 main.c template - Empty main
    //
    //****************************************************************************
    
    #include "driverlib.h"
    #include "IQmathLib.h"
    
    #pragma DATA_ALIGN(MSP_EXP432P401RLP_DMAControlTable, 1024)
    static DMA_ControlTable MSP_EXP432P401RLP_DMAControlTable[32];
    
    void InitMCU();
    
    uint8_t flag;
    uint32_t counterMain;
    uint32_t counterIsr;
    
    void main(void)
    {
    	InitMCU();
    
    	uint8_t buffer = 0x55;
    
    	flag = 1;
    
    	while(1)
    	{
    		if(flag)
    		{
    			// Clear interrupt status
    			SPI_clearInterruptFlag(EUSCI_B0_BASE, EUSCI_B_SPI_TRANSMIT_INTERRUPT);
    
    			// Activate DMA SPI transfer with external pin
    			DMA_setChannelControl(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,
    			UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1);
    			DMA_setChannelTransfer(DMA_CH6_EXTERNALPIN | UDMA_PRI_SELECT,
    					UDMA_MODE_BASIC,
    					&buffer,
    					(void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),
    					1);
    
    			// Setup the TX transfer characteristics & buffers
    			DMA_setChannelControl(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,
    			UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
    			DMA_setChannelTransfer(DMA_CH0_EUSCIB0TX0 | UDMA_PRI_SELECT,
    					UDMA_MODE_BASIC,
    					&buffer,
    					(void *) SPI_getTransmitBufferAddressForDMA(EUSCI_B0_BASE),
    					3);
    
    
    
    			MAP_DMA_enableChannel(0);
    			MAP_DMA_enableChannel(6);
    
    			//MAP_DMA_assignInterrupt(INT_DMA_INT1, 0);
    			//DMA_Channel->INT1_SRCCFG = (DMA_Channel->INT1_SRCCFG & ~DMA_INT1_SRCCFG_INT_SRC_MASK) | channel;
    			MAP_DMA_clearInterruptFlag(0);
    			MAP_DMA_enableInterrupt(INT_DMA_INT1);
    			// Assigning/Enabling Interrupts
    			MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
    
    			flag = 0;
    
    			counterMain++;
    
    			GPIO_setOutputHighOnPin(GPIO_PORT_P2, GPIO_PIN6);
    		}
    	}
    }
    
    // DMA INT1 ISR
    void DMA_INT1_IRQHandler(void)
    {
    	MAP_DMA_disableInterrupt(INT_DMA_INT1);
    	MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
    	MAP_DMA_clearInterruptFlag(0);
    
    	GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);
    	counterIsr++;
    
    	flag = 1;
    }
    
    // SPI Master Configuration Parameter for CC1200
    const eUSCI_SPI_MasterConfig spiMasterConfig =
    {
    		EUSCI_B_SPI_CLOCKSOURCE_SMCLK,				// SMCLK Clock Source
            6000000,									// SMCLK = HFXT/8 = 6MHz
    		6000000,									// SPICLK = 6MHz
            EUSCI_B_SPI_MSB_FIRST,						// MSB First
            EUSCI_B_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT,    // Phase
            EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW,	// Low polarity
            EUSCI_B_SPI_3PIN							// 3Wire SPI Mode
    };
    
    // Initialize the MCU
    void InitMCU()
    {
    	// Halting the Watchdog
    	WDT_A_holdTimer();
    
    	// Enabling MASTER interrupts
    	Interrupt_disableMaster();
    
    	// Set power state of MCU
    	PCM_setPowerState(PCM_AM_LDO_VCORE1);
    
    	// Configuring pins for peripheral/crystal usage and LED for output
    	GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
    			GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION);
    
    	// Just in case the user wants to use the getACLK, getMCLK, etc. functions,
    	// let's set the clock frequency in the code
    	CS_setExternalClockSourceFrequency(32000,48000000);
    
    	// Starting HFXT in non-bypass mode without a timeout. Before we start
    	// we have to change VCORE to 1 to support the 48MHz frequency
    	//PCM_setCoreVoltageLevel(PCM_VCORE1);
    	FlashCtl_setWaitState(FLASH_BANK0, 2);
    	FlashCtl_setWaitState(FLASH_BANK1, 2);
    	CS_startHFXT(false);
    
    	// Initializing MCLK to HFXT (effectively 48MHz)
    	CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
    
    	// Initializing SMCLK to HFXT (effectively 6MHz)
    	CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_8);
    
    	// Selecting pins P1.5, P1.6 and P1.7 in SPI mode
    	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
    			GPIO_PIN7 | GPIO_PIN6 | GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION);
    
    	GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN6);
    	GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN6);
    
    	// Selecting pin 7.0 in DMAE0
    	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN0, GPIO_PRIMARY_MODULE_FUNCTION);
    
    	// Configuring SPI in 3wire master mode for CC1200
    	SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);
    
    	// Enable SPI module for CC1200
    	SPI_enableModule(EUSCI_B0_BASE);
    
    	// Configuring DMA module
    	DMA_enableModule();
    	DMA_setControlBase(MSP_EXP432P401RLP_DMAControlTable);
    
    	// Assign DMA channel 0 to EUSCI_B0_TX0, channel 1 to EUSCI_B0_RX0
    	DMA_assignChannel(DMA_CH0_EUSCIB0TX0);
    	DMA_assignChannel(DMA_CH6_EXTERNALPIN);
    
        // Enable DMA interrupt
    	//MAP_DMA_assignInterrupt(INT_DMA_INT1, 0);
    	//MAP_DMA_enableInterrupt(INT_DMA_INT1);
        MAP_DMA_disableInterrupt(INT_DMA_INT1);
        MAP_DMA_clearInterruptFlag(0);
    
        // Enabling MASTER interrupts
    	Interrupt_enableMaster();
    }
    

     

  • Jaselaja,

    A quick note. We will look into this for you, but a quick heads up, with the holidays in the US, a number of our experts are on holiday right now, so there might be a small delay before I can find the appropriate person to address this concern. Please try this on the rev C red launchpad as well. When will you be receiving this launchpad?
  • It is not up to me, it is up to my boss and he is delaying the order. I hope in about two weeks. I am sure the problem lies in the black launchpad. Just please look into the thing I mentioned with the documentation. Thanks for the heads up.
  • Will do. I'll keep a heads up on this thread and let you know what I find. Let me know what you see with the red launchpad!
  • Hi Jaselaja,

    I've just run into this same set of problems.

    I agree, some documentation about DMA_assignInterrupt() unexpectedly calling DMA_enableInterrupt() would be useful.
    Changing the examples to at least comment this behvaiour (if not remove the redundant DMA_enableInterrupt() call) would be great.

    The examples also like to call DMA_clearInterruptFlag() regardless of the DMA interrupt used, but this can cause trouble because it clears the interrupt flags for DMA_INT0 if you happen to be using it.  There are no flags for DMA_INT1/2/3 so if you are using these, no need to call DMA_clearInterruptFlag().

    Changing to the red Launchpad (or RevC MSP432 parts) does seem to have solved the DMA interrupt problem for me.

    Cheers
    Julian

  • I am glad we found the source of the problem. It isn't such a big deal because everyone will either switch to red or just buy the MCU and work on it directly.

    The only thing that now needs to be done is to correct the documentation or the source code. I for example would rather like to throw the enable out of the assign function.
  • Jaselaja & Julian,

    I have filed an instance for us to clarify this in documentation. Glad that you have been able to resolve it. Moving forward we recommend that everyone use the red LaunchPad (Rev C and above). Thanks for your patience and help!!

**Attention** This is a public forum