Hello!
In the attached project the eDMA Major count completion interrupt service routine gets called twice after one transfer is done.
The example simply copies the first 10 elements of sourceBuffer
to the first 10 elements of destinationBuffer using PIT CH0
trigger (every 0.5 seconds) and fires an interrupt when finished.
Every ISR run increments a counter.
After the interrupt fired the buffers and the counter are printed to the
DEBUG console.
If you just run the attached example code the eDMA ISR will be called twice,
but there was only one eDMA transfer. You can see this in terminal if you
check the debug uart output. destinationBuffer[10] to destinationBuffer[19]
are still 0xff (initial value) therefore only one complete transfer of
10 bytes was done.
If you call EDMA_ClearChannelStatusFlags twice in ISR (uncomment line 71)
the ISR will be called only once. This also happens if you add a delay after
clearing edma status flags or you can also just check if the edma
transfer is really done by calling EDMA_GetChannelStatusFlags.
It seems that only a little bit of delay needs to be added to the ISR and
it will be called only once but I think making the ISR take longer
on purpose is not a good idea (usually you keep your ISRs as short as
possible).
Why does the eDMA ISR DMA0_DMA_CH_INT_DONE_0_IRQHANDLER get called twice if I do not put any more code in it?
Kind regards,
Stefan
Solved! Go to Solution.
Hi Stefan
Add __DSB(); at the end of the interrupt handler and it will solve the problem.
This is a data synchronisation barrier which ensures that the interrupt handler is not exited from until all subsequent data changes that were made have completed.
The problem is that the DMA controller is on a bus that is clocked (usually) 4x slower than the core and, although you start the write to clear the interrupt flag, if the interrupt handler is only short, the core will already have exited from the routine and will return again immediately since the flag is still set (that is, the flag hasn't actually completed being cleared yet).
Slightly longer interrupt routine code will not show the problem since the flag clear completes, as happens when you add a small delay.
See
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646a/CHDDGICF.html
Another solution is to add a while (flag_set) {} after clearing the flag, or at some point later in the interrupt handler, which does about the same (but specific only to the single write).
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]
Hello,
I'm using MKE17Z256 in my project...
Does he have the same problem?
My computer just crashes out of nowhere. I'm using an interrupt from UART 1 and UART 2 to signal when to get to a new buffer.
In other families I have like MKL15 or MKL25 this never happened.
Here is my code for analysis:
USB:
void INT_USB_LPUART_IRQHandler(void) {
/* If new data arrived. */
if ((kLPUART_RxDataRegFullFlag) & LPUART_GetStatusFlags(LPUART_USB)) {LPUART_ReadBlocking(LPUART_USB, &buffer_usb_rx,
NUM_BYTES_USB_RX);flag_novo_dado_usb_rx = 1;
LED_USB(2);
}
SDK_ISR_EXIT_BARRIER;
}
RS485:
void INT_RS485_LPUART_IRQHandler(void) {
/* If new data arrived. */
if ((kLPUART_RxDataRegFullFlag) & LPUART_GetStatusFlags(LPUART_RS485)) {LPUART_ReadBlocking(LPUART_RS485, &rs485_buffer_rx1,
RS485_TAMANHO_BUFFER_RX);LED_RS232_TELEMETRY(2);
flag_novo_buffer_rx = 1;
}
SDK_ISR_EXIT_BARRIER;
}
Hi,
There with a note about eDMA channel periodic triggering:
I call below eDMA interrupt service routine to clear interrupt channel flag when exit eDMA ISR:
Using below eDMA ISR will avoid enter into ISR again before print in while loop.
// eDMA interrupt handler
void DMA0_DMA_CH_INT_DONE_0_IRQHANDLER(void) {
// clear interrupt status
EDMA_ClearChannelStatusFlags(DMA0_DMA_BASEADDR, DMA0_CH0_DMA_CHANNEL, kEDMA_InterruptFlag);
//SDK_DelayAtLeastUs(1, CLOCK_GetCpuClkFreq());
//EDMA_ClearChannelStatusFlags(DMA0_DMA_BASEADDR, DMA0_CH0_DMA_CHANNEL, kEDMA_InterruptFlag);
// counter for ISR calls
counter++;
printResult = true;
EDMA_ClearChannelStatusFlags(DMA0_DMA_BASEADDR, DMA0_CH0_DMA_CHANNEL, kEDMA_InterruptFlag);
}
Wish it helps.
Have a great day,
Mike
-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!
- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------
Hello Hui Ma,
thank you for your answer.
The note of eDMA just tells me that there is no guarantee when my eDMA transfer will be started after a eDMA trigger signal, but my interrupt gets fired after the transfer is complete.
I already tested your solution - calling EDMA_ClearChannelStatusFlags twice - and it works, but it does not matter where you place the second call. You can call the function for the second time directly after calling it for the fist time and the ISR will be called only once. You don't have to call EDMA_ClearChannelStatusFlags twice you can add a for loop which only counts to one in ISR and it will successfully clear the interrupt status.
Is it guaranteed to always clear the interrupt status register after calling another function? It looks like the interrupt clearing mechanism takes too long is this possible?
Kind regards,
Stefan
Hi Stefan
Add __DSB(); at the end of the interrupt handler and it will solve the problem.
This is a data synchronisation barrier which ensures that the interrupt handler is not exited from until all subsequent data changes that were made have completed.
The problem is that the DMA controller is on a bus that is clocked (usually) 4x slower than the core and, although you start the write to clear the interrupt flag, if the interrupt handler is only short, the core will already have exited from the routine and will return again immediately since the flag is still set (that is, the flag hasn't actually completed being cleared yet).
Slightly longer interrupt routine code will not show the problem since the flag clear completes, as happens when you add a small delay.
See
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646a/CHDDGICF.html
Another solution is to add a while (flag_set) {} after clearing the flag, or at some point later in the interrupt handler, which does about the same (but specific only to the single write).
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]
Hello Mark,
thank you very much for your explanation and solution!
Kind regards,
Stefan
Hi Mark,
Thanks for the info.
Add __DSB(); in eDMA ISR routine do fix the issue.
B.R.
Mike