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.

How to determine DMA end of transmit & end of receive interrupts

Other Parts Discussed in Thread: TM4C129ENCPDT

How can i check, which DMA channel is triggered interrupt? I'm using UART3 with DMA for both Rx and Tx, and both of them causes one common interrupt.

I'm using DMA in basic mode - setting up receive and transmit buffers, enabling Rx & Tx, and then, if Rx event occurs - I disable DMA Rx channel interrupt. That's why I can't use uDMAChannelIsEnabled() function for determining, which channel caused interrupt, because both condition checks are passing.

I tried to use uDMAIntStatus() function, and it returns 0x00020000 for UART3RX, and 0x00030000 for UART3TX. Is there way to properly compare returned value of uDMAIntStatus() with channel address? I also planning to use UART0, SSI0, SSI2 and I2C5 with DMA, so I need to know, how to determine dependency between uDMAIntStatus() and channel address.


Here is my code:

Init:

	MAP_IntMasterEnable();
		
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
	MAP_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
		
	MAP_uDMAEnable();
	MAP_uDMAControlBaseSet(pui8ControlTable);

	//UART3 config
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
	
	MAP_GPIOPinConfigure(GPIO_PJ0_U3RX);
	MAP_GPIOPinConfigure(GPIO_PJ1_U3TX);
	
	MAP_GPIOPinTypeUART(GPIO_PORTJ_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
	MAP_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART3);
	MAP_UARTConfigSetExpClk(UART3_BASE, sysClock, speed, UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE);
	
	MAP_UARTFIFOLevelSet(UART3_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
	
	MAP_UARTEnable(UART3_BASE);
	
	//DMA config
	
	MAP_uDMAChannelAssign(UDMA_CH16_UART3RX);
	MAP_uDMAChannelAssign(UDMA_CH17_UART3TX);
	
	MAP_UARTDMAEnable(UART3_BASE, UART_DMA_RX | UART_DMA_TX);
	MAP_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART3RX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
	MAP_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART3TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
	
	MAP_uDMAChannelControlSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1);
	MAP_uDMAChannelControlSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_1);
	
	MAP_uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(UART3_BASE + UART_O_DR), rxBuffer, sizeof(rxBuffer));	
	MAP_uDMAChannelTransferSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, txBuffer, (void *)(UART3_BASE + UART_O_DR), sizeof(txBuffer));
	
	MAP_uDMAChannelEnable(UDMA_CHANNEL_UART3RX);
	//MAP_uDMAChannelEnable(UDMA_CHANNEL_UART3TX);
	
	MAP_UARTIntEnable(UART3_BASE, UART_INT_DMARX /*| UART_INT_DMATX*/);
	
	MAP_IntEnable(INT_UART3);

For DMA receive:

void UART3DMAReceive(uint8_t* rxBuffer, uint32_t size)
{
	u3DMARxComplete = 0;
	memcpy(uart3RxBuff, rxBuffer, size);
	uart3RxBuffLen = size;
	
	MAP_uDMAChannelTransferSet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(UART3_BASE + UART_O_DR), uart3RxBuff, uart3RxBuffLen);
	MAP_UARTDMAEnable(UART3_BASE, UART_DMA_RX);
	MAP_uDMAChannelEnable(UDMA_CHANNEL_UART3RX);
	MAP_UARTIntEnable(UART3_BASE, UART_INT_DMARX);
	
	//TODO
}

For DMA transmit:

int8_t UART3DMASend(uint8_t* txBuffer, uint32_t size)
{
	u3DMATxComplete = 0;
	
	MAP_uDMAChannelTransferSet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, txBuffer, (void *)(UART3_BASE + UART_O_DR), size);
	MAP_uDMAChannelEnable(UDMA_CHANNEL_UART3TX);
	MAP_UARTIntEnable(UART3_BASE, UART_INT_DMATX);
	
	//TODO
	return -1;
}

ISR, based on sample, that doesn't work properly:

