How to get UART RX DMA with ILIE/ILDMAS working (again) [K24 family]

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

How to get UART RX DMA with ILIE/ILDMAS working (again) [K24 family]

905 Views
bjoern_lichtbla
Contributor I


Hi all,

So I have read the numerous (maybe all?) threads about UART and DMA here.


I agree that a free running UART RX DMA is great and want to have that (also achieved draft version,
no problems there so far). But I agree further with others, that the next great thing would be to get an interrupt
when there is something in the DMA buffer to process. pmt has discussed this (imo very apparent&straightforward) need in great length here (and also why this is problematic/critical to do via UART interrupt alone): https://community.nxp.com/thread/301651

I know I could configure DMA so that I get an interrupt every byte, but at high rates and even
with just a signaling IRQ, I'd consider this too much load on the system and not what I want when using RX DMA.

Yes, I also agree just "polling" the RX DMA buffer periodically / at idle times is good enough and likely the way I will go if
this doesn't work out. But to get optimal low latency processing of received data I have to poll often, but high frequency polling will 99% of the time not be needed due to rare transfers. So best thing (again as discussed in https://community.nxp.com/thread/301651) would be to get a notification for the IDLE condition.

So the manual seems to document right in my face what I want: Set ILIE in C2 together with ILDMAS in C5,
and that should then generate DMA transfer requests...

But how should that work? Is it an RX DMA request? But then DMA would read an empty DREG and still it wouldn't help me generate an interrupt ..Or would it be kind of special DMA request that lets my RXA DMA generate INTHALF or  INTMAJOR, or even generate some kind of error? All would be a little more helpful, but no further documentation on how this could work. => Anyway, setting ILIE&ILDMAS does not seem to have an effect at all, no additional character transferred into receive buffer, no additional INTHALF/INTMAJOR/DMA error interrupt, and even the IDLE flag keeps to set in the UART, so really nothing seems to process (and clear) it.

Alternatively, could it maybe work over its own DMA channel? Seems kind of wastfulness, but we have enough channels and I'd happily would set up a DMA channel just for IDLE requests... but no there are only RX and TX UART DMA requests.

Then after reading again and a lot more threads I found https://community.nxp.com/thread/301359
"I'm afraid that is a documentation error, ILDMAS in UART are not supported in Kinetis microcontrollers."

