Understanding of DMA on K66 - generate an interrupt after a number of UART bytes received ?

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

Understanding of DMA on K66 - generate an interrupt after a number of UART bytes received ?

1,904 Views
johnbbsr
Contributor II

Can the DMA on the K66 be configured to generate an interrupt after receiving a specified number of bytes on a UART peripheral ?

I have used DMA on the Microchip dsPIC33E processors in the past and was hoping to do the same with  the K66.

My understanding and experience of using DMA, is that data received (or transmitted) by a peripheral can be handled off chip in hardware (between the DMA controller and the peripheral), thereby not using any CPU instructions which frees up the CPU to do other work.  Is my understanding correct ?

This is exactly how I used it on the dsPIC with peripherals such as the ADC, SPI, CAN and I2S.  I configured the DMA to perform a number of data transfers using two DMA buffers (A and B) in ping pong mode.  Once the DMA controller had transferred the data from the peripheral to the DMA buffer, an interrupt was generated so that the data could be moved from the DMA buffer to RAM.

I have looked at the SDK example 'uart_edma_rb_transfer' but there is no DMA interrupt for the UART Rx. Instead it uses a timer to effectively poll the number of bytes received and move the data from DMA to RAM.  This requires CPU operation which I am trying to avoid, as I have a large string of data to receive which I only want the CPU to process this data once it has all been received.  I do not want the CPU to be tied up receiving this data as I have other tasks running which need to be serviced and I believe these are being starved using the existing FreeRTOS serial driver implementation.  

Assuming the K66 has this functionality (I assume it does because I thought this is what DMA is used for), is there any example code to demonstrate what I need ?

 

0 Kudos
Reply
5 Replies

1,871 Views
johnbbsr
Contributor II

Thanks Mark

Having looked at the Youtube videos, this still appears to be polling for the number of bytes received (which uses CPU operations) and I cannot see a DMA interrupt for when x number of UART bytes are received.

During the DMA initialisation it is configured for polling...

UTASKER1.png

And the function fnCheckFreerunningDMA_recption polls for the number of bytes received...

UTASKER2.png 

When I have used DMA on the Microchip dsPIC, I configured the DMA to generate an interrupt once x number of transfers had occurred.

Therefore no CPU operations were needed until the DMA ISR needed to be serviced, there was no need to keep polling (and therefore using CPU operations) to see how many bytes had been received, the DMA controller took care of all this by itself.

0 Kudos
Reply

1,861 Views
mjbcswitzerland
Specialist V

Hi

That is correct since it is the FREE_RUNNING_RX_DMA_RECEPTION mode of operation which uses no interrupts.
This is configured with
tInterfaceParameters.ucDMAConfig = (UART_RX_DMA | UART_RX_MODULO | UART_TX_DMA);
and polled with
uTaskerStateChange(OWN_TASK, UTASKER_POLLING); // set the task to polling mode to regularly check the receive buffer.

The configurations

tInterfaceParameters.ucDMAConfig = (UART_RX_DMA | UART_RX_DMA_FULL_BUFFER);
or
tInterfaceParameters.ucDMAConfig = (UART_RX_DMA | UART_RX_DMA_HALF_BUFFER | UART_RX_DMA_FULL_BUFFER );
are the ones that use end of buffer or half-buffer interrupts and no polling.

However, practically, the polling method (low priority task that does this when there is nothing else to do) or a HW timer based (eg. processor set to low power mode generally and checks on HW timer wake-up every Xms) are more practical for situations where the reception data is random/asynchronous of no pre-defined length (Xms set as long as possible for the latency requirement and the buffer length set long enough to be able to hold max. data length between checks).

tInterfaceParameters.ucDMAConfig = (UART_RX_DMA | UART_RX_DMA_HALF_BUFFER | UART_RX_DMA_FULL_BUFFER | UART_RX_DMA_BREAK);

allows break conditions to terminate the DMA transfer (useful for DMX reception which works like this) or
free-running combined with
tInterfaceParameters.Config |= UART_IDLE_LINE_INTERRUPT; // use idle line to cause input checking
are further possibilities.

Basically the best method (compromise) needs to to be chosen for the task in hand (or protocol used). All allow high speed UART (several MBaud without risk of overrun, which is often the main reason for DMA) but if the frame length is not know and fixed some form of polling or notification (idle line or break condition) are needed and the polling solution is a compromise between polling rate and reception latency (and required rx buffer size to be sure to be able to fold the max. data between checks).

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or product development requirements

 

1,882 Views
johnbbsr
Contributor II

Thanks Mark

After reading the uTasker UART DMA guide, I noticed a feature that would be very useful...

