UART Tx with DMA

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

UART Tx with DMA

5,870 Views
ulivinico
Contributor II

Hi, I'm developing an application requiring uart0 tx/rx with DMA.

Starting from example "low_power_dma_uart_demo" I was able to configure DMA (channel0) and UART0 and the receiving was ok (I don't need Low Power mode, so I've changed some setting with respect to the given example.

I'm not able, at the moment, to set the trasmission with DMA. Which are the steps to do? Do I have to use a new channel (channel 1 for example) and configure it for TX? I tried but without results.

Some hints? Examples? Thank you.

Labels (1)
Tags (4)
0 Kudos
6 Replies

1,407 Views
cfernandes
Contributor I

Hi ulivinico

I am trying to develop an application requiring uart0 tx/rx with DMA. I am new in code warrior and I am using KL26Z.

I have found low_power_dma_uart_demo example, however it is not opening. So I don't know where I should start.

I would be very grateful if you could give me some hints or examples.

Thank you in advance!

0 Kudos

1,407 Views
mjbcswitzerland
Specialist V

Hi

You can get KL26Z UART Tx DMA code from http://www.utasker.com/forum/index.php?topic=1721.0

Regards

Mark

µTasker Kinetis support

0 Kudos

1,407 Views
michaelguntli
Contributor IV

Mark, do I have to clear the DMA interrupt request of the specific channel once the DMA transfer is completed?

I get constant DMA interrupts when the CITER loop has completed..

According to the TRM (22.3.12 Clear Interrupt Request Register DMA_CINT), I would assume that i have to write 0x01 to clear the DMA Channel 1 interrupt?

0 Kudos

1,406 Views
mjbcswitzerland
Specialist V

Michael

If you enable an interrupt (DMA_DCR[EINT]) you will get one at the end of the transmitted block.

It is cleared with DMA_INT = (DMA_INT_INT0 << channel_number);

The end of transfer interrupt is useful because it signals that the block has been sent, can be used to control RS485 signal timing, low power activation (without moving to low power mode before a transfer has terminated) and to start a next waiting block.

Attached is the current uTasker UART code which handles interrupt/dma rx/tx operation on all UARTS/LPUART (K, KL, KE, KV, KW).

Regards

Mark

Kinetis: http://www.utasker.com/kinetis.html

Low power with UARTs: https://community.freescale.com/message/421247#421247

UARTs: http://www.utasker.com/docs/uTasker/uTaskerUART.PDF

For the complete "out-of-the-box" Kinetis experience and faster time to market

1,406 Views
michaelguntli
Contributor IV

Thanks Mark, I forgot to clear the DMA_INT within the interrupt..

0 Kudos

1,406 Views
mjbcswitzerland
Specialist V

Hi

Tx use is equivalent to Rx use - but in the other direction. It needs a second DMA channel.

When testing, monitor the DMA error register since it reports any configuration problems that stop it from working. In particular, make sure that each used DMA channel has its own unique priority since setting any two with the same (or left in uninitialised state) will lead to an immediate priority error.

There is setup code for UART DMA below - copied from the uTasker project whereby this code allows all UARTs to be operated in DMA mode if desired. Not shows is the initialisation of all DMA channel priorities which is best done before any DMA has been started in the system since changing priorities during operation could cause spurious problems; if you have a chip with multiple DMA groups also ensure that the groups priorities don't conflict.

Regards

Mark

KINETIS_DMA_TDC *ptrDMA_TCD = (KINETIS_DMA_TDC *)eDMA_DESCRIPTORS;

ptrDMA_TCD += UART_DMA_TX_CHANNEL[Channel];

ptrDMA_TCD->DMA_TCD_SOFF = 1;                                    // source increment one byte

ptrDMA_TCD->DMA_TCD_DOFF = 0;                                    // destination not incremented

ptrDMA_TCD->DMA_TCD_ATTR = (DMA_TCD_ATTR_DSIZE_8 | DMA_TCD_ATTR_SSIZE_8); // transfer sizes always single bytes

ptrDMA_TCD->DMA_TCD_DADDR = (unsigned long)&(uart_reg->UART_D);  // destination is the UART's data register

ptrDMA_TCD->DMA_TCD_NBYTES_ML = 1;                               // each request starts a single transfer

ptrDMA_TCD->DMA_TCD_CSR = (DMA_TCD_CSR_DREQ | DMA_TCD_CSR_INTMAJOR); // stop after the defined number of service requests and interrupt on completion

fnEnterInterrupt((irq_DMA0_ID + UART_DMA_TX_CHANNEL[Channel]), UART_DMA_TX_INT_PRIORITY[Channel], (void (*)(void))_uart_tx_dma_Interrupt[Channel]); // enter DMA interrupt handler

uart_reg->UART_C5 |= UART_C5_TDMAS;                              // use DMA rather than interrupts for transmission

POWER_UP(6, SIM_SCGC6_DMAMUX0);                                  // enable DMA multiplexer 0

*(unsigned char *)(DMAMUX0_BLOCK + UART_DMA_TX_CHANNEL[Channel]) = ((DMAMUX_CHCFG_SOURCE_UART0_TX + (2 * Channel)) | DMAMUX_CHCFG_ENBL); // connect UART tx to DMA channel

uart_reg->UART_C2 |= (UART_C2_TIE);                              // enable the tx dma request (DMA not yet enabled) rather than interrupt mode