Brian
1. You need a count variable (eg. unsigned long ulDMA_progress) to remember the reception progress. It starts with the length of the rx circular buffer.
2. Since the DMA will be copying received data immediately to the circular buffer, and wrapping around automatically, the application must "poll" the progress and read out the data before it gets overwritten. The polling rate depends on how fast a (complete) message needs to be detected and also on how large the buffer is; if the buffer is larger it takes longer for it to be able to overflow.
3. To poll the progress one reads the DMA_TCD_CITER_ELINK register, which indicates the number of bytes that haven't yet been copied (it counts down) before automatically being reloaded to its initial value.
If (ulDMA_progress >= the snap shot value of DMA_TCD_CITER_ELINK) you know that the 'additional' bytes in the input buffer have increased by (ulDMA_progress - DMA_TCD_CITER_ELINK), which can also be 0 if nothing was received in the meantime, else the increase is (ulDMA_progress - (DMA_TCD_BITER_ELINK - DMA_TCD_CITER_ELINK))
4. After the check ulDMA_progress is updated to be equal to DMA_TCD_CITER_ELINK again.
5. In the calculations the snap-shot value of DMA_TCD_CITER_ELINK on entry is to be used throughout and not the present DMA_TCD_CITER_ELINK value since it can change and thus cause race-state errors.
Since the polling will do this each time it also updates the values each time new data has been detected. When new data is ready (or the total data count reaches a threshold that should be handled) the application should use the data (which will at some point later be overwritten) and decrement its the total waiting data count value (which is incremented on each poll by the new 'additional' data count value).
As example, FreeRTOS users (who otherwise don't have libraries for free-running Rx with DMA) can use the uTasker project (which integrates a FreeRTOS configuration) and set up a polling task that does something like:
static void uart_task(void *pvParameters)
{
QUEUE_TRANSFER length = 0;
QUEUE_HANDLE uart_handle;
unsigned char dataByte;
while ((uart_handle = fnGetUART_Handle()) == NO_ID_ALLOCATED) {
vTaskDelay(500/portTICK_RATE_MS);
}
fnDebugMsg("FreeRTOS Output\r\n");
FOREVER_LOOP() {
length = fnRead(uart_handle, &dataByte, 1);
if (length != 0) {
fnDebugMsg("FreeRTOS Echo:");
fnWrite(uart_handle, &dataByte, 1);
fnDebugMsg("\r\n");
}
else {
vTaskDelay(1);
}
}
}
which waits for the UART to be configured by uTasker in the appropriate mode and then polls it (here at 1 TICK I believe), and echos the data back to verify operation.
It allows any K, KL, KV, KM, KW part (with DMA HW support) to be used on UART or LPUART in a compatible manner and so doesn't need porting and new driver development each time functions are moved to different processors. It can be used for reception rates of several Mb/s without loss of data.
Regards
Mark
Complete Kinetis solutions for professional needs, training and support:http://www.utasker.com/kinetis.html
uTasker: supporting >1'000 registered Kinetis users get products faster and cheaper to market