Thanks for everyone's input.
I have spent a week trying to get the KL26 UART and DMA to do what I want. I agree with Mark about the overrun problems.
The problem:
I have a modem that spits out status strings are unpredictable times.
The modem only works at 115200.
My app needs to ack as soon as the UART RX goes IDLE.
My app also needs to use minimal power, so the MCU needs to sleep until the UART IDLE event occurs.
My app uses FreeRTOS, so the solution must work with it.
The cause:
The MCU is in sleep mode, it takes time coming out of sleep before it can handle the UART ISR.
The UART hardware overrun occurs before the MCU is awake and completes the UART ISR.
NXP solutions that don't work:
The NXP has provided examples for the UART and DMA that all the have this problem: by the time the sleeping MCU has waken (clocks clocking, etc), the next char has been received by the UART, and it has overrun.
The FreeRTOS UART examples are worse, the receive function waits forever for a fixed length string that it might never receive.
Conclusions:
With a UART running at 115200 and a sleeping MCU, the use of UART or DMA interrupts will not work. Period.
A possible solution:
set the DMA as free running
2 DMA buffers
a hardware timer called by ISR, not FreeRTOS scheduler
a queue with a mutex
xSemaphoreCreateMutex()
a FreeRTOS thread that starts the DMA and gets data from the queue.
Data flow:
DMA -> Buffer0 or Buffer1 -> timer -> queue -> thread's buffer
A FreeRTOS thread would:
Setup 2 DMA buffers.
Setup a Queue that the timer would copy to, and FreeRTOS thread would copy from.
Setup a periodic timer.
Start UART RX and DMA.
A hardware timer ISR would:
Attempt to get the Queue's mutex
xSemaphoreTakeFromISR()
If the Queue's mutex was acquired then
disable FreeRTOS
taskENTER_CRITICAL_FROM_ISR()
disable the DMA interrupt
save the count of data in the current DMA buffer
if (0 < count) then
Switch DMA buffers
Setup the next DMA transfer
enable the DMA interrupt
enable FreeRTOS
taskEXIT_CRITICAL_FROM_ISR()
if (0 < count) then
Copy data in the DMA buffer to the Queue
If the Queue has overrun, then
Set a "overrun" variable
release the Queue's mutex
xSemaphoreGiveFromISR()
if the Queue has received data then
send an event to the FreeRTOS thread to wake it up.
xEventGroupSetBitsFromISR()
A FreeRTOS thread would periodically:
Attempt to get the Queue's mutex
xSemaphoreTake()
If the Queue's mutext was acquired then
copy data from the Queue to a string for processing.
Clear the "overrun" variable
release the Queue's mutex
So far, I have the DMA to filling the DMA buffer without losing any RX data.
I have the queue and mutex working.
But I have not figured out how to SAFELY get the data and setup the next DMA buffer (In bold above).
Does anybody see a problem with this?
Thanks,
Bruce