MKL26Z256 - Can DMA UART RX end transfer on RX idle?

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

MKL26Z256 - Can DMA UART RX end transfer on RX idle?

8,523 Views
bgraham
Contributor IV

MCUXpresso IDE v11.0.0 [Build 2516] [2019-06-05]

Device: MKL26Z256xxx4

SDK_2.x_MKL26Z256xxx4 2.4.1

 

I started with the driver example UART dma_transfer project.

The project has the DMA RX setup to receive fixed length transfers.

I am working with a modem, so I can't predict the transfer length of the data from the modem.

I need a why to end the DMA RX transfer when the UART line is idle.

Is it possible to end the DMA transfer when the UART Controller generates an IDLE interrupt?

Thanks,

Bruce

37 Replies

2,829 Views
bgraham
Contributor IV

Mark,

thanks for pointing out that setting DMA0.DCR.EINT to 1 will cause problems.

I also used the DMA DAR to determine how much data is in the DMA buffer.

I found that using a single DMA buffer was not working.

Coping the data from the single DMA buffer would take to long, and before resuming the DMA, the UART D would Overflow.

I solved the Overflow problem by quickly switching between 2 buffers, resuming DMA, and then coping data from the old buffer.

I code has been running with for hours without any errors, so I feel confident that this is working. See below.

Thanks for putting up with my frustration.

Bruce

uint8_t * pDMA_Buffer;
if (0 == s_iCurrentBuffer)
pDMA_Buffer = s_pDMA_Buffer0;
else
pDMA_Buffer = s_pDMA_Buffer1;

uint8_t * pDAR = (uint8_t *)baseDMA->DMA[channel].DAR;
if ((pDMA_Buffer + 1) < pDAR)
{

// stop the current transfer
//////////////////////////////////////
baseDMA->DMA[channel].DCR &= ~DMA_DCR_ERQ_MASK; // Disable Peripheral Request
baseDMA->DMA[channel].DSR_BCR |= DMA_DSR_BCR_DONE(true); // clear the DONE flag and clear errors etc.

// save the length
//////////////////////////////////////////////////////////////////////////
iLength = pDAR - &pDMA_Buffer[1]; // the first received char is in s_pDMA_Buffer[1]

// switch buffers for the next transfer
//////////////////////////////////
if (0 == s_iCurrentBuffer)
{

baseDMA->DMA[channel].DAR = (uint32_t)s_pDMA_Buffer1;
s_iCurrentBuffer = 1;

}
else
{

baseDMA->DMA[channel].DAR = (uint32_t)s_pDMA_Buffer0;
s_iCurrentBuffer = 0;

}

baseDMA->DMA[channel].DSR_BCR = DMA_DSR_BCR_BCR(s_iSizeOfBuffers);

// enable the next transfer
//////////////////////////////////
baseDMA->DMA[channel].DCR |= DMA_DCR_ERQ_MASK; // Enable Peripheral Request

}

if (0 < iLength)

{

s_Queue.push(&pDMA_Buffer[1], iLength); // the data starts in the 2nd location.

memset(pDMA_Buffer, 0, s_iSizeOfBuffers);

}

0 Kudos
Reply

2,829 Views
bgraham
Contributor IV

I gave up on the free running DMA.

The UART interrupts are stolen by the DMA controller.

Since the timer has to clear an error before any more data can be received, all the characters that arrive between timer ticks are lost.

Since the errors were not being cleared before the next character came in, the OR flag would be set.

I ended up creating my own UART1_IRQHandler().

UART1_IRQHandler() does 3 things:

* clears errors

* puts received chars into a queue

* if RX IDLE occurs, it sets aFreeRTOS event

That worked. See below.

Bruce

file: uart_rx.cpp

/*
* Purpose: UART RX ISR
*
* Details:
*/
extern "C"
void UART1_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
BaseType_t xResult = pdFAIL;
E_EVENT_UART eEvent = E_EVENT_UART_ZERO;

UART_Type * baseUART = UART1;
uint32_t iS1 = baseUART->S1;