"The DMA reception can to be configured to receive a block of data and the reception is only
complete once the defined amount of reception bytes has been received. Alternatively it can
be configured to recognise a break character to trigger the end of a complete reception
message."

Can the K66 DMA be configured to recognise a character that indicates its reached the end of a data stream, rather than rely on the number of bytes ?

If I can get the UART DMA working, then this will be the next issue.  i.e. how to synchronise the data coming in

The UART data will be coming from a GPS receiver (a U-BLOX ZED-F9P) which will be constantly streaming data.

0 Kudos
Reply

1,881 Views
mjbcswitzerland
Specialist V

Hi

The UART break condition is a special state where the data line is held low for a period longer than that of a normal character - the UART can't be configured to recognise normal characters as break conditions.

It is also possible to use an idle line detection to signal the end of a reception packet (assuming it is not generally possible for multiple packets to arrive without any idle line spacing between them).

For random data reception a free-running method is usually most suitable and the uTasker project integrates FreeRTOS free running UART reception since this is a popular configuration which otherwise has difficulties to be realised when using the standard peripheral libraries. Essentially a low priority FreeRTOS task polls the DMA reception as follows:

 

static void uart_task(void *pvParameters)
{
    QUEUE_TRANSFER length = 0;
    QUEUE_HANDLE uart_handle;
    unsigned char dataBuffer[1];

    while ((uart_handle = fnGetUART_Handle()) == NO_ID_ALLOCATED) {      // get the UART handle
        vTaskDelay(500/portTICK_RATE_MS);                                // wait for 500ms in order to allow uTasker to configure UART interfaces
    }
    fnDebugMsg("FreeRTOS Output\r\n");                                   // test a UART transmission when the task starts and the UART is ready
    FOREVER_LOOP() {
        length = fnRead(uart_handle, dataBuffer, sizeof(dataBuffer));    // read waiting data from the DMA input buffer (returns immediately)
        if (length != 0) {                                               // if something is available
            fnDebugMsg("FreeRTOS Echo:");                                // echo it back
            fnWrite(uart_handle, dataBuffer, length);                    // send the reception back
            fnDebugMsg("\r\n");                                          // with termination
        }
        else {                                                           // nothing in the input buffer
            vTaskDelay(1);                                               // wait a single tick to allow other tasks to execute
        }
    }
}

 

 

When using idle line instead it looks like

 

static void uart_task(void *pvParameters)
{
    QUEUE_TRANSFER length = 0;
    QUEUE_HANDLE uart_handle;
    unsigned char dataBuffer[128];

    xSemaphore = xSemaphoreCreateBinary();                               // create a binary semaphore

    while ((uart_handle = fnGetUART_Handle()) == NO_ID_ALLOCATED) {      // get the UART handle
        vTaskDelay(500/portTICK_RATE_MS);                                // wait for 500ms in order to allow uTasker to configure UART interfaces
    }
    fnDebugMsg("FreeRTOS Output\r\n");                                   // test a UART transmission when the task starts and the UART is ready
    FOREVER_LOOP() {
        xSemaphoreTake(xSemaphore, portMAX_DELAY);                       // take semaphore/wait for semaphore to become free (idle line detection)

        length = fnRead(uart_handle, dataBuffer, sizeof(dataBuffer));    // read waiting data from the DMA input buffer (returns immediately)
        if (length != 0) {                                               // if something is available
            fnDebugMsg("FreeRTOS Echo:");                                // echo it back
            fnWrite(uart_handle, dataBuffer, length);                    // send the reception back
            fnDebugMsg("\r\n");                                          // with termination
        }
    }
}

 

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or product development requirements

 

0 Kudos
Reply

1,898 Views
mjbcswitzerland
Specialist V


Hi

The eDMA in the K66 is a full feature DMA with peripheral trigger and can be programmed to genertae an interrupt after a certain number of bytes have been received, or it can generate interrupts at half-buffer barriers for ping-pong buffer operation.

Complete code is available in the open source uTasker project at https://github.com/uTasker/uTasker-Kinetis with UARt DMA guide in chapter 10 of https://www.utasker.com/docs/uTasker/uTaskerUART.PDF

The K66 and its UART DMA operation is simulated in its K66 simulator (in approx. real-time) to allow complete testing, debugging and learning.

See also videos at
https://www.youtube.com/watch?v=dNZvvouiqis&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=10
https://www.youtube.com/watch?v=GaoWE-tMRq4&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=11
showing and explaining free-running Rx DMA on a KL27, which has a reduced feature DMA module but achieves compatible operation.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or product development requirements