Is there or actually how much there is/can be delay between giving the DMA disable request and that channel has been actually stopped?
I have basically following code to tackle the uart errors during DMA transfer (see my other post Kinetis (K10) UART DMA rx error handling ).
- key point is to stop DMA&uart until the uart error has been completely solved
void Uart_error_irq( void )
{
UART_C2_REQ( uart0 ) &= ~(UART_C2_RE_MASK);
DMA_CERQ = DMA_CERQ_CERQ(uart_rx_dma_ch);
status = UART_S1_REQ( uart0 );
(void)UART_D_REG( uart0 );
UART_C_FIFO_REG( uart0 ) |= (UART_CFIFO_RXFLUSH_MASK);
print_uart_error( status );
notifytask(); // posts error event to task
}
task()
{
event = wait_events();
if( event & uart_error)
{
error_event_handler();
}
}
void error_event_handler( void )
{
if( DMA_ERQ & uart_rx_dma_ch )
{
// DMA still running
notifytask(); // kick task again to avoid busy loops // added afterwards
u32DmaStillRunningCountDebug++;
}
else
{
SetBufferReadingIndex();
UART_C_FIFO_REG( uart0 ) |= (UART_CFIFO_RXFLUSH_MASK); // just in case
DMA_SERQ = DMA_SERQ_SERQ( uart_rx_dma_ch );
if( DMA_ERR & uart_rx_dma_ch )
{
Error();
}
UART_C2_REQ( uart0 ) |= UART_C2_RE_MASK;
}
}
I test the system by calling by Uart_error_irq() periodically from my software (1sec in this case) to simulate the error (this is the only reasonable way to test that my error handling code works & the transferred protocol over uart tolerates such errors).
- I noticed that sometimes u32DmaStillRunningCountDebug increases
Then I looked a little bit further and noticed that DMA_CERQ-command is not always "immediately" visible in DMA_ERQ, so I added the task-re-kicker rather than while( DMA_ERQ & uart_rx_dma_ch )-busy wait loop and now it looks to work ok.
- CPU manual does not mention that there is any delays, based on my tests the delay exists only if there is active uart-transmission ongoing...
If the DMA is serving the uart request I assume that it cannot be immediately stopped? If that is true then the DMA_CERQ delay should not depend of used baudrate because DMA is not connected to uart shift-register so some kind of busy-wait loop could added because the delay "should be" small? What is the worst case delay between DMA_CERQ & DMA_ERQ visibility?
I don't also understand why CPU manual says that BITER-value must match CITER-value or configuration error is reported? Based on my experience that is not true. If you use DMA_CERQ to stop the DMA-channel, you do not need to do any CITER settings to continue with DMA_SERQ. After DMA_SERQ I also use DMA_ERR-register to check if there is error present in channel and none is present even though the CITER seldom equals BITER because I have 400 byte long buffer.
So both methods in the function look to work equally (and yes, I am sure that in #else the CITER != BITER)
SetBufferReadingIndex()
{
#ifdef FULL_DMA_INIT
DMA_DADDR( uart_rx_dma_ch ) = buffer;
DMA_CITER_ELINKNO( uart_rx_dma_ch ) = DMA_BITER_ELINKNO( uart_rx_dma_ch );
prevciter = DMA_CITER_ELINKNO( uart_rx_dma_ch );
BufReadIndex = 0U;
#else
prevciter = DMA_CITER_ELINKNO( uart_rx_dma_ch );
BufReadIndex = DMA_DADDR( uart_rx_dma_ch ) - (uint32)buffer;#endif
}
Is there somewhere available a proper description that how the DMA actually works because looks like that CPU manual has errors and also hides information... This is really time consuming trying to figure out cpu-functionality by trial and error!!! Maybe I have now figured out enough of the DMA functionality because code looks now ok and pretty bullet proof so maybe I don't need that information any more but someone else would need...
Hello Jarkko,
The Clear Enable Request doesn't clear the request immediately, you could try to do this quicker by writing 0 in the ERQ register. We don't have information about the worst case delay.
About the CITER and BITER registers, please take a look into the DMA_TCn_BITER_ELINKNO[BITER] description in the reference manual, there is explained why these fields must be equal while the module is configured.
Best regards,
Earl.