void UART3IntHandler(void)
{
	uint32_t status;
	uint32_t mode;
	uint32_t channel;
	
	status = MAP_UARTIntStatus(UART3_BASE, true);
	MAP_UARTIntClear(UART3_BASE, status);
	
	mode = MAP_uDMAChannelModeGet(UDMA_CHANNEL_UART3RX | UDMA_PRI_SELECT);
	
	channel = MAP_uDMAIntStatus();
	
	if (mode == UDMA_MODE_STOP && MAP_uDMAChannelIsEnabled(UDMA_CHANNEL_UART3RX))
	{
		u3DMARxComplete = 1;
		MAP_UARTIntDisable(UART3_BASE, UART_INT_DMARX);
		MAP_uDMAChannelDisable(UDMA_CHANNEL_UART3RX);
		MAP_UARTDMADisable(UART3_BASE, UART_DMA_RX);
	}
	
	mode = MAP_uDMAChannelModeGet(UDMA_CHANNEL_UART3TX | UDMA_PRI_SELECT);
	
	if (mode == UDMA_MODE_STOP && (!MAP_uDMAChannelIsEnabled(UDMA_CHANNEL_UART3TX)))
	{
		u3DMATxComplete = 1;
		MAP_UARTIntDisable(UART3_BASE, UART_INT_DMATX);
		//MAP_uDMAChannelDisable(UDMA_CHANNEL_UART3TX);
		MAP_UARTDMADisable(UART3_BASE, UART_DMA_TX);
	}

}

I tried to use this comparison, but it doesn't work properly too (UDMA_CH17_UART3TX is 0x00020011 and UDMA_CH16_UART3RX is 0x00020010, but channel is 0x00020000 for DMA Rx complete interrupt, and 0x00030000 for DMA Tx complete interrupt):

if (channel & (1 << (UDMA_CH16_UART3RX & 0x1f)))

if (channel == (1 << (UDMA_CH17_UART3TX  & 0x1f)))

UPD: My MCU is TM4C129ENCPDT, where is no DMACHIS register, according to documntation, but looks like MAP_uDMAIntStatus() works.

  • My MCU is TM4C129ENCPDT, where is no DMACHIS register, according to documntation, but looks like MAP_uDMAIntStatus() works.
  • Hello 12345685,

    In TM4C129x devices the DMA completion is mapped via the requesting peripherals DMADONE interrupt bit. You need to set the DMADONE interrupt mask in the peripheral address for the interrupt generation and can use the MIS register of the peripheral to read the interrupt status.

    Regards
    Amit
  • Amit Ashara,

    thank you for solution!

    Now it's work fine.

    Here my updated ISR code:

    void UART3IntHandler(void)
    {
    	uint32_t status;
    	
    	status = MAP_UARTIntStatus(UART3_BASE, true);
    	if ((status & UART_MIS_DMATXMIS) == UART_MIS_DMATXMIS)
    	{
    		//DMA TX interrupt occured
    		__nop();
    		
    		u3DMATxComplete = 1;
    		
    		//TODO
    				
    		MAP_UARTIntDisable(UART3_BASE, UART_INT_DMATX);
    		MAP_uDMAChannelDisable(UDMA_CHANNEL_UART3TX);
    		MAP_UARTDMADisable(UART3_BASE, UART_DMA_TX);
    	}
    	
    	if ((status & UART_MIS_DMARXMIS) == UART_MIS_DMARXMIS)
    	{
    		//DMA RX interrupt occured
    		__nop();
    		
    		u3DMARxComplete = 1;
    				
    		//TODO
    		
    		MAP_UARTIntDisable(UART3_BASE, UART_INT_DMARX);
    		MAP_uDMAChannelDisable(UDMA_CHANNEL_UART3RX);
    		MAP_UARTDMADisable(UART3_BASE, UART_DMA_RX);
    	}
    	
    	MAP_UARTIntClear(UART3_BASE, status);
    }

  • Hello 12345685

    That was the fastest uDMA bring up on the forum, that I know of. Good work...

    Regards
    Amit