if (UART_S1_PF_MASK & iS1)
{
TraceToDebugger("Clear PF flag\r\n");
baseUART->S1 = UART_S1_PF_MASK;
(void)baseUART->D;
}
if (UART_S1_FE_MASK & iS1)
{
TraceToDebugger("Clear FE flag\r\n");
baseUART->S1 = UART_S1_FE_MASK;
(void)baseUART->D;
}
if (UART_S1_NF_MASK & iS1)
{
TraceToDebugger("Clear NF flag\r\n");
baseUART->S1 = UART_S1_NF_MASK;
(void)baseUART->D;
}
if (UART_S1_OR_MASK & iS1)
{
TraceToDebugger("Clear OR flag\r\n");
baseUART->S1 = UART_S1_OR_MASK;
(void)baseUART->D;
}

xResult = xSemaphoreTakeFromISR(mutexQueue, &xHigherPriorityTaskWoken);
assert(pdTRUE == xResult);

/* Receive data register full */
while ((UART_S1_RDRF_MASK & baseUART->S1) && (UART_C2_RIE_MASK & baseUART->C2))
{
uint8_t chChar = baseUART->D;
if (1 != s_Queue.push(&chChar, 1))
{
eEvent = E_EVENT_UART_RX_QUEUE_OVERFLOW;
break; // buffer is full
}
}

xResult = xSemaphoreGiveFromISR(mutexQueue, &xHigherPriorityTaskWoken);
assert(pdTRUE == xResult);

if (UART_S1_IDLE_MASK & baseUART->S1)
{
//TraceToDebuggerNoWait("Clear IDLE flag\r\n");
(void)baseUART->D;

eEvent = E_EVENT_UART_RX_IDLE;
}

