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.