Why does the eDMA ISR get called twice after one major count completion interrupt?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Why does the eDMA ISR get called twice after one major count completion interrupt?

Jump to solution
2,955 Views
mitterha
Senior Contributor I

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

1 Solution
2,804 Views
mjbcswitzerland
Specialist V

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]

View solution in original post

6 Replies
1,858 Views
samueldionisiod
Contributor II

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;

}

 

 

 

0 Kudos
2,804 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

There with a note about eDMA channel periodic triggering:

pastedImage_1.png

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.
-------------------------------------------------------------------------------

0 Kudos
2,804 Views
mitterha
Senior Contributor I

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

0 Kudos
2,805 Views
mjbcswitzerland
Specialist V

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]

2,804 Views
mitterha
Senior Contributor I

Hello Mark,

thank you very much for your explanation and solution!

Kind regards,

Stefan

0 Kudos
2,804 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Mark,

Thanks for the info.

Add  __DSB(); in eDMA ISR routine do fix the issue.

B.R.

Mike

0 Kudos