if (E_EVENT_UART_ZERO != eEvent)
{
xResult = xEventGroupSetBitsFromISR(
s_eventUART,
eEvent,
&xHigherPriorityTaskWoken);
if (xResult != pdFAIL)
{
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}

0 Kudos
Reply

2,836 Views
danielchen
NXP TechSupport
NXP TechSupport

Hi Bruce:

Please refer to my attached code , it uses uart DMA with idle line detection to receive some variable-length data.

This is a bare metal project, and you can port it to SDK.

It was tested with Frdm-kl26 board.

I hope it helps.

I will create an internal ticket to the developers to integrate the idle line detection demo to SDK.

Thank you all for your good suggestions.

Regards

Daniel

0 Kudos
Reply

2,836 Views
mjbcswitzerland
Specialist V

Daniel

Beware that this code is not free-running Rx DMA but instead is the fixed length reception with the idle line interrupt signalling that a pause has occurred and resetting the same fixed length DMA transfer.

This will work in basic situations but suffers from race states when further rx data arrives when the application has not yet handled the content of the reception buffer; this potential problem could however be overcome by using two different fixed length buffers and swapping between them.

The second problem that it has is that it still involves a critical interrupt and it cannot guarantee that the first byte of a following message is not lost (overrun), especially at higher Baud rates.

Therefore it demonstrates the operation but is not a fully reliable implementation and thus poses potential problems to product operation and reliability.

With the DMA controller in the KL parts the only method for optimal performance and reliability is to use true free-running techniques based on modular aligned buffers without interrupts controlling DMA configurations.

Regards

Mark

2,836 Views
bgraham
Contributor IV

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()

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

0 Kudos
Reply

2,835 Views
mjbcswitzerland
Specialist V

Hi

For low power mode you need to ensure that both DMA and UART are operational so that it can operate in the low power state without restrictions (UART0 clock is more flexible on the KL26 so is advised for more flexible low power clocking in low power modes). You also need to know your uA limit to be able to decide whether a particular mode is possible or not.
VLPW is potentially interesting assuming you can afford about 250uA current consumption typically and also run the processor at a lower speed.

I have attached two binaries for the FRDM-KL26Z board that allow the operation that you are looking for and allow the consumption to be measured.

FreeRTOS_FRDM-KL26_UART_FREERUN_DMA_IDLE_LINE_WAIT.bin uses a task as follows with semaphore to avoid any polling. The processor waits in WAIT mode (CPU clock stopped but DMA, UART and other enabled peripherals fully active) which saves about 40% consumption compare to when the processor is always running. There is a task flashing an LED periodically but the UART task will wait for a semaphore indefinitely unless it is temporarily released by the idle line interrupt. The UART is in free running DMA mode without any DMA interrupts or need to change buffers and such, which represents the optimal solution

This is the task and idle line interrupt callback which is controlling the task operation.

#include "semphr.h"

static SemaphoreHandle_t xSemaphore = NULL;

static void uart_task(void *pvParameters)
{
    QUEUE_TRANSFER length = 0;
    QUEUE_HANDLE uart_handle;
    unsigned char dataIn[128];
    xSemaphore = xSemaphoreCreateBinary();                               // creat 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
    FOREVER_LOOP() {
        xSemaphoreTake(xSemaphore, portMAX_DELAY);                       // take semaphore/wait for semaphore to become free (idle line detection)
        length = fnRead(uart_handle, dataIn, sizeof(dataIn));            // read available data from the DMA input buffer (returns immediately)
        if (length != 0) {                                               // if something is available
            fnDebugMsg("FreeRTOS Echo:");                                // echo it back
            fnWrite(uart_handle, dataIn, length);                        // send the buffer content back
            fnDebugMsg("\r\n");                                          // with termination
        }
    }
}

// Called from UART idle line interrupt
//
extern int fnSciRxIdle(QUEUE_HANDLE channel)
{
    xSemaphoreGive(xSemaphore);                                          // allow the UART task to continue
    return 0;
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I do use the uTasker low power module and UART driver to do this as it works off-the-bat and, since I am on holiday the next weeks, don't have time to re-write it so that it is doesn't reference existing uTasker library code. You can however attach a debugger and check how the DMA and UART is setup and possibly reverse engineer it from the settings (the library is only setting up the UART, a modulo circular buffer and the DMA).
Since the FreeRTOS task only echos back reception here is no menu to control low power mode tests in this version.


The second is a pure uTasker project (without FreeRTOS task but using the same libray code - the UART/DMA/Idle line operation is equivalent) - uTasker_FRDM-KL26_UART_FREERUN_DMA_IDLE_LINE_WAIT.bin. It inherits a menu with low power control in this case so also allows checking the current consumption in the various low power modes and see how the UART is affected in the process. Note that the processor is operating at 48MHz and so not all low power modes are possible in this case (due to max. clocks being exceeded).

The VCOM UART is active in all cases at 115kBaud and the low power menu is in the "administration menu":
The command "show_lp" shows the available modes which are dynamically switched between when set, with the WAIT mode being set by default (as used by FreeRTOS version):

"show_lp"
RUN = 0
WAIT = 1 [active]
STOP = 2
PSTOP1 = 3
PSTOP2 = 4
VLPR = 5
VLPW = 6
VLPS = 7
VLLS0 = 8
VLLS1 = 9
VLLS3 = 10


The new low power mode can be set with
"set_lp 2" for example.

Since I don't have a multi-meter with me I couldn't test the consumption in each case and therefore I also am not sure which of the low power modes are possible/taken.
It may however give you a starting reference for your own work.

Regards

Mark

0 Kudos
Reply

2,835 Views
bgraham
Contributor IV

Thanks for trying to help, but uTasker drags in too much extra stuff that will not fit in FLASH.

My current version is mostly working as I described above, but I used a FreeRTOS timer instead of a hardware timer, so I used the non ISR forms of the FreeRTOS APIs.

I have the UART, DMA buffer switching and FreeRTOS timer working.

The code gets the first modem string from the first DMA buffer.

But, after the 2nd DMA buffer is setup, the DMA fails to trainsfer the 2nd modem string.

I can see that the first char of the 2nd string is getting into the UART's D register, so it seems that the DMA controller has failed to start the 2nd DMA transfer.

My timer code is starting the next DMA using DMA_SetTransferConfig() to setup the buffer. It uses DMA_TriggerChannelStart() to start the next DMA transfer by setting the DMA DCR START bit.

See below.

DMA_ResetChannel(baseDMA, channel);

// Switch DMA buffers
switch(s_iCurrentBuffer)
{
case 0:

memset(s_szBuffer1_DMA, 0, s_iSizeOfBuffers);
s_dma_transfer_config.destAddr = (uint32_t)s_szBuffer1_DMA;
s_iCurrentBuffer = 1;
break;

case 1:

memset(s_szBuffer0_DMA, 0, s_iSizeOfBuffers);
s_dma_transfer_config.destAddr = (uint32_t)s_szBuffer0_DMA;
s_iCurrentBuffer = 0;
break;

}

DMA_SetTransferConfig(baseDMA, channel, &s_dma_transfer_config); // Use the saved config
DMA_TriggerChannelStart(baseDMA, channel);

UART_EnableInterrupts(baseUART, kUART_RxDataRegFullInterruptEnable);

The UART appears to be getting the first char from the modem's 2nd second string.

See DMA0 and UART1 registers below.

DMA-DSR-BCR0 BSY is 1

DMA-DCS0 EINT is 1

DMA-DCS0 START was set

I think the 2nd DMA transfer is not getting started.

What might explain why my 2nd DMA transfer fails to start?

Thanks,

Bruce

pastedImage_2.png

0 Kudos
Reply

2,836 Views
bgraham
Contributor IV

I found the problem.

Each DMA transfer is clearing DMA-DCR0 ERQ.

To set ERQ, I added DMA_StartTransfer(s_handleDMA->rxDmaHandle) after DMA_TriggerChannelStart(baseDMA, channel).

Setting ERQ looks like it is working!

Thanks for every one's ideas.

I attached the working project.

Bruce

0 Kudos
Reply

2,836 Views
mjbcswitzerland
Specialist V

Hi

What current consumption do you achieve?

Note that if you have problems with code size make sure that you enable optimisation for size - I see that your debug version generates about 40k code size but your release version (with optimisation for size) is about half the size.

Where did you get the code size values for the uTasker FreeRTOS environment from? If I put your tasks in it I get a code size of 15k (with optimisation for size) including all your tasks plus the uTasker DMA interface in a further task, and dynamic low power support. This is what I expect because the environment is designed to be more efficient than the standard HW libraries and allows more application functionality to be achieved in a certain flash size; since your figures suggest that it is the other way round I would be interested to learn where they were taken from so that I can check there is no mistake somewhere.

Regards

Mark

0 Kudos
Reply

2,836 Views
bgraham
Contributor IV

My test app has not power management.

My target app does power management in the FreeRTOS vApplicationIdleHook().

When the Idle task runs, it puts the MCU to sleep.

The MCU wakes when an interrupt occurs.

My state machines are event driven. They regularly wake after a timeout.

When an interrupt occurs, the FreeRTOS scheduler resumes, the state machines run and then wait for another event.

The MCU is typically asleep 99.999% of the time.

I measured the current drawn from the battery and this saved me 2.5 mA.

Since my code is directly managing DMA registers, it is about as minimal as it can get.

I would like to see if using free running DMA code would use less memory and MCU cycles.

I looked at the uTasker code. It is executing lots of code that makes it portable. I can't afford that over head. This project will never be ported to another MCU, so why not manage the DMA registers directly?

Bruce

0 Kudos
Reply

2,836 Views
CarlFST60L
Senior Contributor II

Hi Bruce,

I was trying to use the SDK for similar reasons and the same application in FreeRToS. I know you said you dont want to use uTasker but it actually has full FreeRToS support and I have a few projects running in production with it which we're very happy with. I had a large and complex project in FreeRToS and just copied it over to uTasker and called tasks and it works straight away.

Unless you want to rework the SDK code to do what you want you'll end up doing what i did and wasting weeks trying to make it do what need, I was actually not able to get the DMA working as I wanted so I was left with trying uTasker which i did, and within a day i was up and running with all my DMA problems solved. I am not sure why the supplied SDK does not have full DMA support for UART but i just does not, their examples and implementation are not really practical.

Hope all works out for you, but I can tell you from my experience trying to get the standard SDK working ended up with a couple of weeks of pulling my hair out.

Good luck Bruce!

0 Kudos
Reply

2,836 Views
bgraham
Contributor IV

In fsl_uart.h UART_EnableRxDMA() the UART's C4.RDMAS is getting set to cause an interrupt when the DMA buffer is full.

I don't want this. Instead, I want the interrupt to occur when the UART peripheral detects an RX IDLE.

In the KL26 manual, I see the UART has a ILDMAS register.

See Table 40-34 below.

Would setting the UART's ILDMAS register end the DMA transfer on RX IDLE?

Where is the UART's ILDMAS register and how do I set it?

Thanks,

Bruce

KL26 Sub-Family Reference Manual, Rev. 3.2, October 2013

40.4.6 DMA Operation

Table 40-34. DMA configuration

====================================

Flag        Request enable bit    DMA select bit

RDRF     RIE = 1                      RDMAS = 1
IDLE       ILIE =1                       ILDMAS = 1

0 Kudos
Reply

2,836 Views
mjbcswitzerland
Specialist V

Hi

As you know, having DMA reception that needs to know how much data will be received beforehand is only of practical use in very limited situations.
The more general solution is to have free-running UART DMA to a circular buffer (which all Kinetis parts with DMA allow). You can either poll the buffer (eg. whenever there is nothing else to do, every 1ms or 10ms, etc.) depending on the protocol involved and the reaction time required to a complete message reception, or you can use the idle line interrupt to signal when there 'might' be a message waiting and it is worth taking a look.

When the UART is operating in DMA reception mode it will be triggering a DMA channel and not interrupting to inform of reception. This means that in the reference you refer to it is the DMA controller interrupting to inform that the pre-defined number of transfers has been made and not the UART. The UART can however be configured to interrupt on idle line and this interrupt then used to check the reception state. The idle line condition however has no interaction with the DMA operation and so code in the idle line interrupt needs to do whatever required.

Note that a further advantage of free-running DMA reception over the pre-defined reception length is that the fixed reception length method requires the DMA to be set up "again" for the next reception. If the data rate is high it may be that the code is not always fast enough to react to the initial end of DMA interrupt and set up before the start of the next message arrives and is lost (overrun). Free running DMA to a large circular buffer (no firmware intervention needed) ensures that no overrun can occur even at very high data rates.

The following videos explain free-running Rx UART DMA on a KL27 (which is compatible with KL26):
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

There is another video [without sound - that I don't remember any more for what reason it was made] showing a simulated KL27 using Rx and Tx DMA and also idle line interrupt for Modbus RTU protocol:
https://www.youtube.com/watch?v=OrqSn9x7N1E


Regards

Mark

Complete Kinetis solutions for professional needs, training and support: http://www.utasker.com/kinetis.html
Kinetis KL25, KL26, KL27, KL28, KL43, KL46, KL82
- http://http://www.utasker.com/kinetis/FRDM-KL25Z.html
- http://www.utasker.com/kinetis/TWR-KL25Z48M.html
- http://www.utasker.com/kinetis/FRDM-KL26Z.html
- http://www.utasker.com/kinetis/TEENSY_LC.html
- http://www.utasker.com/kinetis/FRDM-KL27Z.html
- http://www.utasker.com/kinetis/Capuccino-KL27.html
- http://www.utasker.com/kinetis/FRDM-KL28Z.html
- http://www.utasker.com/kinetis/FRDM-KL43Z.html
- http://www.utasker.com/kinetis/TWR-KL43Z48M.html
- http://www.utasker.com/kinetis/FRDM-KL46Z.html
- http://www.utasker.com/kinetis/TWR-KL46Z48M.html
- http://www.utasker.com/kinetis/FRDM-KL82Z.html


uTasker: supporting >1'000 registered Kinetis users get products faster and cheaper to market
Request Free emergency remote desk-top consulting at http://www.utasker.com/services.html

Open Source version at https://github.com/uTasker/uTasker-Kinetis

0 Kudos
Reply

2,836 Views
bgraham
Contributor IV

I made it very clear in my comments that I am using FreeRTOS and the Kinetic SDK.

I wasted an hour looking for at utasker.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!I WILL NOT convert my project to utasker!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!I WILL NOT convert my project to utasker!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!I WILL NOT convert my project to utasker!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

The utasker suggestion is worthless to me, so please no more utasker.

The free-running Rx UART DMA sounds great.

After going through the KL26 Sub-Family Reference Manual, Rev. 3.2, October 2013, and the Kinetis SDK v.2.0 API Reference Manual, I don't have clear idea how to setup free-running Rx UART DMA and safely get RX data from the DMA buffer.

I am guessing it requires setting DMA DCRx, etc.

And uses SDK APIs like DMA_SetModulo(), etc.

The MCUXpresso UART examples do not include setting up free-running Rx UART DMA.

I read notes from other customer that have the same problem: thread/451044

Can you point me to a Kinetis SDK project, with source that sets up free-running Rx UART DMA?

Thanks,

Bruce

 

2,836 Views
mjbcswitzerland
Specialist V

Bruce

The uTasker libraries work with FreeRTOS and SDK (they just don't use SDK HW sources for this particular task since these have poor portability [if you moved to a different Kinetis part they need different libraries whereas uTasker libraries can operate on any chip in a compatible manner]) - it is just C code that sets up everything you need so can essentially be used in any environment.

There are no SDK and no FreeRTOS libraries that allow free-running UART DMA and this restriction has been known for a long time and that is why the uTasker resources have been made available to help out in such situations. FreeRTOS based products with modems have used this technique on KL parts to overcome the restriction.

This is an example of a FreeRTOS task using the uTasker free-running Rx DMA resources (which simply echoes back for demonstration purposes):

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) {      // 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
    FOREVER_LOOP() {
        length = fnRead(uart_handle, &dataByte, 1);                      // read a byte from the DMA input buffer (returns immediately)
        if (length != 0) {                                               // if something is available
            fnDebugMsg("FreeRTOS Echo:");                                // echo it back
            fnWrite(uart_handle, &dataByte, 1);                          // send the byte back
            fnDebugMsg("\r\n");                                          // with termination
        }
        else {                                                           // nothing in the input buffer
            vTaskDelay(1);                                               // wait a single tick to allow other tasks to execute
        }
    }
}


‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This gives configurable interrupt/DMA Rx/Tx on any Kinetis UART in uTasker, FreeRTOS or dual-OS (uTasker/FreeRTOS) environments. The particular example checks the DMA input buffer once a Tick but its rate is obviously configurable.

See also your thread  thread/451044 - the project was FreeRTOS based and solved by the uTasker resources called from a FreeRTOS task. Following on, the same customer has developed a number of further products using this approach (including the same for HS USB-CDC on the K66 which uses the same approach and gives efficient and reliable USB on any KL or K part with USB) and confirms better performance and faster developments (thus lower development costs). I am sure that the customer will be happy to give more information if you have doubts.

That means that all is available for those needing it. For those needing it but only allowed to use SDK sources, guidelines (as in my last post) are also published as to what is needed in the spirit of helping but it is of course up to them to do the coding of the missing parts themselves.

Regards

Mark

Ref: https://community.nxp.com/thread/454831 

2,836 Views
bgraham
Contributor IV

You are not listening to me. This is not funny at all.

My MCU is tight on memory, so no utasker crap!

uTasker polls the UART, and polling eats battery, so no utasker crap!

I don't need the over head of utasker, so not utasker crap!

See attached file for details.

*Can you provide me with some info about how to setup DMA and UART

for free-running Rx UART DMA?*

This should be 10 lines of code.

Please don't piss me off with another utasker suggestion.

Have I made myself clear?

Bruce

On Fri, Jul 26, 2019 at 7:53 PM mjbcswitzerland <admin@community.nxp.com>

0 Kudos
Reply

2,836 Views
mjbcswitzerland
Specialist V

Hi

If you don't want to poll you just add an IDLE line wake-up event as discussed previously (and the topic of this thread).

There was a thread about 2 months ago where the low level details were discussed, with the code required (that someone managed to get working in a bare metal SDK environment). Unfortunately I can't find this thread anymore otherwise you could have copied that.

For low power operations VLPS allows uA operation but will only work up to about 19kBaud due to the time it takes to leave the mode when new UART data arrives (the first character needs to wake via an asynchronous interrupt and not be missed by the HW). For high(er) speed you need to use WAIT mode, which allows free-running DMA with Idle line event but it will only save about 40% over full run mode. To get lower current consumption you will need to see what is the lowest speed you can run the flash and bus clocks but still achieving the reaction times.

Regards

Mark

0 Kudos
Reply