Can anyone confirm this again please? I still have minor but dwindling hopes that just changed; I mean this thread is from 2013 ... I am looking at the latest reference manual from 2017, in the year 2020. If above statement is true, why is the reference manual still pointing it out like that? ( I'm concretely looking at a MK24FN1M0xxx12. - https://www.nxp.com/webapp/Download?colCode=K24P144M120SF5RM&location=null Rev 3, July 2017)


(and just some further UART/DMA threads for reference beyond the two mentioned above: https://community.nxp.com/thread/110844 https://community.nxp.com/thread/318780 https://community.nxp.com/thread/508874 https://community.nxp.com/thread/301031 https://community.nxp.com/thread/525667 )

Afterwards questions: Has anyone conceived a scheme how to 100% safely use the UART IDLE interrupt together with DMA (due to potential side effects of clearing this flag by needing to read S1/D while receiving characters)? My current thinking would be that in the IDLE IRQ routine I need to check RAF and can only clear IDLE by reading S1/D (and then also clear underflow and flush fifo?) when RAF is not set (otherwise do clear IDLE only later outside of IRQ somehow).

Thank you for any response!

0 Kudos
2 Replies

868 Views
mjbcswitzerland
Specialist V

Hi

I believe that the DMA on idle line control is a documentation error since this appeared in the Rev.4 version of the K24 manual and previously was not mentioned. Also the Rev. 4 document history doesn't refer to it being added, but does rework the UART description for some other unrelated reasons. Furthermore, as you point out, there is no DMA trigger for such an event (only for Rx and Tx) and thus makes no sense.

By using a mixture of reception polling and the idle line detection interrupt a compromise between polling period and latency can often be achieved.

The LPUARTs used in various Kinetis parts allow the idle state to be reset by writing a '1' to it, which is practical and reliable.

In the case of the Kinetis UARTs, such as in K24, a read of the data register is required to clear it, which is not really safe when working with DMA that is also reading the same data register. My feeling is that the UART design is flawed somewhat in this respect and, as you have seen, safely reading (especially when DMA reads could also take place) is a challenge. Personally I would avoid using this feature if at all possible since I also don't know how to do it with 100% safety (without temporarily freezing the DMA and Rx operation, which could also cause data corruption/loss when the Baud rate is high).

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

0 Kudos

868 Views
mjbcswitzerland
Specialist V

Björn

I checked the solution in the free-running DMA UART Rx mode with idle line interrupt in the uTasker project:


// Generic UART interrupt handler
//
static __interrupt void _UART_interrupt(KINETIS_UART_CONTROL *ptrUART, int UART_Reference, int iFlags)
{
    unsigned char ucState = ptrUART->UART_S1;                            // status register on entry to the interrupt routine

    if (((ptrUART->UART_C2 & UART_C2_ILIE) != 0) && ((ucState & UART_S1_IDLE) != 0)) { // idle line flagged on entry and its interrupt is enabled
        if ((ptrUART->UART_S1 & UART_S1_IDLE) != 0) {                    // if the idle line flag is still set (not cleared by a read of a new reception since the status register was read - by DMA)
            if ((ptrUART->UART_S1 & UART_S1_RDRF) == 0) {                // as long as no reception is pending
                (void)ptrUART->UART_D;                                   // read the data register in order to clear the idle line flag
            }
        }
        fnSciRxIdle((QUEUE_LIMIT)UART_Reference);                         // call the idle line interrupt handler
    }
..
... handle rx, tx, errors
..
}

As you can see it detects the idle line state when the interrupt "enters" with the idle line flag set and clears it with a dummy read of the data register if the flag is still set and there is no pending data in the receiver. This "works" with all Kinetis UARTs, including the K24 but I am not convinced that there is not a race state where it could cause data loss.

The reasoning for the code is that also DMA Rx data reads clear the idle flag after the status read on entry was made, as does any other (non-DMA) read. Therefore it is possible that the idle state was detected and a following reception has already taken place (fast Baud rates and other system interrupts with higher priority delaying the  idle handling).
If rx is pending, no dummy read is made since it would cause the Rx interrupt that would take place if working in interrupt driven mode to be lost. In fact I think that it is less likely to cause a DMA reception problem since even if the dummy code were to steal the data byte from the DMA, the DMA operation is probably still pending and will also read the same value.
However I still see a minimum race state at the actual dummy read itself - assuming that the previous checks didn't show signs that data should not be read since it will be subsequently done so by interrupt or DMA (which also clears the idle line status flag) it doesn't mean that it can't become ready 'during' the dummy read operation, in which case the dummy read may cause the DMA trigger to be lost (or an rx interrupt to be lost in interrupt driven mode).

The RAF flag would show that subsequent reception is in progress and so one could also avoid reading the data register (due to a race state coming up) but this causes other difficulties since one is then relying on the subsequent read (either interrupt driven or DMA driven) to clear the idle line interrupt. During this time the idle line interrupt needs to be disabled otherwise it will continuously cause the interrupt to re-enter until the character finally completes and in DMA mode there is no indication of when that is so there is the complication when to re-enable the interrupt without missing something... On top of that is the question of race state allowing the RAF to be missed when checked just as data becomes ready? Therefore no RAF checking was implemented.

Although data loss is unlikely I am not convinced it can't take place and I also think that the flag resetting method is what makes it impossible to exclude it 100%. If you see any way to improve this it would be interesting to continue discussions of potential methods!

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

P.S. The i.MX RT parts have only the LPUART instances so these are free of such worries!

0 Kudos